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:
@@ -90,6 +90,12 @@ type ReadyChannel struct {
|
||||
Slowmode int `json:"slowmode_seconds,omitempty"`
|
||||
CanSend bool `json:"can_send"`
|
||||
CanConnect bool `json:"can_connect"`
|
||||
// Поля личных бесед (type = dm): собеседник и последнее сообщение.
|
||||
RecipientID string `json:"recipient_id,omitempty"`
|
||||
IconFileID string `json:"icon_file_id,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
LastMessageID string `json:"last_message_id,omitempty"`
|
||||
LastMessageAt string `json:"last_message_at,omitempty"`
|
||||
}
|
||||
|
||||
type ReadyRole struct {
|
||||
@@ -290,10 +296,17 @@ func (s *Service) dispatchToChannel(ctx context.Context, channelID, exceptUserID
|
||||
}
|
||||
}
|
||||
|
||||
// canViewChannel проверяет видимость комнаты для сессии. Без калькулятора
|
||||
// прав событие доставляется всем: так работают тесты и режим без БД.
|
||||
// canViewChannel проверяет видимость комнаты для сессии. Для личных бесед
|
||||
// (без сервера) событие получают только участники (AGENT.md 7.8, 9.7).
|
||||
func (s *Service) canViewChannel(ctx context.Context, guildID, channelID uint64, session *clientSession) bool {
|
||||
if s.visibility == nil || guildID == 0 {
|
||||
if guildID == 0 {
|
||||
participant, err := s.store.IsDMParticipant(ctx, channelID, session.userID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return participant
|
||||
}
|
||||
if s.visibility == nil {
|
||||
return true
|
||||
}
|
||||
instanceAdmin := session.user != nil && session.user.IsInstanceAdmin
|
||||
|
||||
Reference in New Issue
Block a user