2026-06-08 14:12:23 +08:00

243 lines
8.8 KiB
Go

package userapi
import (
"net/http"
"strings"
userv1 "hyapp.local/api/proto/user/v1"
"hyapp/services/gateway-service/internal/auth"
"hyapp/services/gateway-service/internal/transport/http/httpkit"
)
type cpUserProfileData struct {
UserID string `json:"user_id"`
DisplayUserID string `json:"display_user_id"`
Username string `json:"username"`
Avatar string `json:"avatar"`
}
type cpGiftSnapshotData struct {
GiftID string `json:"gift_id"`
GiftName string `json:"gift_name"`
GiftIconURL string `json:"gift_icon_url"`
GiftAnimationURL string `json:"gift_animation_url"`
GiftCount int32 `json:"gift_count"`
GiftValue int64 `json:"gift_value"`
BillingReceiptID string `json:"billing_receipt_id"`
}
type cpApplicationData struct {
ApplicationID string `json:"application_id"`
RelationType string `json:"relation_type"`
Status string `json:"status"`
Requester *cpUserProfileData `json:"requester,omitempty"`
Target *cpUserProfileData `json:"target,omitempty"`
RoomID string `json:"room_id"`
RoomRegionID int64 `json:"room_region_id"`
Gift *cpGiftSnapshotData `json:"gift,omitempty"`
CreatedAtMS int64 `json:"created_at_ms"`
UpdatedAtMS int64 `json:"updated_at_ms"`
ExpiresAtMS int64 `json:"expires_at_ms"`
DecidedAtMS int64 `json:"decided_at_ms"`
}
type cpRelationshipData struct {
RelationshipID string `json:"relationship_id"`
RelationType string `json:"relation_type"`
Status string `json:"status"`
Me *cpUserProfileData `json:"me,omitempty"`
Partner *cpUserProfileData `json:"partner,omitempty"`
IntimacyValue int64 `json:"intimacy_value"`
Level int32 `json:"level"`
FormedAtMS int64 `json:"formed_at_ms"`
UpdatedAtMS int64 `json:"updated_at_ms"`
}
type cpRejectRequest struct {
Reason string `json:"reason"`
}
// listCPApplications 返回当前用户收到或发出的 CP/兄弟/姐妹申请。
func (h *Handler) listCPApplications(writer http.ResponseWriter, request *http.Request) {
if h.userCPClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
page, pageSize, ok := socialPage(request)
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
resp, err := h.userCPClient.ListCPApplications(request.Context(), &userv1.ListCPApplicationsRequest{
Meta: httpkit.UserMeta(request, ""),
UserId: auth.UserIDFromContext(request.Context()),
Direction: strings.TrimSpace(request.URL.Query().Get("direction")),
Status: strings.TrimSpace(request.URL.Query().Get("status")),
Page: page,
PageSize: pageSize,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
applications := make([]cpApplicationData, 0, len(resp.GetApplications()))
for _, item := range resp.GetApplications() {
applications = append(applications, cpApplicationFromProto(item))
}
httpkit.WriteOK(writer, request, map[string]any{
"applications": applications,
"total": resp.GetTotal(),
"server_time_ms": resp.GetServerTimeMs(),
})
}
// acceptCPApplication 同意一条申请;同意后同一对用户其他 pending 类型由 user-service 阻断。
func (h *Handler) acceptCPApplication(writer http.ResponseWriter, request *http.Request) {
if h.userCPClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
applicationID := strings.TrimSpace(request.PathValue("application_id"))
if applicationID == "" {
httpkit.WriteError(writer, request, http.StatusNotFound, httpkit.CodeNotFound, "not found")
return
}
resp, err := h.userCPClient.AcceptCPApplication(request.Context(), &userv1.AcceptCPApplicationRequest{
Meta: httpkit.UserMeta(request, ""),
UserId: auth.UserIDFromContext(request.Context()),
ApplicationId: applicationID,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
httpkit.WriteOK(writer, request, map[string]any{
"application": cpApplicationFromProto(resp.GetApplication()),
"relationship": cpRelationshipFromProto(resp.GetRelationship()),
})
}
// rejectCPApplication 拒绝一条申请;拒绝不会删除历史申请,客户端仍可看到 decided 状态。
func (h *Handler) rejectCPApplication(writer http.ResponseWriter, request *http.Request) {
if h.userCPClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
applicationID := strings.TrimSpace(request.PathValue("application_id"))
if applicationID == "" {
httpkit.WriteError(writer, request, http.StatusNotFound, httpkit.CodeNotFound, "not found")
return
}
var body cpRejectRequest
if request.Body != nil && request.ContentLength != 0 && !httpkit.Decode(writer, request, &body) {
return
}
resp, err := h.userCPClient.RejectCPApplication(request.Context(), &userv1.RejectCPApplicationRequest{
Meta: httpkit.UserMeta(request, ""),
UserId: auth.UserIDFromContext(request.Context()),
ApplicationId: applicationID,
Reason: body.Reason,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
httpkit.WriteOK(writer, request, map[string]any{"application": cpApplicationFromProto(resp.GetApplication())})
}
// listCPRelationships 返回当前用户 active 关系;服务端固定限制一个用户只能同时存在一条关系。
func (h *Handler) listCPRelationships(writer http.ResponseWriter, request *http.Request) {
if h.userCPClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
page, pageSize, ok := socialPage(request)
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
resp, err := h.userCPClient.ListCPRelationships(request.Context(), &userv1.ListCPRelationshipsRequest{
Meta: httpkit.UserMeta(request, ""),
UserId: auth.UserIDFromContext(request.Context()),
RelationType: strings.TrimSpace(request.URL.Query().Get("relation_type")),
Page: page,
PageSize: pageSize,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
relationships := make([]cpRelationshipData, 0, len(resp.GetRelationships()))
for _, item := range resp.GetRelationships() {
relationships = append(relationships, cpRelationshipFromProto(item))
}
httpkit.WriteOK(writer, request, map[string]any{
"relationships": relationships,
"total": resp.GetTotal(),
})
}
func cpApplicationFromProto(item *userv1.CPApplication) cpApplicationData {
if item == nil {
return cpApplicationData{}
}
return cpApplicationData{
ApplicationID: item.GetApplicationId(),
RelationType: item.GetRelationType(),
Status: item.GetStatus(),
Requester: cpUserProfileFromProto(item.GetRequester()),
Target: cpUserProfileFromProto(item.GetTarget()),
RoomID: item.GetRoomId(),
RoomRegionID: item.GetRoomRegionId(),
Gift: cpGiftSnapshotFromProto(item.GetGift()),
CreatedAtMS: item.GetCreatedAtMs(),
UpdatedAtMS: item.GetUpdatedAtMs(),
ExpiresAtMS: item.GetExpiresAtMs(),
DecidedAtMS: item.GetDecidedAtMs(),
}
}
func cpRelationshipFromProto(item *userv1.CPRelationship) cpRelationshipData {
if item == nil {
return cpRelationshipData{}
}
return cpRelationshipData{
RelationshipID: item.GetRelationshipId(),
RelationType: item.GetRelationType(),
Status: item.GetStatus(),
Me: cpUserProfileFromProto(item.GetMe()),
Partner: cpUserProfileFromProto(item.GetPartner()),
IntimacyValue: item.GetIntimacyValue(),
Level: item.GetLevel(),
FormedAtMS: item.GetFormedAtMs(),
UpdatedAtMS: item.GetUpdatedAtMs(),
}
}
func cpUserProfileFromProto(item *userv1.CPUserProfile) *cpUserProfileData {
if item == nil || item.GetUserId() <= 0 {
return nil
}
return &cpUserProfileData{
UserID: userIDString(item.GetUserId()),
DisplayUserID: item.GetDisplayUserId(),
Username: item.GetUsername(),
Avatar: item.GetAvatar(),
}
}
func cpGiftSnapshotFromProto(item *userv1.CPGiftSnapshot) *cpGiftSnapshotData {
if item == nil {
return nil
}
return &cpGiftSnapshotData{
GiftID: item.GetGiftId(),
GiftName: item.GetGiftName(),
GiftIconURL: item.GetGiftIconUrl(),
GiftAnimationURL: item.GetGiftAnimationUrl(),
GiftCount: item.GetGiftCount(),
GiftValue: item.GetGiftValue(),
BillingReceiptID: item.GetBillingReceiptId(),
}
}