diff --git a/app/player/api/etc/player-api.yaml b/app/player/api/etc/player-api.yaml index f1c6c72..1c5f270 100644 --- a/app/player/api/etc/player-api.yaml +++ b/app/player/api/etc/player-api.yaml @@ -16,3 +16,6 @@ Prometheus: PlayerRpcConf: Endpoints: - player-rpc:8080 +UsercenterRpcConf: + Endpoints: + - user-rpc:8080 diff --git a/app/player/api/internal/config/config.go b/app/player/api/internal/config/config.go index 57cf769..7e51976 100644 --- a/app/player/api/internal/config/config.go +++ b/app/player/api/internal/config/config.go @@ -10,5 +10,6 @@ import ( type Config struct { rest.RestConf - PlayerRpcConf zrpc.RpcClientConf + PlayerRpcConf zrpc.RpcClientConf + UsercenterRpcConf zrpc.RpcClientConf } diff --git a/app/player/api/internal/handler/player/initPlayerHandler.go b/app/player/api/internal/handler/player/initPlayerHandler.go new file mode 100644 index 0000000..5dd4fa8 --- /dev/null +++ b/app/player/api/internal/handler/player/initPlayerHandler.go @@ -0,0 +1,38 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl 1.9.2 + +package player + +import ( + "errors" + "juwan-backend/common/utils/responses" + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "juwan-backend/app/player/api/internal/logic/player" + "juwan-backend/app/player/api/internal/svc" + "juwan-backend/app/player/api/internal/types" +) + +// 初始化当前用户的打手资料 +func InitPlayerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.EmptyResp + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := player.NewInitPlayerLogic(r.Context(), svcCtx) + resp, err := l.InitPlayer(&req) + if err != nil { + if errors.Is(err, player.ErrPlayerNotEligible) { + httpx.ErrorCtx(r.Context(), w, responses.NewErrorResp(http.StatusForbidden, err)) + return + } + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/app/player/api/internal/handler/routes.go b/app/player/api/internal/handler/routes.go index 726c0d5..7ad37b2 100644 --- a/app/player/api/internal/handler/routes.go +++ b/app/player/api/internal/handler/routes.go @@ -51,6 +51,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { server.AddRoutes( []rest.Route{ + { + // 初始化当前用户的打手资料 + Method: http.MethodPost, + Path: "/players/me", + Handler: player.InitPlayerHandler(serverCtx), + }, { // 更新接单状态 Method: http.MethodPut, diff --git a/app/player/api/internal/logic/player/initPlayerLogic.go b/app/player/api/internal/logic/player/initPlayerLogic.go new file mode 100644 index 0000000..b381b75 --- /dev/null +++ b/app/player/api/internal/logic/player/initPlayerLogic.go @@ -0,0 +1,128 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl 1.9.2 + +package player + +import ( + "context" + "encoding/json" + "errors" + "slices" + "strconv" + "time" + + "juwan-backend/app/player/api/internal/svc" + "juwan-backend/app/player/api/internal/types" + "juwan-backend/app/player/rpc/playerservice" + "juwan-backend/app/users/rpc/usercenter" + "juwan-backend/common/utils/contextj" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/status" +) + +var ErrPlayerNotEligible = errors.New("player role not verified") + +type InitPlayerLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// 初始化当前用户的打手资料 +func NewInitPlayerLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InitPlayerLogic { + return &InitPlayerLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *InitPlayerLogic) InitPlayer(req *types.EmptyResp) (resp *types.PlayerProfile, err error) { + userID, err := contextj.UserIDFrom(l.ctx) + if err != nil { + return nil, err + } + + userResp, err := l.svcCtx.UserRpc.GetUsersById(l.ctx, &usercenter.GetUsersByIdReq{Id: userID}) + if err != nil { + return nil, err + } + if userResp.GetUsers() == nil { + return nil, ErrPlayerNotEligible + } + + if !slices.Contains(userResp.GetUsers().VerifiedRoles, "player") { + return nil, ErrPlayerNotEligible + } + + verificationStatus := map[string]string{} + if userResp.GetUsers().VerificationStatus != "" { + _ = json.Unmarshal([]byte(userResp.GetUsers().VerificationStatus), &verificationStatus) + } + + playerReq := &playerservice.SearchPlayersReq{UserId: &userID} + playerResp, err := l.svcCtx.PlayerRpc.GetPlayerByUserId(l.ctx, playerReq) + if err != nil { + st, _ := status.FromError(err) + if st.Code().String() != "NotFound" { + logx.Errorf("InitPlayerLogic.GetPlayerByUserId err: %v", err) + return nil, errors.New("get player failed") + } + + _, err = l.svcCtx.PlayerRpc.AddPlayers(l.ctx, &playerservice.AddPlayersReq{ + UserId: userID, + Status: "offline", + Rating: 5, + Gender: 1, + }) + if err != nil { + logx.Errorf("InitPlayerLogic.AddPlayers err: %v", err) + return nil, errors.New("create player failed") + } + + playerResp, err = l.svcCtx.PlayerRpc.GetPlayerByUserId(l.ctx, playerReq) + if err != nil { + logx.Errorf("InitPlayerLogic.GetPlayerByUserId after create err: %v", err) + return nil, errors.New("get player failed") + } + } + + player := playerResp.GetPlayers() + if player == nil { + return nil, errors.New("player not found") + } + + games := make([]string, 0, len(player.Games)) + for _, gameID := range player.Games { + games = append(games, strconv.FormatInt(gameID, 10)) + } + + resp = &types.PlayerProfile{ + Id: player.Id, + User: types.UserProfile{ + Id: strconv.FormatInt(userResp.GetUsers().Id, 10), + Username: userResp.GetUsers().Username, + Nickname: userResp.GetUsers().Nickname, + Avatar: userResp.GetUsers().Avatar, + Role: userResp.GetUsers().CurrentRole, + VerifiedRoles: append([]string{}, userResp.GetUsers().VerifiedRoles...), + Phone: userResp.GetUsers().Phone, + Bio: userResp.GetUsers().Bio, + CreatedAt: time.Unix(userResp.GetUsers().CreatedAt, 0).Format(time.DateTime), + }, + Rating: player.Rating, + TotalOrders: player.TotalOrders, + Status: player.Status, + Games: games, + Services: []types.PlayerService{}, + Gender: player.Gender, + Tags: append([]string{}, player.Tags...), + } + resp.User.VerificationStatus = verificationStatus + if player.ShopId != 0 { + resp.ShopId = strconv.FormatInt(player.ShopId, 10) + } + + return resp, nil +} diff --git a/app/player/api/internal/svc/serviceContext.go b/app/player/api/internal/svc/serviceContext.go index 1f1ce92..5f4509e 100644 --- a/app/player/api/internal/svc/serviceContext.go +++ b/app/player/api/internal/svc/serviceContext.go @@ -6,6 +6,7 @@ package svc import ( "juwan-backend/app/player/api/internal/config" "juwan-backend/app/player/rpc/playerservice" + "juwan-backend/app/users/rpc/usercenter" "github.com/zeromicro/go-zero/zrpc" ) @@ -13,11 +14,13 @@ import ( type ServiceContext struct { Config config.Config PlayerRpc playerservice.PlayerService + UserRpc usercenter.Usercenter } func NewServiceContext(c config.Config) *ServiceContext { return &ServiceContext{ Config: c, PlayerRpc: playerservice.NewPlayerService(zrpc.MustNewClient(c.PlayerRpcConf)), + UserRpc: usercenter.NewUsercenter(zrpc.MustNewClient(c.UsercenterRpcConf)), } } diff --git a/app/player/rpc/internal/logic/addPlayersLogic.go b/app/player/rpc/internal/logic/addPlayersLogic.go index ee3a39d..6142ac2 100644 --- a/app/player/rpc/internal/logic/addPlayersLogic.go +++ b/app/player/rpc/internal/logic/addPlayersLogic.go @@ -33,18 +33,28 @@ func (l *AddPlayersLogic) AddPlayers(in *pb.AddPlayersReq) (*pb.AddPlayersResp, logx.Errorf("addPlayerServices err:%v", err) return nil, errors.New("create player service id failed") } - _, err = l.svcCtx.PlayerModelRW.Players.Create(). + creator := l.svcCtx.PlayerModelRW.Players.Create(). SetID(idResp.Id). SetUserID(in.UserId). SetStatus(in.Status). SetRating(decimal.NewFromFloat(in.Rating)). - SetTotalOrders(int(in.TotalOrders)). - SetCompletedOrders(int(in.CompletedOrders)). - SetShopID(in.ShopId). - SetTags(in.Tags). - SetGender(in.Gender != 0). - SetGames(in.Games). - Save(l.ctx) + SetGender(in.Gender != 0) + if in.TotalOrders != 0 { + creator.SetTotalOrders(int(in.TotalOrders)) + } + if in.CompletedOrders != 0 { + creator.SetCompletedOrders(int(in.CompletedOrders)) + } + if in.ShopId != 0 { + creator.SetShopID(in.ShopId) + } + if len(in.GetTags()) > 0 { + creator.SetTags(in.GetTags()) + } + if len(in.GetGames()) > 0 { + creator.SetGames(in.GetGames()) + } + _, err = creator.Save(l.ctx) if err != nil { logx.Errorf("addPlayerServices err:%v", err) return nil, errors.New("add player service failed") diff --git a/app/player/rpc/internal/logic/getPlayerByUserIdLogic.go b/app/player/rpc/internal/logic/getPlayerByUserIdLogic.go index f9a5fc9..3c5f60e 100644 --- a/app/player/rpc/internal/logic/getPlayerByUserIdLogic.go +++ b/app/player/rpc/internal/logic/getPlayerByUserIdLogic.go @@ -3,12 +3,15 @@ package logic import ( "context" "errors" + "juwan-backend/app/player/rpc/internal/models" "juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/svc" "juwan-backend/app/player/rpc/pb" "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type GetPlayerByUserIdLogic struct { @@ -32,6 +35,9 @@ func (l *GetPlayerByUserIdLogic) GetPlayerByUserId(in *pb.SearchPlayersReq) (*pb player, err := l.svcCtx.PlayerModelRO.Players.Query().Where(players.UserIDEQ(in.GetUserId())).First(l.ctx) if err != nil { + if models.IsNotFound(err) { + return nil, status.Error(codes.NotFound, "player not found") + } logx.WithContext(l.ctx).Errorf("GetPlayerByUserIdLogic err: %v", err) return nil, errors.New("get player by user id failed") } @@ -40,6 +46,7 @@ func (l *GetPlayerByUserIdLogic) GetPlayerByUserId(in *pb.SearchPlayersReq) (*pb Id: player.ID, UserId: player.UserID, Status: player.Status, + Gender: player.Gender, Rating: player.Rating.InexactFloat64(), TotalOrders: int64(player.TotalOrders), CompletedOrders: int64(player.CompletedOrders), diff --git a/app/player/rpc/internal/models/players.go b/app/player/rpc/internal/models/players.go index 335a18d..404a84a 100644 --- a/app/player/rpc/internal/models/players.go +++ b/app/player/rpc/internal/models/players.go @@ -3,9 +3,9 @@ package models import ( - "encoding/json" "fmt" "juwan-backend/app/player/rpc/internal/models/players" + "juwan-backend/pkg/types" "strings" "time" @@ -51,7 +51,7 @@ func (*Players) scanValues(columns []string) ([]any, error) { for i := range columns { switch columns[i] { case players.FieldTags: - values[i] = new([]byte) + values[i] = new(types.TextArray) case players.FieldRating: values[i] = new(decimal.Decimal) case players.FieldGames: @@ -129,12 +129,10 @@ func (_m *Players) assignValues(columns []string, values []any) error { *_m.ShopID = value.Int64 } case players.FieldTags: - if value, ok := values[i].(*[]byte); !ok { + if value, ok := values[i].(*types.TextArray); !ok { return fmt.Errorf("unexpected type %T for field tags", values[i]) - } else if value != nil && len(*value) > 0 { - if err := json.Unmarshal(*value, &_m.Tags); err != nil { - return fmt.Errorf("unmarshal field tags: %w", err) - } + } else if value != nil { + _m.Tags = append([]string{}, value.Elements...) } case players.FieldGames: if value, ok := values[i].(*pq.Int64Array); !ok { diff --git a/app/player/rpc/internal/models/players_create.go b/app/player/rpc/internal/models/players_create.go index 9e0935d..4fa4d4a 100644 --- a/app/player/rpc/internal/models/players_create.go +++ b/app/player/rpc/internal/models/players_create.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "juwan-backend/app/player/rpc/internal/models/players" + "juwan-backend/pkg/types" "time" "entgo.io/ent/dialect/sql/sqlgraph" @@ -314,7 +315,8 @@ func (_c *PlayersCreate) createSpec() (*Players, *sqlgraph.CreateSpec) { _node.ShopID = &value } if value, ok := _c.mutation.Tags(); ok { - _spec.SetField(players.FieldTags, field.TypeJSON, value) + tags := types.TextArray{Elements: append([]string{}, value...), Valid: true} + _spec.SetField(players.FieldTags, field.TypeOther, tags) _node.Tags = value } if value, ok := _c.mutation.Games(); ok { diff --git a/app/player/rpc/internal/models/players_update.go b/app/player/rpc/internal/models/players_update.go index 87453d9..db2ab59 100644 --- a/app/player/rpc/internal/models/players_update.go +++ b/app/player/rpc/internal/models/players_update.go @@ -8,6 +8,7 @@ import ( "fmt" "juwan-backend/app/player/rpc/internal/models/players" "juwan-backend/app/player/rpc/internal/models/predicate" + "juwan-backend/pkg/types" "time" "entgo.io/ent/dialect/sql" @@ -326,7 +327,8 @@ func (_u *PlayersUpdate) sqlSave(ctx context.Context) (_node int, err error) { _spec.ClearField(players.FieldShopID, field.TypeInt64) } if value, ok := _u.mutation.Tags(); ok { - _spec.SetField(players.FieldTags, field.TypeJSON, value) + tags := types.TextArray{Elements: append([]string{}, value...), Valid: true} + _spec.SetField(players.FieldTags, field.TypeOther, tags) } if value, ok := _u.mutation.AppendedTags(); ok { _spec.AddModifier(func(u *sql.UpdateBuilder) { @@ -334,7 +336,7 @@ func (_u *PlayersUpdate) sqlSave(ctx context.Context) (_node int, err error) { }) } if _u.mutation.TagsCleared() { - _spec.ClearField(players.FieldTags, field.TypeJSON) + _spec.ClearField(players.FieldTags, field.TypeOther) } if value, ok := _u.mutation.Games(); ok { _spec.SetField(players.FieldGames, field.TypeOther, value) @@ -690,7 +692,8 @@ func (_u *PlayersUpdateOne) sqlSave(ctx context.Context) (_node *Players, err er _spec.ClearField(players.FieldShopID, field.TypeInt64) } if value, ok := _u.mutation.Tags(); ok { - _spec.SetField(players.FieldTags, field.TypeJSON, value) + tags := types.TextArray{Elements: append([]string{}, value...), Valid: true} + _spec.SetField(players.FieldTags, field.TypeOther, tags) } if value, ok := _u.mutation.AppendedTags(); ok { _spec.AddModifier(func(u *sql.UpdateBuilder) { @@ -698,7 +701,7 @@ func (_u *PlayersUpdateOne) sqlSave(ctx context.Context) (_node *Players, err er }) } if _u.mutation.TagsCleared() { - _spec.ClearField(players.FieldTags, field.TypeJSON) + _spec.ClearField(players.FieldTags, field.TypeOther) } if value, ok := _u.mutation.Games(); ok { _spec.SetField(players.FieldGames, field.TypeOther, value) diff --git a/desc/api/player.api b/desc/api/player.api index b11cb10..b394f07 100644 --- a/desc/api/player.api +++ b/desc/api/player.api @@ -123,6 +123,10 @@ type ( group: player ) service player-api { + @doc "初始化当前用户的打手资料" + @handler InitPlayer + post /players/me (EmptyResp) returns (PlayerProfile) + @doc "更新接单状态" @handler UpdatePlayerStatus put /players/me/status (UpdatePlayerStatusReq) returns (EmptyResp)