用户锁国家
This commit is contained in:
parent
d67213fca6
commit
a844c7b738
@ -3251,6 +3251,7 @@ definitions:
|
||||
- DISPLAY_USER_ID_EXISTS
|
||||
- DISPLAY_USER_ID_COOLDOWN
|
||||
- COUNTRY_CHANGE_COOLDOWN
|
||||
- COUNTRY_CHANGE_IDENTITY_LOCKED
|
||||
- DISPLAY_USER_ID_NOT_FOUND
|
||||
- DISPLAY_USER_ID_PRETTY_NOT_AVAILABLE
|
||||
- DISPLAY_USER_ID_PRETTY_ACTIVE
|
||||
|
||||
@ -1682,6 +1682,7 @@ definitions:
|
||||
- DISPLAY_USER_ID_EXISTS
|
||||
- DISPLAY_USER_ID_COOLDOWN
|
||||
- COUNTRY_CHANGE_COOLDOWN
|
||||
- COUNTRY_CHANGE_IDENTITY_LOCKED
|
||||
- DISPLAY_USER_ID_NOT_FOUND
|
||||
- DISPLAY_USER_ID_ALLOCATE_FAILED
|
||||
- DISPLAY_USER_ID_PRETTY_NOT_AVAILABLE
|
||||
|
||||
@ -161,6 +161,7 @@ User 专用 reason:
|
||||
| --- | --- | --- |
|
||||
| `INVALID_INVITE_CODE` | `InvalidArgument` | `400` |
|
||||
| `COUNTRY_CHANGE_COOLDOWN` | `FailedPrecondition` | `409` |
|
||||
| `COUNTRY_CHANGE_IDENTITY_LOCKED` | `PermissionDenied` | `403` |
|
||||
| `USER_PROFILE_REQUIRED` | `FailedPrecondition` | `403` |
|
||||
|
||||
Wallet 专用 reason:
|
||||
|
||||
@ -1007,6 +1007,7 @@ gateway HTTP envelope 的 `code` 不使用数字。
|
||||
| `PROFILE_REQUIRED` | 403 | authenticated user has not completed required registration profile |
|
||||
| `PASSWORD_ALREADY_SET` | 409 | user already has password identity |
|
||||
| `COUNTRY_CHANGE_COOLDOWN` | 409 | country change is within the 30-day cooldown window |
|
||||
| `COUNTRY_CHANGE_IDENTITY_LOCKED` | 403 | an existing host or business identity requires customer-service country changes |
|
||||
| `USER_DISABLED` | 403 | user is disabled or banned |
|
||||
| `SESSION_EXPIRED` | 401 | refresh token expired |
|
||||
| `SESSION_REVOKED` | 401 | refresh token revoked |
|
||||
|
||||
@ -70,6 +70,12 @@ var catalog = map[Code]Spec{
|
||||
DisplayUserIDPaymentRequired: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDPaymentRequired, "pretty display user id payment required"),
|
||||
|
||||
CountryChangeCooldown: spec(codes.FailedPrecondition, httpStatusConflict, CountryChangeCooldown, "country change is cooling down"),
|
||||
CountryChangeIdentityLocked: spec(
|
||||
codes.PermissionDenied,
|
||||
httpStatusForbidden,
|
||||
CountryChangeIdentityLocked,
|
||||
"You already have a host identity. Please contact customer service to change your country.",
|
||||
),
|
||||
CountryNotFound: spec(codes.NotFound, httpStatusNotFound, CountryNotFound, "not found"),
|
||||
RegionNotFound: spec(codes.NotFound, httpStatusNotFound, RegionNotFound, "not found"),
|
||||
RegionCountryConflict: spec(codes.FailedPrecondition, httpStatusConflict, RegionCountryConflict, "country already belongs to another region"),
|
||||
|
||||
@ -66,6 +66,8 @@ const (
|
||||
DisplayUserIDPaymentRequired Code = "DISPLAY_USER_ID_PAYMENT_REQUIRED"
|
||||
// CountryChangeCooldown 表示用户仍处在国家修改冷却期。
|
||||
CountryChangeCooldown Code = "COUNTRY_CHANGE_COOLDOWN"
|
||||
// CountryChangeIdentityLocked 表示用户已有经营身份,国家只能由客服治理入口修改。
|
||||
CountryChangeIdentityLocked Code = "COUNTRY_CHANGE_IDENTITY_LOCKED"
|
||||
// CountryNotFound 表示国家主数据不存在或已经停用。
|
||||
CountryNotFound Code = "COUNTRY_NOT_FOUND"
|
||||
// RegionNotFound 表示区域主数据不存在。
|
||||
|
||||
@ -159,6 +159,14 @@ func TestCatalogMappings(t *testing.T) {
|
||||
publicCode: string(CountryChangeCooldown),
|
||||
publicMessage: "country change is cooling down",
|
||||
},
|
||||
{
|
||||
name: "country identity lock tells user how to proceed",
|
||||
code: CountryChangeIdentityLocked,
|
||||
grpcCode: codes.PermissionDenied,
|
||||
httpStatus: httpStatusForbidden,
|
||||
publicCode: string(CountryChangeIdentityLocked),
|
||||
publicMessage: "You already have a host identity. Please contact customer service to change your country.",
|
||||
},
|
||||
{
|
||||
name: "registered device conflict exposes concrete login reason",
|
||||
code: DeviceAlreadyRegistered,
|
||||
|
||||
@ -11105,6 +11105,27 @@ func TestChangeCountryUsesAuthenticatedUserIDAndMapsCooldown(t *testing.T) {
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelopeMessage(t, recorder, http.StatusConflict, string(xerr.CountryChangeCooldown), "country change is cooling down", "req-country-cooldown")
|
||||
|
||||
profileClient = &fakeUserProfileClient{countryErr: xerr.ToGRPCError(xerr.New(
|
||||
xerr.CountryChangeIdentityLocked,
|
||||
"You already have a host identity. Please contact customer service to change your country.",
|
||||
))}
|
||||
router = NewHandlerWithClients(&fakeRoomClient{}, nil, nil, profileClient).Routes(auth.NewVerifier("secret"))
|
||||
request = httptest.NewRequest(http.MethodPost, "/api/v1/users/me/country/change", bytes.NewReader(body))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
request.Header.Set("X-Request-ID", "req-country-identity-locked")
|
||||
recorder = httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
assertEnvelopeMessage(
|
||||
t,
|
||||
recorder,
|
||||
http.StatusForbidden,
|
||||
string(xerr.CountryChangeIdentityLocked),
|
||||
"You already have a host identity. Please contact customer service to change your country.",
|
||||
"req-country-identity-locked",
|
||||
)
|
||||
}
|
||||
|
||||
func TestChangeCountryRemovesOldRegionBroadcastMember(t *testing.T) {
|
||||
|
||||
@ -272,7 +272,11 @@ func (s *Service) ChangeUserCountry(ctx context.Context, userID int64, country s
|
||||
}
|
||||
if role := blockedCountryChangeRole(summary); role != "" {
|
||||
// App 自助入口不能改变已有经营身份的区域归属,否则房间、组织和币商读模型会在用户侧无审计地漂移。
|
||||
return userdomain.User{}, 0, xerr.New(xerr.PermissionDenied, "you have "+role+" id, not allow modify country")
|
||||
// 使用独立公开 reason,避免 gateway 把普通 PERMISSION_DENIED 脱敏成语义不明的固定文案。
|
||||
return userdomain.User{}, 0, xerr.New(
|
||||
xerr.CountryChangeIdentityLocked,
|
||||
"You already have a host identity. Please contact customer service to change your country.",
|
||||
)
|
||||
}
|
||||
}
|
||||
resolvedCountry, regionID, err := s.resolveCountryRegionForChange(ctx, country)
|
||||
|
||||
@ -114,10 +114,10 @@ func TestChangeUserCountryRejectsProtectedRoles(t *testing.T) {
|
||||
)
|
||||
|
||||
_, _, err := svc.ChangeUserCountry(appcode.WithContext(context.Background(), "lalu"), 10001, "ID", "req-protected")
|
||||
if xerr.CodeOf(err) != xerr.PermissionDenied {
|
||||
t.Fatalf("protected role must be permission denied: role=%s err=%v", tc.role, err)
|
||||
if xerr.CodeOf(err) != xerr.CountryChangeIdentityLocked {
|
||||
t.Fatalf("protected role must return identity lock: role=%s err=%v", tc.role, err)
|
||||
}
|
||||
want := "you have " + tc.role + " id, not allow modify country"
|
||||
want := "You already have a host identity. Please contact customer service to change your country."
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("protected role message mismatch: got=%q want contains=%q", err.Error(), want)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user