表情包功能 UserEmoji

pull/701/head
miaowuawa 6 months ago
parent 6c923207bf
commit fcba697a55

@ -56,6 +56,15 @@ type Priv interface {
DownloadAttachmentPrecheck(*web.DownloadAttachmentPrecheckReq) (*web.DownloadAttachmentPrecheckResp, error)
UploadAttachment(*web.UploadAttachmentReq) (*web.UploadAttachmentResp, error)
// 表情包相关API
UploadEmoji(*web.UploadEmojiReq) (*web.UploadEmojiResp, error)
GetEmojiList(*web.GetEmojiListReq) (*web.GetEmojiListResp, error)
GetUserEmojiList(*web.GetUserEmojiListReq) (*web.GetUserEmojiListResp, error)
GetUserCollectedEmojiList(*web.GetUserCollectedEmojiListReq) (*web.GetUserCollectedEmojiListResp, error)
CollectEmoji(*web.CollectEmojiReq) (*web.CollectEmojiResp, error)
UncollectEmoji(*web.UncollectEmojiReq) (*web.UncollectEmojiResp, error)
DeleteEmoji(*web.DeleteEmojiReq) error
mustEmbedUnimplementedPrivServant()
}
@ -594,6 +603,112 @@ func RegisterPrivServant(e *gin.Engine, s Priv, m ...PrivChain) {
resp, err := s.UploadAttachment(req)
s.Render(c, resp, err)
})
// 表情包相关路由
router.Handle("POST", "emoji", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.UploadEmojiReq)
var bv _binding_ = req
if err := bv.Bind(c); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.UploadEmoji(req)
s.Render(c, resp, err)
})
router.Handle("GET", "emoji/list", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.GetEmojiListReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.GetEmojiList(req)
s.Render(c, resp, err)
})
router.Handle("GET", "emoji/user", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.GetUserEmojiListReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.GetUserEmojiList(req)
s.Render(c, resp, err)
})
router.Handle("GET", "emoji/collected", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.GetUserCollectedEmojiListReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.GetUserCollectedEmojiList(req)
s.Render(c, resp, err)
})
router.Handle("POST", "emoji/collect", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.CollectEmojiReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.CollectEmoji(req)
s.Render(c, resp, err)
})
router.Handle("POST", "emoji/uncollect", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.UncollectEmojiReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.UncollectEmoji(req)
s.Render(c, resp, err)
})
router.Handle("DELETE", "emoji", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.DeleteEmojiReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
s.Render(c, nil, s.DeleteEmoji(req))
})
}
// UnimplementedPrivServant can be embedded to have forward compatible implementations.
@ -751,6 +866,35 @@ func (UnimplementedPrivServant) UploadAttachment(req *web.UploadAttachmentReq) (
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
// 表情包相关方法
func (UnimplementedPrivServant) UploadEmoji(req *web.UploadEmojiReq) (*web.UploadEmojiResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) GetEmojiList(req *web.GetEmojiListReq) (*web.GetEmojiListResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) GetUserEmojiList(req *web.GetUserEmojiListReq) (*web.GetUserEmojiListResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) GetUserCollectedEmojiList(req *web.GetUserCollectedEmojiListReq) (*web.GetUserCollectedEmojiListResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) CollectEmoji(req *web.CollectEmojiReq) (*web.CollectEmojiResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) UncollectEmoji(req *web.UncollectEmojiReq) (*web.UncollectEmojiResp, error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DeleteEmoji(req *web.DeleteEmojiReq) error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) mustEmbedUnimplementedPrivServant() {}
// UnimplementedPrivChain can be embedded to have forward compatible implementations.

@ -27,7 +27,7 @@ require (
github.com/grafana/pyroscope-go v1.2.2
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.25.4+incompatible
github.com/json-iterator/go v1.1.12
github.com/lionsoul2014/ip2region v1.7.0
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20260226062615-1a8d01d9679e
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731
github.com/meilisearch/meilisearch-go v0.27.2
github.com/minio/minio-go/v7 v7.0.84
@ -120,7 +120,6 @@ require (
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20260226062615-1a8d01d9679e // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -129,7 +128,6 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mohong122/ip2region v0.0.0-20190505055455-f4ef24f6b03d // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect

@ -198,8 +198,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lionsoul2014/ip2region v1.7.0 h1:LUNcu4rsodhet/6wd3p5QMmtQUxPBUm+N9sI2Tw7BFs=
github.com/lionsoul2014/ip2region v1.7.0/go.mod h1:+ZBN7PBoh5gG6/y0ZQ85vJDBe21WnfbRrQQwTfliJJI=
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20260226062615-1a8d01d9679e h1:1+rVed4OnYgQCg934wWHms6J7aEbyQ7TaR/fSYhJmLA=
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20260226062615-1a8d01d9679e/go.mod h1:+mNMTBuDMdEGhWzoQgc6kBdqeaQpWh5ba8zqmp2MxCU=
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5ATTo469PQPkqzdoU7be46ryiCDO3boc=
@ -232,8 +230,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohong122/ip2region v0.0.0-20190505055455-f4ef24f6b03d h1:Fgk2vj/4uaCke01N4Z91X2gFv3bizQC/5Z0jpXVLWWA=
github.com/mohong122/ip2region v0.0.0-20190505055455-f4ef24f6b03d/go.mod h1:nWEvmMDv872jkCVATPoiQKQvB6NYSzra9gCN5OgS/Mg=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=

@ -44,6 +44,9 @@ type DataService interface {
// 实用性服务
//StickerService
// 表情包服务
EmojiService
}
// WebDataServantA Web数据服务集成(版本A)

@ -0,0 +1,39 @@
// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package core
import (
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
)
// EmojiService 表情包服务接口
type EmojiService interface {
// 上传表情包
UploadEmoji(userID int64, name, url string, width, height int, size int64, emojiType string) (*dbr.Emoji, error)
// 获取表情包列表
GetEmojiList(offset, limit int) ([]*dbr.Emoji, error)
// 获取用户上传的表情包列表
GetUserEmojiList(userID int64, offset, limit int) ([]*dbr.Emoji, error)
// 获取用户收藏的表情包列表
GetUserCollectedEmojiList(userID int64, offset, limit int) ([]*dbr.Emoji, error)
// 收藏表情包
CollectEmoji(userID, emojiID int64) error
// 取消收藏表情包
UncollectEmoji(userID, emojiID int64) error
// 检查表情包是否被用户收藏
IsEmojiCollected(userID, emojiID int64) (bool, error)
// 获取表情包详情
GetEmojiByID(emojiID int64) (*dbr.Emoji, error)
// 删除表情包
DeleteEmoji(userID, emojiID int64) error
}

@ -0,0 +1,170 @@
// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package dbr
import (
"gorm.io/gorm"
)
// Emoji 表情包模型
type Emoji struct {
*Model
UserID int64 `json:"user_id"`
Name string `json:"name"`
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
Size int64 `json:"size"`
Type string `json:"type"`
CollectionCount int64 `json:"collection_count"`
}
// UserEmoji 用户表情包收藏模型
type UserEmoji struct {
*Model
UserID int64 `json:"user_id"`
EmojiID int64 `json:"emoji_id"`
}
// EmojiFormated 格式化的表情包信息
type EmojiFormated struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
Name string `json:"name"`
URL string `json:"url"`
Width int `json:"width"`
Height int `json:"height"`
Size int64 `json:"size"`
Type string `json:"type"`
CollectionCount int64 `json:"collection_count"`
IsCollected bool `json:"is_collected"`
CreatedOn int64 `json:"created_on"`
}
// Format 格式化表情包信息
func (e *Emoji) Format() *EmojiFormated {
if e.Model != nil {
return &EmojiFormated{
ID: e.ID,
UserID: e.UserID,
Name: e.Name,
URL: e.URL,
Width: e.Width,
Height: e.Height,
Size: e.Size,
Type: e.Type,
CollectionCount: e.CollectionCount,
IsCollected: false,
CreatedOn: e.CreatedOn,
}
}
return nil
}
// Get 获取单个表情包
func (e *Emoji) Get(db *gorm.DB) (*Emoji, error) {
var emoji Emoji
if e.Model != nil && e.Model.ID > 0 {
db = db.Where("id = ? AND is_del = ?", e.Model.ID, 0)
} else {
return nil, gorm.ErrRecordNotFound
}
err := db.First(&emoji).Error
if err != nil {
return nil, err
}
return &emoji, nil
}
// List 获取表情包列表
func (e *Emoji) List(db *gorm.DB, conditions *ConditionsT, offset, limit int) ([]*Emoji, error) {
var emojis []*Emoji
var err error
if offset >= 0 && limit > 0 {
db = db.Offset(offset).Limit(limit)
}
for k, v := range *conditions {
if k == "ORDER" {
db = db.Order(v)
} else {
db = db.Where(k, v)
}
}
if err = db.Where("is_del = ?", 0).Find(&emojis).Error; err != nil {
return nil, err
}
return emojis, nil
}
// Create 创建表情包
func (e *Emoji) Create(db *gorm.DB) (*Emoji, error) {
err := db.Create(&e).Error
return e, err
}
// Update 更新表情包
func (e *Emoji) Update(db *gorm.DB) error {
return db.Model(&Emoji{}).Where("id = ? AND is_del = ?", e.Model.ID, 0).Save(e).Error
}
// Delete 删除表情包
func (e *Emoji) Delete(db *gorm.DB) error {
return db.Delete(&e).Error
}
// IncrementCollectionCount 增加收藏数
func (e *Emoji) IncrementCollectionCount(db *gorm.DB) error {
return db.Model(&Emoji{}).Where("id = ? AND is_del = ?", e.Model.ID, 0).Update("collection_count", gorm.Expr("collection_count + ?", 1)).Error
}
// DecrementCollectionCount 减少收藏数
func (e *Emoji) DecrementCollectionCount(db *gorm.DB) error {
return db.Model(&Emoji{}).Where("id = ? AND is_del = ? AND collection_count > 0", e.Model.ID, 0).Update("collection_count", gorm.Expr("collection_count - ?", 1)).Error
}
// GetUserEmoji 获取用户的表情包收藏
func (ue *UserEmoji) GetUserEmoji(db *gorm.DB) (*UserEmoji, error) {
var userEmoji UserEmoji
err := db.Where("user_id = ? AND emoji_id = ? AND is_del = ?", ue.UserID, ue.EmojiID, 0).First(&userEmoji).Error
if err != nil {
return nil, err
}
return &userEmoji, nil
}
// ListUserEmojis 获取用户的表情包收藏列表
func (ue *UserEmoji) ListUserEmojis(db *gorm.DB, userID int64, offset, limit int) ([]*Emoji, error) {
var emojis []*Emoji
query := db.Table("p_emoji").Select("p_emoji.*").Joins("JOIN p_user_emoji ON p_emoji.id = p_user_emoji.emoji_id").Where("p_user_emoji.user_id = ? AND p_user_emoji.is_del = ? AND p_emoji.is_del = ?", userID, 0, 0)
if offset >= 0 && limit > 0 {
query = query.Offset(offset).Limit(limit)
}
err := query.Order("p_user_emoji.created_on DESC").Find(&emojis).Error
if err != nil {
return nil, err
}
return emojis, nil
}
// Create 创建用户表情包收藏
func (ue *UserEmoji) Create(db *gorm.DB) (*UserEmoji, error) {
err := db.Create(&ue).Error
return ue, err
}
// Delete 删除用户表情包收藏
func (ue *UserEmoji) Delete(db *gorm.DB) error {
return db.Where("user_id = ? AND emoji_id = ? AND is_del = ?", ue.UserID, ue.EmojiID, 0).Delete(&UserEmoji{}).Error
}

@ -0,0 +1,193 @@
// Copyright 2022 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package jinzhu
import (
"errors"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/dao/jinzhu/dbr"
"gorm.io/gorm"
)
var (
_ core.EmojiService = (*emojiSrv)(nil)
)
const (
_emoji_ = "p_emoji"
_user_emoji_ = "p_user_emoji"
)
type emojiSrv struct {
db *gorm.DB
}
func newEmojiService(db *gorm.DB) core.EmojiService {
return &emojiSrv{
db: db,
}
}
// UploadEmoji 上传表情包
func (s *emojiSrv) UploadEmoji(userID int64, name, url string, width, height int, size int64, emojiType string) (*dbr.Emoji, error) {
emoji := &dbr.Emoji{
Model: &dbr.Model{},
UserID: userID,
Name: name,
URL: url,
Width: width,
Height: height,
Size: size,
Type: emojiType,
CollectionCount: 0,
}
return emoji.Create(s.db)
}
// GetEmojiList 获取表情包列表
func (s *emojiSrv) GetEmojiList(offset, limit int) ([]*dbr.Emoji, error) {
emoji := &dbr.Emoji{}
conditions := &dbr.ConditionsT{
"ORDER": "collection_count DESC, created_on DESC",
}
return emoji.List(s.db, conditions, offset, limit)
}
// GetUserEmojiList 获取用户上传的表情包列表
func (s *emojiSrv) GetUserEmojiList(userID int64, offset, limit int) ([]*dbr.Emoji, error) {
emoji := &dbr.Emoji{}
conditions := &dbr.ConditionsT{
"user_id = ?": userID,
"ORDER": "created_on DESC",
}
return emoji.List(s.db, conditions, offset, limit)
}
// GetUserCollectedEmojiList 获取用户收藏的表情包列表
func (s *emojiSrv) GetUserCollectedEmojiList(userID int64, offset, limit int) ([]*dbr.Emoji, error) {
userEmoji := &dbr.UserEmoji{}
return userEmoji.ListUserEmojis(s.db, userID, offset, limit)
}
// CollectEmoji 收藏表情包
func (s *emojiSrv) CollectEmoji(userID, emojiID int64) error {
// 检查表情包是否存在
emoji := &dbr.Emoji{
Model: &dbr.Model{
ID: emojiID,
},
}
_, err := emoji.Get(s.db)
if err != nil {
return err
}
// 检查是否已经收藏
userEmoji := &dbr.UserEmoji{
UserID: userID,
EmojiID: emojiID,
}
_, err = userEmoji.GetUserEmoji(s.db)
if err == nil {
return errors.New("emoji already collected")
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
// 创建收藏记录
userEmoji = &dbr.UserEmoji{
Model: &dbr.Model{},
UserID: userID,
EmojiID: emojiID,
}
_, err = userEmoji.Create(s.db)
if err != nil {
return err
}
// 增加表情包收藏数
return emoji.IncrementCollectionCount(s.db)
}
// UncollectEmoji 取消收藏表情包
func (s *emojiSrv) UncollectEmoji(userID, emojiID int64) error {
// 检查是否已经收藏
userEmoji := &dbr.UserEmoji{
UserID: userID,
EmojiID: emojiID,
}
_, err := userEmoji.GetUserEmoji(s.db)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("emoji not collected")
}
return err
}
// 删除收藏记录
err = userEmoji.Delete(s.db)
if err != nil {
return err
}
// 减少表情包收藏数
emoji := &dbr.Emoji{
Model: &dbr.Model{
ID: emojiID,
},
}
return emoji.DecrementCollectionCount(s.db)
}
// IsEmojiCollected 检查表情包是否被用户收藏
func (s *emojiSrv) IsEmojiCollected(userID, emojiID int64) (bool, error) {
userEmoji := &dbr.UserEmoji{
UserID: userID,
EmojiID: emojiID,
}
_, err := userEmoji.GetUserEmoji(s.db)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
return false, err
}
return true, nil
}
// GetEmojiByID 获取表情包详情
func (s *emojiSrv) GetEmojiByID(emojiID int64) (*dbr.Emoji, error) {
emoji := &dbr.Emoji{
Model: &dbr.Model{
ID: emojiID,
},
}
return emoji.Get(s.db)
}
// DeleteEmoji 删除表情包
func (s *emojiSrv) DeleteEmoji(userID, emojiID int64) error {
// 检查表情包是否存在且属于该用户
emoji := &dbr.Emoji{
Model: &dbr.Model{
ID: emojiID,
},
}
emoji, err := emoji.Get(s.db)
if err != nil {
return err
}
if emoji.UserID != userID {
return errors.New("permission denied")
}
// 删除表情包
return emoji.Delete(s.db)
}

