feat(social): блокировка пользователей
- PUT/DELETE /users/@me/blocks/{id}: блокировка снимает дружбу и заявки в обе
стороны, разблокировка возвращает возможность писать (AGENT.md 7.2)
- блокировка запрещает личные сообщения (ошибка dm.blocked), открытие беседы и
заявки в друзья с любой стороны
- клиент: раздел «Заблокированные» в друзьях со снятием блокировки, действие
«Заблокировать» в меню строки друга и в меню модерации участника
- тесты: Go (блокировка, заявки, беседа, сообщение) и Vitest (список, снятие,
блокировка из меню)
This commit is contained in:
@@ -521,3 +521,84 @@ func TestMembersCarrySystemBadges(t *testing.T) {
|
||||
t.Fatalf("участник %s не найден: %s", ownerID, list.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockUserStopsDMsAndRequests(t *testing.T) {
|
||||
srv, owner, member, _, memberID := cosmeticsFixture(t)
|
||||
me := doJSON(t, srv, http.MethodGet, "/api/v1/users/@me", "", owner)
|
||||
ownerID := decodeResponse[struct {
|
||||
User struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"user"`
|
||||
}](t, me).User.ID
|
||||
|
||||
// Заводим дружбу, затем блокируем: связь снимается, остаётся блокировка.
|
||||
request := doJSON(t, srv, http.MethodPost, "/api/v1/users/@me/relationships",
|
||||
`{"user_id":"`+memberID+`"}`, owner)
|
||||
if request.Code != http.StatusOK {
|
||||
t.Fatalf("заявка = %d (%s)", request.Code, request.Body.String())
|
||||
}
|
||||
if accept := doJSON(t, srv, http.MethodPost,
|
||||
"/api/v1/users/@me/relationships/"+ownerID+"/accept", "", member); accept.Code != http.StatusOK {
|
||||
t.Fatalf("принятие = %d", accept.Code)
|
||||
}
|
||||
|
||||
blocked := doJSON(t, srv, http.MethodPut, "/api/v1/users/@me/blocks/"+memberID, "", owner)
|
||||
if blocked.Code != http.StatusOK {
|
||||
t.Fatalf("блокировка = %d (%s)", blocked.Code, blocked.Body.String())
|
||||
}
|
||||
relations := doJSON(t, srv, http.MethodGet, "/api/v1/users/@me/relationships", "", owner)
|
||||
list := decodeResponse[struct {
|
||||
Friends []struct {
|
||||
UserID string `json:"user_id"`
|
||||
} `json:"friends"`
|
||||
Blocked []struct {
|
||||
UserID string `json:"user_id"`
|
||||
} `json:"blocked"`
|
||||
}](t, relations)
|
||||
if len(list.Friends) != 0 || len(list.Blocked) != 1 || list.Blocked[0].UserID != memberID {
|
||||
t.Fatalf("после блокировки: друзей %d, заблокированных %d", len(list.Friends), len(list.Blocked))
|
||||
}
|
||||
|
||||
// Заявка в друзья от заблокированного отклоняется.
|
||||
again := doJSON(t, srv, http.MethodPost, "/api/v1/users/@me/relationships",
|
||||
`{"user_id":"`+ownerID+`"}`, member)
|
||||
if again.Code != http.StatusForbidden {
|
||||
t.Fatalf("заявка от заблокированного = %d, ожидался 403 (%s)", again.Code, again.Body.String())
|
||||
}
|
||||
|
||||
// Личная беседа не открывается и сообщения в неё не уходят.
|
||||
open := doJSON(t, srv, http.MethodPost, "/api/v1/users/@me/channels",
|
||||
`{"recipient_id":"`+memberID+`"}`, owner)
|
||||
if open.Code != http.StatusForbidden {
|
||||
t.Fatalf("беседа с заблокированным = %d, ожидался 403 (%s)", open.Code, open.Body.String())
|
||||
}
|
||||
|
||||
// Снятие блокировки возвращает возможность писать.
|
||||
if unblock := doJSON(t, srv, http.MethodDelete, "/api/v1/users/@me/blocks/"+memberID, "", owner); unblock.Code != http.StatusOK {
|
||||
t.Fatalf("снятие блокировки = %d", unblock.Code)
|
||||
}
|
||||
reopened := doJSON(t, srv, http.MethodPost, "/api/v1/users/@me/channels",
|
||||
`{"recipient_id":"`+memberID+`"}`, owner)
|
||||
if reopened.Code != http.StatusOK {
|
||||
t.Fatalf("беседа после снятия блокировки = %d (%s)", reopened.Code, reopened.Body.String())
|
||||
}
|
||||
channelID := decodeResponse[struct {
|
||||
Channel struct {
|
||||
ID string `json:"id"`
|
||||
} `json:"channel"`
|
||||
}](t, reopened).Channel.ID
|
||||
|
||||
// Блокируем снова уже при существующей беседе: сообщение не отправляется.
|
||||
if rec := doJSON(t, srv, http.MethodPut, "/api/v1/users/@me/blocks/"+memberID, "", owner); rec.Code != http.StatusOK {
|
||||
t.Fatalf("повторная блокировка = %d", rec.Code)
|
||||
}
|
||||
post := doJSON(t, srv, http.MethodPost, "/api/v1/channels/"+channelID+"/messages",
|
||||
`{"content":"привет"}`, owner)
|
||||
if post.Code != http.StatusForbidden {
|
||||
t.Fatalf("сообщение заблокированному = %d, ожидался 403 (%s)", post.Code, post.Body.String())
|
||||
}
|
||||
if code := errorCodeOf(t, post); code != "dm.blocked" {
|
||||
t.Fatalf("код ошибки = %q", code)
|
||||
}
|
||||
_ = ownerID
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user