mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
db: rejoining a channel starts read state caught up
A rejoin reset only removed_at, so the unread position fell back to the first joined_at and counted messages from while the member was away. Reset joined_at on reactivation at every membership upsert; an active member's upsert (a role change) keeps it. Signed-off-by: hMurderbot <219c58afff8ac2c76e4e527a329aa61c2ebbb896786b1916d4f9cca5140ecd04@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -150,6 +150,9 @@ pub async fn create_channel(
|
||||
INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by)
|
||||
VALUES ($1, $2, $3, 'owner', $4)
|
||||
ON CONFLICT (community_id, channel_id, pubkey) DO UPDATE SET
|
||||
-- A rejoin starts caught up: unread counts from here.
|
||||
joined_at = CASE WHEN channel_members.removed_at IS NULL
|
||||
THEN channel_members.joined_at ELSE now() END,
|
||||
removed_at = NULL,
|
||||
removed_by = NULL,
|
||||
role = EXCLUDED.role
|
||||
@@ -249,6 +252,9 @@ pub async fn create_channel_with_id(
|
||||
INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by)
|
||||
VALUES ($1, $2, $3, 'owner', $4)
|
||||
ON CONFLICT (community_id, channel_id, pubkey) DO UPDATE SET
|
||||
-- A rejoin starts caught up: unread counts from here.
|
||||
joined_at = CASE WHEN channel_members.removed_at IS NULL
|
||||
THEN channel_members.joined_at ELSE now() END,
|
||||
removed_at = NULL,
|
||||
removed_by = NULL,
|
||||
role = EXCLUDED.role
|
||||
|
||||
@@ -257,6 +257,9 @@ pub async fn insert_auto_membership_in_transaction(
|
||||
INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by)
|
||||
VALUES ($1, $2, $3, 'member'::member_role, $4)
|
||||
ON CONFLICT (community_id, channel_id, pubkey) DO UPDATE SET
|
||||
-- A rejoin starts caught up: unread counts from here.
|
||||
joined_at = CASE WHEN channel_members.removed_at IS NULL
|
||||
THEN channel_members.joined_at ELSE now() END,
|
||||
removed_at = NULL,
|
||||
removed_by = NULL,
|
||||
role = EXCLUDED.role
|
||||
@@ -601,6 +604,9 @@ pub async fn add_member(
|
||||
INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by)
|
||||
VALUES ($1, $2, $3, $4::member_role, $5)
|
||||
ON CONFLICT (community_id, channel_id, pubkey) DO UPDATE SET
|
||||
-- A rejoin starts caught up: unread counts from here.
|
||||
joined_at = CASE WHEN channel_members.removed_at IS NULL
|
||||
THEN channel_members.joined_at ELSE now() END,
|
||||
removed_at = NULL,
|
||||
removed_by = NULL,
|
||||
role = EXCLUDED.role
|
||||
|
||||
@@ -187,6 +187,9 @@ pub async fn create_dm(
|
||||
INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by)
|
||||
VALUES ($1, $2, $3, 'member', $4)
|
||||
ON CONFLICT (community_id, channel_id, pubkey) DO UPDATE SET
|
||||
-- A rejoin starts caught up: unread counts from here.
|
||||
joined_at = CASE WHEN channel_members.removed_at IS NULL
|
||||
THEN channel_members.joined_at ELSE now() END,
|
||||
removed_at = NULL,
|
||||
removed_by = NULL,
|
||||
role = EXCLUDED.role
|
||||
|
||||
@@ -315,6 +315,55 @@ async fn joining_starts_caught_up_and_counts_only_what_arrives_after() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "requires Postgres"]
|
||||
async fn rejoining_starts_caught_up_again() {
|
||||
let (db, pool, community, channel, owner, _) = fixture().await;
|
||||
let member = Keys::generate();
|
||||
let pk = member.public_key().to_bytes();
|
||||
start(&pool, community, &member).await;
|
||||
db.add_member(community, channel, &pk, MemberRole::Member, None)
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query(
|
||||
"UPDATE channel_members SET joined_at=now()-interval '1 hour'
|
||||
WHERE community_id=$1 AND channel_id=$2 AND pubkey=$3",
|
||||
)
|
||||
.bind(community.as_uuid())
|
||||
.bind(channel)
|
||||
.bind(pk.as_slice())
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
db.remove_member(community, channel, &pk, &pk)
|
||||
.await
|
||||
.unwrap();
|
||||
let away = post(&db, community, channel, &Keys::generate(), now(), vec![]).await;
|
||||
// Re-adding an active member (a role change) must not move the position.
|
||||
let owner_pk = owner.public_key().to_bytes();
|
||||
db.add_member(
|
||||
community,
|
||||
channel,
|
||||
&owner_pk,
|
||||
MemberRole::Owner,
|
||||
Some(&owner_pk),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(sidebar(&db, community, &owner).await.unread, 2);
|
||||
db.add_member(community, channel, &pk, MemberRole::Member, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let row = sidebar(&db, community, &member).await;
|
||||
assert_eq!(row.unread, 0, "messages from while away are read");
|
||||
assert_eq!(
|
||||
status(&db, community, &member, channel, None, &[&away]).await,
|
||||
["read"]
|
||||
);
|
||||
post(&db, community, channel, &Keys::generate(), now(), vec![]).await;
|
||||
assert_eq!(sidebar(&db, community, &member).await.unread, 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "requires Postgres"]
|
||||
async fn read_state_starts_caught_up_at_the_first_intent() {
|
||||
|
||||
Reference in New Issue
Block a user