package http import ( "net/http" "strings" userv1 "hyapp/api/proto/user/v1" "hyapp/services/gateway-service/internal/auth" ) // userIdentityData 是 gateway 对外返回的当前短号投影。 // `display_user_id` 永远表示当前有效展示号,临时靓号过期后由 user-service 恢复为默认短号。 type userIdentityData struct { UserID int64 `json:"user_id"` DisplayUserID string `json:"display_user_id"` Status string `json:"status"` DefaultDisplayUserID string `json:"default_display_user_id"` DisplayUserIDKind string `json:"display_user_id_kind"` DisplayUserIDExpiresAtMs int64 `json:"display_user_id_expires_at_ms"` LeaseID string `json:"lease_id,omitempty"` } // userProfileData 是 gateway 对外返回的用户基础资料投影。 // 它不包含注册来源、三方身份或 refresh session 等服务端内部字段。 type userProfileData struct { UserID int64 `json:"user_id"` DisplayUserID string `json:"display_user_id"` DefaultDisplayUserID string `json:"default_display_user_id"` DisplayUserIDKind string `json:"display_user_id_kind"` DisplayUserIDExpiresAtMs int64 `json:"display_user_id_expires_at_ms"` Username string `json:"username"` Gender string `json:"gender,omitempty"` Country string `json:"country,omitempty"` CountryID int64 `json:"country_id,omitempty"` CountryName string `json:"country_name,omitempty"` CountryDisplayName string `json:"country_display_name,omitempty"` RegionID int64 `json:"region_id,omitempty"` RegionCode string `json:"region_code,omitempty"` RegionName string `json:"region_name,omitempty"` Avatar string `json:"avatar,omitempty"` Birth string `json:"birth,omitempty"` Language string `json:"language,omitempty"` UpdatedAtMs int64 `json:"updated_at_ms"` NextCountryChangeAtMs int64 `json:"next_country_change_allowed_at_ms,omitempty"` } // getMyIdentity 返回当前登录用户的短号状态。 func (h *Handler) getMyIdentity(writer http.ResponseWriter, request *http.Request) { if h.userIdentityClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } resp, err := h.userIdentityClient.GetUserIdentity(request.Context(), &userv1.GetUserIdentityRequest{ Meta: authRequestMeta(request, ""), UserId: auth.UserIDFromContext(request.Context()), }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, identityData(resp.GetIdentity(), "")) } // resolveDisplayUserID 通过当前有效展示号解析用户。 func (h *Handler) resolveDisplayUserID(writer http.ResponseWriter, request *http.Request) { if h.userIdentityClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } displayUserID := strings.TrimPrefix(request.URL.Path, apiV1Prefix+"/users/by-display-user-id/") resp, err := h.userIdentityClient.ResolveDisplayUserID(request.Context(), &userv1.ResolveDisplayUserIDRequest{ Meta: authRequestMeta(request, ""), DisplayUserId: displayUserID, }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, identityData(resp.GetIdentity(), "")) } // updateMyProfile 修改当前用户的用户名、头像和生日。 func (h *Handler) updateMyProfile(writer http.ResponseWriter, request *http.Request) { var body struct { Username *string `json:"username"` Avatar *string `json:"avatar"` Birth *string `json:"birth"` } if !decode(writer, request, &body) { return } if h.userProfileClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } resp, err := h.userProfileClient.UpdateUserProfile(request.Context(), &userv1.UpdateUserProfileRequest{ Meta: authRequestMeta(request, ""), UserId: auth.UserIDFromContext(request.Context()), Username: body.Username, Avatar: body.Avatar, Birth: body.Birth, }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, profileData(resp.GetUser(), 0)) } // changeMyCountry 单独修改当前用户国家;冷却期和审计由 user-service 保证。 func (h *Handler) changeMyCountry(writer http.ResponseWriter, request *http.Request) { var body struct { Country string `json:"country"` } if !decode(writer, request, &body) { return } if h.userProfileClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } resp, err := h.userProfileClient.ChangeUserCountry(request.Context(), &userv1.ChangeUserCountryRequest{ Meta: authRequestMeta(request, ""), UserId: auth.UserIDFromContext(request.Context()), Country: body.Country, }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, profileData(resp.GetUser(), resp.GetNextChangeAllowedAtMs())) } // changeMyDisplayUserID 修改当前登录用户的默认短号。 func (h *Handler) changeMyDisplayUserID(writer http.ResponseWriter, request *http.Request) { var body struct { NewDisplayUserID string `json:"new_display_user_id"` Reason string `json:"reason"` } if !decode(writer, request, &body) { return } if h.userIdentityClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } resp, err := h.userIdentityClient.ChangeDisplayUserID(request.Context(), &userv1.ChangeDisplayUserIDRequest{ Meta: authRequestMeta(request, ""), UserId: auth.UserIDFromContext(request.Context()), NewDisplayUserId: body.NewDisplayUserID, Reason: body.Reason, OperatorUserId: auth.UserIDFromContext(request.Context()), }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, identityData(resp.GetIdentity(), "")) } // applyMyPrettyDisplayUserID 为当前登录用户申请临时靓号。 func (h *Handler) applyMyPrettyDisplayUserID(writer http.ResponseWriter, request *http.Request) { var body struct { PrettyDisplayUserID string `json:"pretty_display_user_id"` LeaseDurationMs int64 `json:"lease_duration_ms"` PaymentReceiptID string `json:"payment_receipt_id"` } if !decode(writer, request, &body) { return } if h.userIdentityClient == nil { writeError(writer, request, http.StatusBadGateway, codeUpstreamError, "upstream service error") return } resp, err := h.userIdentityClient.ApplyPrettyDisplayUserID(request.Context(), &userv1.ApplyPrettyDisplayUserIDRequest{ Meta: authRequestMeta(request, ""), UserId: auth.UserIDFromContext(request.Context()), PrettyDisplayUserId: body.PrettyDisplayUserID, LeaseDurationMs: body.LeaseDurationMs, PaymentReceiptId: body.PaymentReceiptID, }) if err != nil { writeRPCError(writer, request, err) return } writeOK(writer, request, identityData(resp.GetIdentity(), resp.GetLeaseId())) } func identityData(identity *userv1.UserIdentity, leaseID string) userIdentityData { if identity == nil { return userIdentityData{LeaseID: leaseID} } return userIdentityData{ UserID: identity.GetUserId(), DisplayUserID: identity.GetDisplayUserId(), Status: identity.GetStatus(), DefaultDisplayUserID: identity.GetDefaultDisplayUserId(), DisplayUserIDKind: identity.GetDisplayUserIdKind(), DisplayUserIDExpiresAtMs: identity.GetDisplayUserIdExpiresAtMs(), LeaseID: leaseID, } } func profileData(user *userv1.User, nextCountryChangeAtMs int64) userProfileData { if user == nil { return userProfileData{NextCountryChangeAtMs: nextCountryChangeAtMs} } return userProfileData{ UserID: user.GetUserId(), DisplayUserID: user.GetDisplayUserId(), DefaultDisplayUserID: user.GetDefaultDisplayUserId(), DisplayUserIDKind: user.GetDisplayUserIdKind(), DisplayUserIDExpiresAtMs: user.GetDisplayUserIdExpiresAtMs(), Username: user.GetUsername(), Gender: user.GetGender(), Country: user.GetCountry(), CountryID: user.GetCountryId(), CountryName: user.GetCountryName(), CountryDisplayName: user.GetCountryDisplayName(), RegionID: user.GetRegionId(), RegionCode: user.GetRegionCode(), RegionName: user.GetRegionName(), Avatar: user.GetAvatar(), Birth: user.GetBirth(), Language: user.GetLanguage(), UpdatedAtMs: user.GetUpdatedAtMs(), NextCountryChangeAtMs: nextCountryChangeAtMs, } }