feat(social): add listening activity, shared rooms and modern chat
ci / api / api (push) Canceled after 0s
ci / module boundaries / boundaries (push) Canceled after 0s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Canceled after 11m29s
ci / db / db (push) Canceled after 11m22s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 6m43s
ci / recommender / recommender (push) Canceled after 6m47s
ci / ts / ts (packages + web) (push) Canceled after 1s
ci / api / api (push) Canceled after 0s
ci / module boundaries / boundaries (push) Canceled after 0s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Canceled after 11m29s
ci / db / db (push) Canceled after 11m22s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 6m43s
ci / recommender / recommender (push) Canceled after 6m47s
ci / ts / ts (packages + web) (push) Canceled after 1s
This commit is contained in:
1 parent
0a05bfe2cd
commit
11a16cd023
59 files changed
+5022
-542
No files matched your search
@@ -73,7 +73,11 @@ func (s *Store) people(ctx context.Context, id uuid.UUID, q string) ([]gen.Socia
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return scanPeople(rows)
|
||||
people, e := scanPeople(rows)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return people, s.attachActivity(ctx, id, people)
|
||||
}
|
||||
func (s *Store) inbox(ctx context.Context, id uuid.UUID) (gen.SocialInbox, error) {
|
||||
out := gen.SocialInbox{People: []gen.SocialPerson{}, Notifications: []gen.SocialNotification{}}
|
||||
@@ -85,6 +89,12 @@ func (s *Store) inbox(ctx context.Context, id uuid.UUID) (gen.SocialInbox, error
|
||||
if e != nil {
|
||||
return out, e
|
||||
}
|
||||
if e = s.attachActivity(ctx, id, out.People); e != nil {
|
||||
return out, e
|
||||
}
|
||||
if e = s.pool.QueryRow(ctx, `SELECT activity_visibility,friends_recommendations FROM users WHERE id=$1`, id).Scan(&out.ActivityVisibility, &out.FriendsRecommendations); e != nil {
|
||||
return out, e
|
||||
}
|
||||
rows, e = s.pool.Query(ctx, `SELECT n.id,n.actor_id,COALESCE(u.display_name,u.username::text),n.kind,n.created_at,n.read_at IS NOT NULL
|
||||
FROM social_notifications n JOIN users u ON u.id=n.actor_id WHERE n.user_id=$1 AND NOT u.is_blocked
|
||||
AND NOT EXISTS(SELECT 1 FROM social_blocks b WHERE (b.user_id=$1 AND b.peer_id=n.actor_id) OR (b.peer_id=$1 AND b.user_id=n.actor_id))
|
||||
@@ -215,14 +225,19 @@ func (s *Store) action(ctx context.Context, id uuid.UUID, a gen.SocialAction) er
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
|
||||
const messageColumns = `id,seq,sender_id,text,attachment_kind,attachment_id,created_at,read_at IS NOT NULL`
|
||||
const messageColumns = `id,seq,sender_id,CASE WHEN deleted_at IS NULL THEN text ELSE '' END,attachment_kind,attachment_id,created_at,read_at IS NOT NULL,reply_to,edited_at,deleted_at IS NOT NULL`
|
||||
|
||||
func scanMessage(row pgx.Row) (gen.DirectMessage, error) {
|
||||
var m gen.DirectMessage
|
||||
e := row.Scan(&m.Id, &m.Seq, &m.SenderId, &m.Text, &m.AttachmentKind, &m.AttachmentId, &m.CreatedAt, &m.Read)
|
||||
var deleted bool
|
||||
e := row.Scan(&m.Id, &m.Seq, &m.SenderId, &m.Text, &m.AttachmentKind, &m.AttachmentId, &m.CreatedAt, &m.Read, &m.ReplyTo, &m.EditedAt, &deleted)
|
||||
m.Deleted = &deleted
|
||||
return m, e
|
||||
}
|
||||
func (s *Store) messages(ctx context.Context, id, peer uuid.UUID, before *int64) ([]gen.DirectMessage, error) {
|
||||
return s.messagePage(ctx, id, peer, before, "")
|
||||
}
|
||||
func (s *Store) messagePage(ctx context.Context, id, peer uuid.UUID, before *int64, q string) ([]gen.DirectMessage, error) {
|
||||
tx, e := pairTx(ctx, s.pool, id, peer)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
@@ -231,7 +246,7 @@ func (s *Store) messages(ctx context.Context, id, peer uuid.UUID, before *int64)
|
||||
if e = allowed(ctx, tx, id, peer); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
rows, e := tx.Query(ctx, `SELECT `+messageColumns+` FROM direct_messages WHERE LEAST(sender_id,recipient_id)=LEAST($1::uuid,$2::uuid) AND GREATEST(sender_id,recipient_id)=GREATEST($1::uuid,$2::uuid) AND ($3::bigint IS NULL OR seq<$3) ORDER BY seq DESC LIMIT 50`, id, peer, before)
|
||||
rows, e := tx.Query(ctx, `SELECT `+messageColumns+` FROM direct_messages WHERE LEAST(sender_id,recipient_id)=LEAST($1::uuid,$2::uuid) AND GREATEST(sender_id,recipient_id)=GREATEST($1::uuid,$2::uuid) AND ($3::bigint IS NULL OR seq<$3) AND ($4='' OR (deleted_at IS NULL AND strpos(lower(text),lower($4))>0)) ORDER BY seq DESC LIMIT 50`, id, peer, before, q)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
@@ -250,7 +265,8 @@ func (s *Store) messages(ctx context.Context, id, peer uuid.UUID, before *int64)
|
||||
for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
|
||||
out[i], out[j] = out[j], out[i]
|
||||
}
|
||||
return out, nil
|
||||
rows.Close()
|
||||
return out, enrichMessages(ctx, tx, id, out)
|
||||
}
|
||||
func (s *Store) send(ctx context.Context, id, peer uuid.UUID, in gen.SendDirectMessage) (gen.DirectMessage, error) {
|
||||
var zero gen.DirectMessage
|
||||
@@ -274,10 +290,13 @@ func (s *Store) send(ctx context.Context, id, peer uuid.UUID, in gen.SendDirectM
|
||||
if e != nil {
|
||||
return zero, e
|
||||
}
|
||||
if m.SenderId != id || recipient != peer || m.Text != strings.TrimSpace(in.Text) || string(m.AttachmentKind) != string(in.AttachmentKind) || !sameAttachment {
|
||||
sameReply := (m.ReplyTo == nil && in.ReplyTo == nil) || (m.ReplyTo != nil && in.ReplyTo != nil && *m.ReplyTo == *in.ReplyTo)
|
||||
if m.SenderId != id || recipient != peer || m.Text != strings.TrimSpace(in.Text) || string(m.AttachmentKind) != string(in.AttachmentKind) || !sameAttachment || !sameReply {
|
||||
return zero, apperr.Conflict("social.message_conflict", "message ID already used")
|
||||
}
|
||||
return m, nil
|
||||
out := []gen.DirectMessage{m}
|
||||
e = enrichMessages(ctx, tx, id, out)
|
||||
return out[0], e
|
||||
}
|
||||
if !errors.Is(e, pgx.ErrNoRows) {
|
||||
return zero, e
|
||||
@@ -303,7 +322,17 @@ func (s *Store) send(ctx context.Context, id, peer uuid.UUID, in gen.SendDirectM
|
||||
return zero, apperr.NotFound("social.attachment_unavailable", "music is unavailable")
|
||||
}
|
||||
}
|
||||
m, e = scanMessage(tx.QueryRow(ctx, `INSERT INTO direct_messages(id,sender_id,recipient_id,text,attachment_kind,attachment_id) VALUES($1,$2,$3,$4,$5,$6) RETURNING `+messageColumns, in.Id, id, peer, strings.TrimSpace(in.Text), in.AttachmentKind, in.AttachmentId))
|
||||
if in.ReplyTo != nil {
|
||||
var valid bool
|
||||
e = tx.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM direct_messages WHERE id=$1 AND LEAST(sender_id,recipient_id)=LEAST($2::uuid,$3::uuid) AND GREATEST(sender_id,recipient_id)=GREATEST($2::uuid,$3::uuid) AND deleted_at IS NULL)`, in.ReplyTo, id, peer).Scan(&valid)
|
||||
if e != nil {
|
||||
return zero, e
|
||||
}
|
||||
if !valid {
|
||||
return zero, apperr.Conflict("social.message_conflict", "reply unavailable")
|
||||
}
|
||||
}
|
||||
m, e = scanMessage(tx.QueryRow(ctx, `INSERT INTO direct_messages(id,sender_id,recipient_id,text,attachment_kind,attachment_id,reply_to) VALUES($1,$2,$3,$4,$5,$6,$7) RETURNING `+messageColumns, in.Id, id, peer, strings.TrimSpace(in.Text), in.AttachmentKind, in.AttachmentId, in.ReplyTo))
|
||||
if e != nil {
|
||||
return zero, e
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user