fix: harden group lifecycle and registration writes

This commit is contained in:
richjohnrambo
2026-09-14 12:04:10 +08:00
parent 990526647c
commit 4854e090ef
9 changed files with 182 additions and 28 deletions
+52 -9
View File
@@ -171,6 +171,11 @@ func (a *adapter) TenantGroupSettingsUpdate(id t.TenantID, topic string, patch t
}
return nil, t.ErrNotFound
}
if patch.MuteAll != nil {
if err = syncGroupMuteAllTx(tx, topic, *patch.MuteAll, time.Now().UTC().Round(time.Millisecond)); err != nil {
return nil, err
}
}
if err = tx.Commit(); err != nil {
return nil, err
}
@@ -199,7 +204,7 @@ func (a *adapter) TenantGroupDissolve(id t.TenantID, topic string, actor t.Uid,
}
defer tx.Rollback()
res, err := tx.ExecContext(ctx, `UPDATE im_group_settings
SET group_status='dissolved',dissolved_by=?,dissolved_at=?,version=version+1,updated_at=?
SET group_status='dissolved',dissolved_by=?,dissolved_at=?,member_count=0,version=version+1,updated_at=?
WHERE topic=? AND group_status<>'dissolved'`, decodeUID(actor), now, now, strings.TrimSpace(topic))
if err != nil {
return nil, err
@@ -207,6 +212,21 @@ func (a *adapter) TenantGroupDissolve(id t.TenantID, topic string, actor t.Uid,
if affected, _ := res.RowsAffected(); affected == 0 {
return nil, t.ErrNotFound
}
if _, err = tx.ExecContext(ctx, `UPDATE im_subscriptions
SET updatedat=?,deletedat=?
WHERE topic IN (?,?) AND deletedat IS NULL`, now, now, strings.TrimSpace(topic), t.GrpToChn(strings.TrimSpace(topic))); err != nil {
return nil, err
}
if _, err = tx.ExecContext(ctx, `UPDATE im_group_members
SET member_status=?,left_at=?,removed_by=?,version=version+1,updated_at=?
WHERE topic=? AND member_status=?`, t.GroupMemberStatusLeft, now, decodeUID(actor), now, strings.TrimSpace(topic), t.GroupMemberStatusActive); err != nil {
return nil, err
}
if _, err = tx.ExecContext(ctx, `UPDATE im_topics
SET updatedat=?,touchedat=?,state=?,stateat=?,subcnt=0
WHERE name=?`, now, now, t.StateDeleted, now, strings.TrimSpace(topic)); err != nil {
return nil, err
}
if err = tx.Commit(); err != nil {
return nil, err
}
@@ -573,7 +593,7 @@ func (a *adapter) TenantGroupInvitationAccept(id t.TenantID, invitationID string
if err = upsertGroupMemberTx(tx, member); err != nil {
return nil, err
}
if err = recountGroupMembersTx(tx, inv.Topic); err != nil {
if err = recountGroupMembersAndBumpVersionTx(tx, inv.Topic); err != nil {
return nil, err
}
if err = updateGroupTopicSubCountTx(tx, inv.Topic); err != nil {
@@ -757,11 +777,13 @@ func (a *adapter) TenantGroupJoinRequestResolve(id t.TenantID, topic, requestID
WHERE topic=? AND request_id=? AND status=?`, status, rejectReason, decodeUID(actor), now, now, topic, requestID, t.GroupJoinRequestStatusPending); err != nil {
return nil, err
}
if err = recountGroupMembersTx(tx, topic); err != nil {
return nil, err
}
if err = updateGroupTopicSubCountTx(tx, topic); err != nil {
return nil, err
if action == "accept" {
if err = recountGroupMembersAndBumpVersionTx(tx, topic); err != nil {
return nil, err
}
if err = updateGroupTopicSubCountTx(tx, topic); err != nil {
return nil, err
}
}
if err = tx.Commit(); err != nil {
return nil, err
@@ -1284,7 +1306,7 @@ func (a *adapter) TenantGroupInviteMember(id t.TenantID, topic string, inviter,
if err = upsertGroupMemberTx(tx, member); err != nil {
return false, err
}
if err = recountGroupMembersTx(tx, topic); err != nil {
if err = recountGroupMembersAndBumpVersionTx(tx, topic); err != nil {
return false, err
}
if err = updateGroupTopicSubCountTx(tx, topic); err != nil {
@@ -1322,7 +1344,7 @@ func (a *adapter) TenantGroupLeave(id t.TenantID, topic string, uid t.Uid, now t
WHERE topic=? AND user_id=? AND member_status=?`, t.GroupMemberStatusLeft, now, now, topic, decodeUID(uid), t.GroupMemberStatusActive); err != nil {
return err
}
if err = recountGroupMembersTx(tx, topic); err != nil {
if err = recountGroupMembersAndBumpVersionTx(tx, topic); err != nil {
return err
}
if err = updateGroupTopicSubCountTx(tx, topic); err != nil {
@@ -1485,12 +1507,33 @@ func recountGroupMembersTx(tx *sqlx.Tx, topic string) error {
return err
}
func recountGroupMembersAndBumpVersionTx(tx *sqlx.Tx, topic string) error {
_, err := tx.Exec(`UPDATE im_group_settings SET member_count=(SELECT COUNT(*) FROM im_group_members
WHERE topic=? AND member_status=?),version=version+1,updated_at=CURRENT_TIMESTAMP(3) WHERE topic=?`, topic, t.GroupMemberStatusActive, topic)
return err
}
func updateGroupTopicSubCountTx(tx *sqlx.Tx, topic string) error {
_, err := tx.Exec(`UPDATE im_topics SET subcnt=(SELECT COUNT(*) FROM im_subscriptions
WHERE topic IN (?,?) AND deletedat IS NULL) WHERE name=?`, topic, t.GrpToChn(topic), topic)
return err
}
func syncGroupMuteAllTx(tx *sqlx.Tx, topic string, muteAll bool, now time.Time) error {
mode := t.ModeCPublic
if muteAll {
mode = t.ModeCPublic &^ t.ModeWrite
}
_, err := tx.Exec(`UPDATE im_subscriptions AS s
JOIN im_group_members AS gm ON gm.topic=s.topic AND gm.user_id=s.userid
SET s.modewant=?,s.modegiven=?,s.updatedat=?,
gm.version=gm.version+1,gm.updated_at=?
WHERE s.topic=? AND s.deletedat IS NULL
AND gm.member_status=? AND gm.role=?`,
mode.String(), mode.String(), now, now, topic, t.GroupMemberStatusActive, t.GroupMemberRoleMember)
return err
}
func (a *adapter) routeGroupTenant(id t.TenantID) (*adapter, error) {
if !a.tenantScopedDB {
tenantAdp, err := a.routedTenantAdapter(id)