feat(social): друзья, личные беседы, присутствие, аватары и часовой пояс
По запросу пользователя (вне очереди AGENT.md §13): - главного сервера как точки входа больше нет: новичок начинает с пустым списком серверов, вход — только по приглашению или созданием своего; - друзья: поиск по логину с экранированием LIKE, заявки (POST /users/@me/relationships), принятие, удаление/отклонение, списки friends/ incoming/outgoing/blocked; - личные беседы: POST /users/@me/channels (идемпотентно), GET /users/@me/channels со собеседником, статусом и последним сообщением; сообщения в DM работают через общие ручки комнат, доступ — только участникам (посторонний получает 404, события в Gateway тоже фильтруются); - присутствие: last_seen_at обновляется при активности, «невидимка» и простой дольше двух минут выглядят как офлайн, смена статуса рассылает PRESENCE_UPDATE друзьям; - READY отдаёт dm_channels (собеседник, аватар, статус, последнее сообщение); - профиль: timezone (по умолчанию Europe/Moscow) в PATCH /users/@me, загрузка аватара POST /users/@me/avatar (проверка, что это изображение, в том числе по содержимому) и удаление DELETE /users/@me/avatar; старый файл удаляется с диска; - тесты: заявки в друзья, личные беседы и их изоляция, «невидимка», часовой пояс и аватар, PRESENCE_UPDATE другу, отсутствие событий DM у постороннего.
This commit is contained in:
@@ -114,10 +114,9 @@ func TestRegisterAndLogin(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Register: %v", err)
|
||||
}
|
||||
// Главный сервер создаётся установщиком (владелец — уже существующий админ).
|
||||
// Сервер существует (создан установщиком), но новый пользователь в него
|
||||
// не попадает: вход только по приглашению (решение пользователя).
|
||||
bootstrapMainGuild(t, st, user.ID)
|
||||
// Новый пользователь регистрируется после появления главного сервера,
|
||||
// чтобы проверить автовступление.
|
||||
second, _, _, err := service.Register(ctx, auth.RegisterInput{
|
||||
Username: "newcomer", Email: "newcomer@example.com", Password: "correct-horse-battery",
|
||||
})
|
||||
@@ -128,15 +127,8 @@ func TestRegisterAndLogin(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("ListGuildsForUser(newcomer): %v", err)
|
||||
}
|
||||
if len(newcomerGuilds) != 1 || !newcomerGuilds[0].IsMain {
|
||||
t.Fatalf("newcomer must join the main guild, got %+v", newcomerGuilds)
|
||||
}
|
||||
newcomerRoles, err := st.MemberRoles(ctx, newcomerGuilds[0].ID, second.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("MemberRoles(newcomer): %v", err)
|
||||
}
|
||||
if len(newcomerRoles) != 1 || !newcomerRoles[0].IsDefault {
|
||||
t.Fatalf("newcomer must receive the default role, got %+v", newcomerRoles)
|
||||
if len(newcomerGuilds) != 0 {
|
||||
t.Fatalf("newcomer must start without guilds, got %+v", newcomerGuilds)
|
||||
}
|
||||
if user.ID == 0 || token == "" || session.ID == 0 {
|
||||
t.Fatal("registration must return user, token and session")
|
||||
|
||||
Reference in New Issue
Block a user