@ -47,6 +47,7 @@ type dataSrv struct {
core.UserRelationService
core.SecurityService
core.AttachmentCheckService
core.EmojiService
}
type webDataSrvA struct {
@ -83,6 +84,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
UserRelationService: newUserRelationService(db),
SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(),
EmojiService: newEmojiService(db),
}
return cache.NewCacheDataService(ds), ds
}

@ -182,3 +182,86 @@ func (r *TweetStarStatusReq) Bind(c *gin.Context) error {
type StreamMessagesReq struct {
SimpleInfo `json:"-" binding:"-"`
}
// 表情包相关请求和响应
// UploadEmojiReq 上传表情包请求
type UploadEmojiReq struct {
BaseInfo `json:"-" binding:"-"`
Name string `form:"name" binding:"required"`
File interface{} `form:"file" binding:"required"`
FileExt string `form:"file_ext" binding:"required"`
FileSize int64 `form:"file_size" binding:"required"`
ContentType string `form:"content_type" binding:"required"`
Width int `form:"width" binding:"required"`
Height int `form:"height" binding:"required"`
}
// UploadEmojiResp 上传表情包响应
type UploadEmojiResp struct {
ID int64 `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
}
// GetEmojiListReq 获取表情包列表请求
type GetEmojiListReq struct {
SimpleInfo `json:"-" binding:"-"`
BasePageInfo
}
// GetEmojiListResp 获取表情包列表响应
type GetEmojiListResp struct {
base.PageResp
}
// GetUserEmojiListReq 获取用户上传的表情包列表请求
type GetUserEmojiListReq struct {
SimpleInfo `json:"-" binding:"-"`
BasePageInfo
UserID int64 `form:"user_id" binding:"required"`
}
// GetUserEmojiListResp 获取用户上传的表情包列表响应
type GetUserEmojiListResp struct {
base.PageResp
}
// GetUserCollectedEmojiListReq 获取用户收藏的表情包列表请求
type GetUserCollectedEmojiListReq struct {
SimpleInfo `json:"-" binding:"-"`
BasePageInfo
}
// GetUserCollectedEmojiListResp 获取用户收藏的表情包列表响应
type GetUserCollectedEmojiListResp struct {
base.PageResp
}
// CollectEmojiReq 收藏表情包请求
type CollectEmojiReq struct {
SimpleInfo `json:"-" binding:"-"`
EmojiID int64 `json:"emoji_id" binding:"required"`
}
// CollectEmojiResp 收藏表情包响应
type CollectEmojiResp struct {
Status bool `json:"status"`
}
// UncollectEmojiReq 取消收藏表情包请求
type UncollectEmojiReq struct {
SimpleInfo `json:"-" binding:"-"`
EmojiID int64 `json:"emoji_id" binding:"required"`
}
// UncollectEmojiResp 取消收藏表情包响应
type UncollectEmojiResp struct {
Status bool `json:"status"`
}
// DeleteEmojiReq 删除表情包请求
type DeleteEmojiReq struct {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`
}

@ -115,6 +115,11 @@ var (
ErrFileInvalidExt = xerror.NewError(10201, "文件类型不合法")
ErrFileInvalidSize = xerror.NewError(10202, "文件大小超限")
// 表情包相关错误
ErrCollectEmojiFailed = xerror.NewError(12001, "收藏表情包失败")
ErrUncollectEmojiFailed = xerror.NewError(12002, "取消收藏表情包失败")
ErrDeleteEmojiFailed = xerror.NewError(12003, "删除表情包失败")
// 长文章相关错误
ErrCreateArticle = xerror.NewError(11001, "长文章创建失败")
ErrUpdateArticle = xerror.NewError(11002, "长文章更新失败")

@ -898,6 +898,181 @@ func (s *privSrv) buyPostAttachment(post *ms.Post, user *ms.User) error {
return nil
}
// UploadEmoji 上传表情包
func (s *privSrv) UploadEmoji(req *web.UploadEmojiReq) (*web.UploadEmojiResp, error) {
defer req.File.(interface{ Close() error }).Close()
// 生成随机路径
randomPath := uuid.Must(uuid.NewV4()).String()
ossSavePath := "emoji/" + generatePath(randomPath[:8]) + "/" + randomPath[9:] + req.FileExt
data := io.NopCloser(req.File.(io.Reader))
objectUrl, err := s.oss.PutObject(ossSavePath, data, req.FileSize, req.ContentType, false)
if err != nil {
logrus.Errorf("oss.putObject err: %s", err)
return nil, web.ErrFileUploadFailed
}
// 上传到数据库
emoji, err := s.Ds.EmojiService.UploadEmoji(req.User.ID, req.Name, objectUrl, req.Width, req.Height, req.FileSize, req.ContentType)
if err != nil {
logrus.Errorf("Ds.EmojiService.UploadEmoji err: %s", err)
return nil, web.ErrFileUploadFailed
}
return &web.UploadEmojiResp{
ID: emoji.ID,
Name: emoji.Name,
URL: emoji.URL,
}, nil
}
// GetEmojiList 获取表情包列表
func (s *privSrv) GetEmojiList(req *web.GetEmojiListReq) (*web.GetEmojiListResp, error) {
emojis, err := s.Ds.EmojiService.GetEmojiList(req.Offset, req.Limit)
if err != nil {
logrus.Errorf("Ds.EmojiService.GetEmojiList err: %s", err)
return nil, xerror.ServerError
}
// 检查是否被当前用户收藏
var emojiList []map[string]interface{}
for _, emoji := range emojis {
isCollected, _ := s.Ds.EmojiService.IsEmojiCollected(req.Uid, emoji.ID)
emojiFormated := emoji.Format()
emojiFormated.IsCollected = isCollected
emojiList = append(emojiList, map[string]interface{}{
"id": emojiFormated.ID,
"user_id": emojiFormated.UserID,
"name": emojiFormated.Name,
"url": emojiFormated.URL,
"width": emojiFormated.Width,
"height": emojiFormated.Height,
"size": emojiFormated.Size,
"type": emojiFormated.Type,
"collection_count": emojiFormated.CollectionCount,
"is_collected": emojiFormated.IsCollected,
"created_on": emojiFormated.CreatedOn,
})
}
return &web.GetEmojiListResp{
PageResp: base.PageResp{
Items: emojiList,
Total: int64(len(emojiList)),
},
}, nil
}
// GetUserEmojiList 获取用户上传的表情包列表
func (s *privSrv) GetUserEmojiList(req *web.GetUserEmojiListReq) (*web.GetUserEmojiListResp, error) {
emojis, err := s.Ds.EmojiService.GetUserEmojiList(req.UserID, req.Offset, req.Limit)
if err != nil {
logrus.Errorf("Ds.EmojiService.GetUserEmojiList err: %s", err)
return nil, xerror.ServerError
}
// 检查是否被当前用户收藏
var emojiList []map[string]interface{}
for _, emoji := range emojis {
isCollected, _ := s.Ds.EmojiService.IsEmojiCollected(req.Uid, emoji.ID)
emojiFormated := emoji.Format()
emojiFormated.IsCollected = isCollected
emojiList = append(emojiList, map[string]interface{}{
"id": emojiFormated.ID,
"user_id": emojiFormated.UserID,
"name": emojiFormated.Name,
"url": emojiFormated.URL,
"width": emojiFormated.Width,
"height": emojiFormated.Height,
"size": emojiFormated.Size,
"type": emojiFormated.Type,
"collection_count": emojiFormated.CollectionCount,
"is_collected": emojiFormated.IsCollected,
"created_on": emojiFormated.CreatedOn,
})
}
return &web.GetUserEmojiListResp{
PageResp: base.PageResp{
Items: emojiList,
Total: int64(len(emojiList)),
},
}, nil
}
// GetUserCollectedEmojiList 获取用户收藏的表情包列表
func (s *privSrv) GetUserCollectedEmojiList(req *web.GetUserCollectedEmojiListReq) (*web.GetUserCollectedEmojiListResp, error) {
emojis, err := s.Ds.EmojiService.GetUserCollectedEmojiList(req.Uid, req.Offset, req.Limit)
if err != nil {
logrus.Errorf("Ds.EmojiService.GetUserCollectedEmojiList err: %s", err)
return nil, xerror.ServerError
}
// 标记为已收藏
var emojiList []map[string]interface{}
for _, emoji := range emojis {
emojiFormated := emoji.Format()
emojiFormated.IsCollected = true
emojiList = append(emojiList, map[string]interface{}{
"id": emojiFormated.ID,
"user_id": emojiFormated.UserID,
"name": emojiFormated.Name,
"url": emojiFormated.URL,
"width": emojiFormated.Width,
"height": emojiFormated.Height,
"size": emojiFormated.Size,
"type": emojiFormated.Type,
"collection_count": emojiFormated.CollectionCount,
"is_collected": emojiFormated.IsCollected,
"created_on": emojiFormated.CreatedOn,
})
}
return &web.GetUserCollectedEmojiListResp{
PageResp: base.PageResp{
Items: emojiList,
Total: int64(len(emojiList)),
},
}, nil
}
// CollectEmoji 收藏表情包
func (s *privSrv) CollectEmoji(req *web.CollectEmojiReq) (*web.CollectEmojiResp, error) {
err := s.Ds.EmojiService.CollectEmoji(req.Uid, req.EmojiID)
if err != nil {
logrus.Errorf("Ds.EmojiService.CollectEmoji err: %s", err)
return nil, web.ErrCollectEmojiFailed
}
return &web.CollectEmojiResp{
Status: true,
}, nil
}
// UncollectEmoji 取消收藏表情包
func (s *privSrv) UncollectEmoji(req *web.UncollectEmojiReq) (*web.UncollectEmojiResp, error) {
err := s.Ds.EmojiService.UncollectEmoji(req.Uid, req.EmojiID)
if err != nil {
logrus.Errorf("Ds.EmojiService.UncollectEmoji err: %s", err)
return nil, web.ErrUncollectEmojiFailed
}
return &web.UncollectEmojiResp{
Status: true,
}, nil
}
// DeleteEmoji 删除表情包
func (s *privSrv) DeleteEmoji(req *web.DeleteEmojiReq) error {
err := s.Ds.EmojiService.DeleteEmoji(req.User.ID, req.ID)
if err != nil {
logrus.Errorf("Ds.EmojiService.DeleteEmoji err: %s", err)
return web.ErrDeleteEmojiFailed
}
return nil
}
func newPrivSrv(s *base.DaoServant, oss core.ObjectStorageService) api.Priv {
return &privSrv{
DaoServant: s,

@ -121,4 +121,26 @@ type Priv struct {
// AdminDeleteArticle 管理员删除长文章
AdminDeleteArticle func(Delete, web.AdminDeleteArticleReq) `mir:"admin/articles"`
// 表情包相关API
// UploadEmoji 上传表情包
UploadEmoji func(Post, web.UploadEmojiReq) web.UploadEmojiResp `mir:"emoji"`
// GetEmojiList 获取表情包列表
GetEmojiList func(Get, web.GetEmojiListReq) web.GetEmojiListResp `mir:"emoji/list"`
// GetUserEmojiList 获取用户上传的表情包列表
GetUserEmojiList func(Get, web.GetUserEmojiListReq) web.GetUserEmojiListResp `mir:"emoji/user"`
// GetUserCollectedEmojiList 获取用户收藏的表情包列表
GetUserCollectedEmojiList func(Get, web.GetUserCollectedEmojiListReq) web.GetUserCollectedEmojiListResp `mir:"emoji/collected"`
// CollectEmoji 收藏表情包
CollectEmoji func(Post, web.CollectEmojiReq) web.CollectEmojiResp `mir:"emoji/collect"`
// UncollectEmoji 取消收藏表情包
UncollectEmoji func(Post, web.UncollectEmojiReq) web.UncollectEmojiResp `mir:"emoji/uncollect"`
// DeleteEmoji 删除表情包
DeleteEmoji func(Delete, web.DeleteEmojiReq) `mir:"emoji"`
}

@ -0,0 +1,7 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `p_user_emoji`;
DROP TABLE IF EXISTS `p_emoji`;
SET FOREIGN_KEY_CHECKS = 1;

@ -0,0 +1,36 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
CREATE TABLE `p_emoji` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '表情包ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '上传用户ID',
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '表情包名称',
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '表情包URL',
`width` int unsigned NOT NULL DEFAULT '0' COMMENT '宽度',
`height` int unsigned NOT NULL DEFAULT '0' COMMENT '高度',
`size` bigint unsigned NOT NULL DEFAULT '0' COMMENT '文件大小',
`type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '文件类型',
`collection_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '收藏数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user` (`user_id`) USING BTREE,
KEY `idx_collection` (`collection_count`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='表情包';
CREATE TABLE `p_user_emoji` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '记录ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`emoji_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '表情包ID',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '收藏时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_user_emoji` (`user_id`,`emoji_id`) USING BTREE,
KEY `idx_emoji` (`emoji_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表情包收藏';
SET FOREIGN_KEY_CHECKS = 1;

@ -0,0 +1,2 @@
DROP TABLE IF EXISTS p_user_emoji;
DROP TABLE IF EXISTS p_emoji;

@ -0,0 +1,31 @@
CREATE TABLE IF NOT EXISTS p_emoji (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL DEFAULT 0,
name VARCHAR(64) NOT NULL DEFAULT '',
url VARCHAR(255) NOT NULL DEFAULT '',
width INTEGER NOT NULL DEFAULT 0,
height INTEGER NOT NULL DEFAULT 0,
size BIGINT NOT NULL DEFAULT 0,
type VARCHAR(32) NOT NULL DEFAULT '',
collection_count BIGINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_emoji_user ON p_emoji(user_id);
CREATE INDEX IF NOT EXISTS idx_emoji_collection ON p_emoji(collection_count);
CREATE TABLE IF NOT EXISTS p_user_emoji (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL DEFAULT 0,
emoji_id BIGINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_user_emoji ON p_user_emoji(user_id, emoji_id);
CREATE INDEX IF NOT EXISTS idx_user_emoji_emoji ON p_user_emoji(emoji_id);

@ -0,0 +1,2 @@
DROP TABLE IF EXISTS p_user_emoji;
DROP TABLE IF EXISTS p_emoji;

@ -0,0 +1,31 @@
CREATE TABLE IF NOT EXISTS p_emoji (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL DEFAULT 0,
name TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL DEFAULT '',
width INTEGER NOT NULL DEFAULT 0,
height INTEGER NOT NULL DEFAULT 0,
size INTEGER NOT NULL DEFAULT 0,
type TEXT NOT NULL DEFAULT '',
collection_count INTEGER NOT NULL DEFAULT 0,
created_on INTEGER NOT NULL DEFAULT 0,
modified_on INTEGER NOT NULL DEFAULT 0,
deleted_on INTEGER NOT NULL DEFAULT 0,
is_del INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_emoji_user ON p_emoji(user_id);
CREATE INDEX IF NOT EXISTS idx_emoji_collection ON p_emoji(collection_count);
CREATE TABLE IF NOT EXISTS p_user_emoji (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL DEFAULT 0,
emoji_id INTEGER NOT NULL DEFAULT 0,
created_on INTEGER NOT NULL DEFAULT 0,
modified_on INTEGER NOT NULL DEFAULT 0,
deleted_on INTEGER NOT NULL DEFAULT 0,
is_del INTEGER NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_user_emoji ON p_user_emoji(user_id, emoji_id);
CREATE INDEX IF NOT EXISTS idx_user_emoji_emoji ON p_user_emoji(emoji_id);
Loading…
Cancel
Save