fix tenant scoping for group business tables

This commit is contained in:
richjohnrambo
2026-09-23 10:10:08 +08:00
parent 35a70ce9ff
commit 7f0903cd31
6 changed files with 119 additions and 114 deletions
+35 -35
View File
@@ -19,9 +19,9 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
version INT NOT NULL DEFAULT 1, created_by BIGINT NOT NULL, dissolved_by BIGINT,
dissolved_at DATETIME(3), created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_settings_topic(topic),
INDEX idx_im_group_settings_owner(owner_user_id, group_status),
INDEX idx_im_group_settings_status_updated(group_status, updated_at)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_settings_topic(tenant_id, topic),
INDEX idx_im_group_settings_owner(tenant_id, owner_user_id, group_status),
INDEX idx_im_group_settings_status_updated(tenant_id, group_status, updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_messages (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, topic VARCHAR(64) NOT NULL, group_id BIGINT NOT NULL,
@@ -53,10 +53,10 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
removed_by BIGINT, version INT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_members_topic_user(topic, user_id),
INDEX idx_im_group_members_user_status(user_id, member_status, updated_at),
INDEX idx_im_group_members_topic_role(topic, role, member_status, id),
INDEX idx_im_group_members_topic_status(topic, member_status, id)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_members_topic_user(tenant_id, topic, user_id),
INDEX idx_im_group_members_user_status(tenant_id, user_id, member_status, updated_at),
INDEX idx_im_group_members_topic_role(tenant_id, topic, role, member_status, id),
INDEX idx_im_group_members_topic_status(tenant_id, topic, member_status, id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_invitations (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, invitation_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
@@ -66,10 +66,10 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
expires_at DATETIME(3) NOT NULL, handled_at DATETIME(3),
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_invitations_invitation(invitation_id),
UNIQUE INDEX uk_im_group_invitations_idempotency(inviter_user_id, idempotency_key),
INDEX idx_im_group_invitations_target(target_user_id, status, expires_at),
INDEX idx_im_group_invitations_topic_status(topic, status, id)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_invitations_invitation(tenant_id, invitation_id),
UNIQUE INDEX uk_im_group_invitations_idempotency(tenant_id, inviter_user_id, idempotency_key),
INDEX idx_im_group_invitations_target(tenant_id, target_user_id, status, expires_at),
INDEX idx_im_group_invitations_topic_status(tenant_id, topic, status, id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_join_requests (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, request_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
@@ -80,11 +80,11 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
idempotency_key VARCHAR(128) NOT NULL DEFAULT '', version INT NOT NULL DEFAULT 1,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_join_requests_request(request_id),
UNIQUE INDEX uk_im_group_join_requests_idempotency(applicant_user_id, idempotency_key),
INDEX idx_im_group_join_requests_topic_status(topic, status, id),
INDEX idx_im_group_join_requests_applicant(applicant_user_id, topic, status, id),
INDEX idx_im_group_join_requests_expire(status, expires_at)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_join_requests_request(tenant_id, request_id),
UNIQUE INDEX uk_im_group_join_requests_idempotency(tenant_id, applicant_user_id, idempotency_key),
INDEX idx_im_group_join_requests_topic_status(tenant_id, topic, status, id),
INDEX idx_im_group_join_requests_applicant(tenant_id, applicant_user_id, topic, status, id),
INDEX idx_im_group_join_requests_expire(tenant_id, status, expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_announcements (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, announcement_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
@@ -93,17 +93,17 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
idempotency_key VARCHAR(128) NOT NULL DEFAULT '',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_announcements_announcement(announcement_id),
UNIQUE INDEX uk_im_group_announcements_idempotency(topic, author_user_id, idempotency_key),
INDEX idx_im_group_announcements_topic_status(topic, status, version DESC, id DESC),
INDEX idx_im_group_announcements_topic_time(topic, published_at DESC, id DESC)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_announcements_announcement(tenant_id, announcement_id),
UNIQUE INDEX uk_im_group_announcements_idempotency(tenant_id, topic, author_user_id, idempotency_key),
INDEX idx_im_group_announcements_topic_status(tenant_id, topic, status, version DESC, id DESC),
INDEX idx_im_group_announcements_topic_time(tenant_id, topic, published_at DESC, id DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_announcement_reads (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL, announcement_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL, user_id BIGINT NOT NULL,
read_at DATETIME(3) NOT NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_announcement_reads_announcement_user(announcement_id, user_id),
INDEX idx_im_group_announcement_reads_topic_user(topic, user_id, read_at)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_announcement_reads_announcement_user(tenant_id, announcement_id, user_id),
INDEX idx_im_group_announcement_reads_topic_user(tenant_id, topic, user_id, read_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_mutes (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL, topic VARCHAR(32) NOT NULL, user_id BIGINT NOT NULL, muted_by BIGINT NOT NULL,
@@ -111,9 +111,9 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
status VARCHAR(16) NOT NULL DEFAULT 'active', revoked_by BIGINT, revoked_at DATETIME(3),
version INT NOT NULL DEFAULT 1, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_mutes_topic_user(topic, user_id),
INDEX idx_im_group_mutes_topic_status(topic, status, expires_at),
INDEX idx_im_group_mutes_user_status(user_id, status, expires_at)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_mutes_topic_user(tenant_id, topic, user_id),
INDEX idx_im_group_mutes_topic_status(tenant_id, topic, status, expires_at),
INDEX idx_im_group_mutes_user_status(tenant_id, user_id, status, expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_qrcodes (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, token_id VARCHAR(64) NOT NULL, token_hash CHAR(64) NOT NULL,
@@ -121,8 +121,8 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
expires_at DATETIME(3) NOT NULL, revoked_by BIGINT, revoked_at DATETIME(3),
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_qrcodes_token(token_id),
UNIQUE INDEX uk_im_group_qrcodes_hash(token_hash), INDEX idx_im_group_qrcodes_topic_status(topic, status, expires_at)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_qrcodes_token(tenant_id, token_id),
UNIQUE INDEX uk_im_group_qrcodes_hash(tenant_id, token_hash), INDEX idx_im_group_qrcodes_topic_status(tenant_id, topic, status, expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_files (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, group_file_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
@@ -133,11 +133,11 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
idempotency_key VARCHAR(128) NOT NULL DEFAULT '',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_files_group_file(group_file_id),
UNIQUE INDEX uk_im_group_files_topic_file(topic, file_id),
UNIQUE INDEX uk_im_group_files_idempotency(topic, uploader_id, idempotency_key),
INDEX idx_im_group_files_topic_type(topic, status, file_type, id DESC),
INDEX idx_im_group_files_topic_name(topic, status, file_name), INDEX idx_im_group_files_uploader(uploader_id, id DESC)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_files_group_file(tenant_id, group_file_id),
UNIQUE INDEX uk_im_group_files_topic_file(tenant_id, topic, file_id),
UNIQUE INDEX uk_im_group_files_idempotency(tenant_id, topic, uploader_id, idempotency_key),
INDEX idx_im_group_files_topic_type(tenant_id, topic, status, file_type, id DESC),
INDEX idx_im_group_files_topic_name(tenant_id, topic, status, file_name), INDEX idx_im_group_files_uploader(tenant_id, uploader_id, id DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`CREATE TABLE IF NOT EXISTS im_group_admin_logs (
tenant_id BIGINT NOT NULL DEFAULT 0, id BIGINT NOT NULL AUTO_INCREMENT, log_id VARCHAR(64) NOT NULL, topic VARCHAR(32) NOT NULL,
@@ -145,9 +145,9 @@ func ensureIMGroupBusinessTables(exec sqlExecutor) error {
object_type VARCHAR(32) NOT NULL DEFAULT '', object_id VARCHAR(64) NOT NULL DEFAULT '',
before_data JSON, after_data JSON, request_id VARCHAR(128) NOT NULL DEFAULT '',
idempotency_key VARCHAR(128) NOT NULL DEFAULT '', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_admin_logs_log(log_id),
INDEX idx_im_group_admin_logs_topic_time(topic, id DESC),
INDEX idx_im_group_admin_logs_operator(operator_id, id DESC), INDEX idx_im_group_admin_logs_object(object_type, object_id)
PRIMARY KEY(id), UNIQUE INDEX uk_im_group_admin_logs_log(tenant_id, log_id),
INDEX idx_im_group_admin_logs_topic_time(tenant_id, topic, id DESC),
INDEX idx_im_group_admin_logs_operator(tenant_id, operator_id, id DESC), INDEX idx_im_group_admin_logs_object(tenant_id, object_type, object_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci`,
`UPDATE im_topics SET public=JSON_SET(public, '$.fn', JSON_UNQUOTE(JSON_EXTRACT(public, '$.name')))
WHERE name LIKE 'grp%' AND JSON_VALID(public)
+3 -3
View File
@@ -40,9 +40,9 @@ func TestEnsureIMGroupBusinessTablesUsesSelectedTenantDatabase(t *testing.T) {
t.Fatal("group idempotency table must not be created")
}
for _, expected := range []string{
"primary key(id), unique index uk_im_group_settings_topic(topic)",
"primary key(id), unique index uk_im_group_announcement_reads_announcement_user(announcement_id, user_id)",
"primary key(id), unique index uk_im_group_mutes_topic_user(topic, user_id)",
"primary key(id), unique index uk_im_group_settings_topic(tenant_id, topic)",
"primary key(id), unique index uk_im_group_announcement_reads_announcement_user(tenant_id, announcement_id, user_id)",
"primary key(id), unique index uk_im_group_mutes_topic_user(tenant_id, topic, user_id)",
} {
if !strings.Contains(joined, expected) {
t.Fatalf("group schema is missing snowflake primary-key definition %q", expected)
+3 -3
View File
@@ -29,9 +29,9 @@ var snowflakePrimaryKeySpecs = []snowflakePrimaryKeySpec{
{table: "im_friendships", uniqueIndex: "uk_im_friendships_pair", businessKey: []string{"user_id", "peer_id"}},
{table: "im_user_blocks", uniqueIndex: "uk_im_user_blocks_pair", businessKey: []string{"blocker_id", "blocked_id"}},
{table: "im_youth_mode_settings", uniqueIndex: "uk_im_youth_mode_settings_user_purpose", businessKey: []string{"user_id", "purpose"}},
{table: "im_group_settings", uniqueIndex: "uk_im_group_settings_topic", businessKey: []string{"topic"}},
{table: "im_group_announcement_reads", uniqueIndex: "uk_im_group_announcement_reads_announcement_user", businessKey: []string{"announcement_id", "user_id"}},
{table: "im_group_mutes", uniqueIndex: "uk_im_group_mutes_topic_user", businessKey: []string{"topic", "user_id"}},
{table: "im_group_settings", uniqueIndex: "uk_im_group_settings_topic", businessKey: []string{"tenant_id", "topic"}},
{table: "im_group_announcement_reads", uniqueIndex: "uk_im_group_announcement_reads_announcement_user", businessKey: []string{"tenant_id", "announcement_id", "user_id"}},
{table: "im_group_mutes", uniqueIndex: "uk_im_group_mutes_topic_user", businessKey: []string{"tenant_id", "topic", "user_id"}},
}
const snowflakeMigrationLock = "CONCAT('im_snowflake_pk:', LEFT(SHA2(DATABASE(), 256), 40))"
+1 -1
View File
@@ -5270,7 +5270,7 @@ func (a *adapter) TenantFileUserHasAccess(id t.TenantID, fid string, uid t.Uid)
SELECT 1 FROM im_group_files AS gf
INNER JOIN im_subscriptions AS s
ON s.tenant_id=fu.tenant_id AND s.topic=gf.topic AND s.userid=?
WHERE (gf.file_id=? OR gf.file_id LIKE CONCAT(?,'.%%')) AND gf.status='active'
WHERE gf.tenant_id=fu.tenant_id AND (gf.file_id=? OR gf.file_id LIKE CONCAT(?,'.%%')) AND gf.status='active'
AND s.deletedat IS NULL AND INSTR(s.modewant,'R')>0 AND INSTR(s.modegiven,'R')>0
)
) LIMIT 1`, tenantFriendshipsTable(id), tenantMessagesTable(id))),
+72 -72
View File
@@ -20,12 +20,12 @@ const (
groupSettingsSelectColumns = `tenant_id,topic,owner_user_id,name,avatar_file_id,description,group_status,join_approval,mute_all,
member_upload_files,member_private_chat,member_invite,max_member_count,max_admin_count,member_count,version,
created_by,dissolved_by,dissolved_at,created_at,updated_at`
groupAnnouncementSelectColumnsBase = `id,announcement_id,topic,author_user_id,content,status,version,published_at,idempotency_key,created_at,updated_at,
(SELECT COUNT(*) FROM im_group_announcement_reads AS ar WHERE ar.topic=im_group_announcements.topic AND ar.announcement_id=im_group_announcements.announcement_id) AS read_count,
(SELECT COUNT(*) FROM im_group_members AS gm WHERE gm.topic=im_group_announcements.topic AND gm.member_status='active') AS member_count`
groupAnnouncementSelectColumnsBase = `tenant_id,id,announcement_id,topic,author_user_id,content,status,version,published_at,idempotency_key,created_at,updated_at,
(SELECT COUNT(*) FROM im_group_announcement_reads AS ar WHERE ar.tenant_id=im_group_announcements.tenant_id AND ar.topic=im_group_announcements.topic AND ar.announcement_id=im_group_announcements.announcement_id) AS read_count,
(SELECT COUNT(*) FROM im_group_members AS gm WHERE gm.tenant_id=im_group_announcements.tenant_id AND gm.topic=im_group_announcements.topic AND gm.member_status='active') AS member_count`
groupMemberSelectColumns = `id,topic,user_id,role,member_status,nickname,pinned,mute_notifications,
join_source,joined_by,joined_at,left_at,removed_by,version,created_at,updated_at`
groupMuteSelectColumns = `topic,user_id,muted_by,muted_at,expires_at,reason,status,revoked_by,revoked_at,version,created_at,updated_at`
groupMuteSelectColumns = `tenant_id,topic,user_id,muted_by,muted_at,expires_at,reason,status,revoked_by,revoked_at,version,created_at,updated_at`
)
func groupAnnouncementSelectColumns(tenantID t.TenantID) string {
@@ -488,13 +488,13 @@ func (a *adapter) TenantGroupInvitationCreate(id t.TenantID, inv *t.GroupInvitat
defer cancel()
}
if strings.TrimSpace(inv.JoinRequestID) != "" {
existing, err := a.groupInvitationByQuery(ctx, `SELECT inv.id,inv.invitation_id,inv.topic,inv.inviter_user_id,inv.target_user_id,inv.message,inv.status,inv.result,
existing, err := a.groupInvitationByQuery(ctx, `SELECT inv.tenant_id,inv.id,inv.invitation_id,inv.topic,inv.inviter_user_id,inv.target_user_id,inv.message,inv.status,inv.result,
inv.join_request_id,inv.idempotency_key,inv.expires_at,inv.handled_at,inv.created_at,inv.updated_at
FROM im_group_invitations AS inv
INNER JOIN im_group_join_requests AS req ON req.request_id=inv.join_request_id
WHERE inv.topic=? AND inv.target_user_id=? AND inv.status=? AND req.status=?
INNER JOIN im_group_join_requests AS req ON req.tenant_id=inv.tenant_id AND req.request_id=inv.join_request_id
WHERE inv.tenant_id=? AND inv.topic=? AND inv.target_user_id=? AND inv.status=? AND req.status=?
ORDER BY req.id DESC LIMIT 1`,
inv.Topic, decodeUID(inv.TargetUserID), t.GroupInvitationStatusPending, t.GroupJoinRequestStatusPending)
id, inv.Topic, decodeUID(inv.TargetUserID), t.GroupInvitationStatusPending, t.GroupJoinRequestStatusPending)
if err == nil {
return existing, nil
}
@@ -507,16 +507,16 @@ func (a *adapter) TenantGroupInvitationCreate(id t.TenantID, inv *t.GroupInvitat
return nil, err
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_invitations(invitation_id,topic,inviter_user_id,target_user_id,message,status,result,join_request_id,idempotency_key,expires_at,handled_at,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)`,
inv.InvitationID, inv.Topic, decodeUID(inv.InviterUserID), decodeUID(inv.TargetUserID), inv.Message, inv.Status, inv.Result, inv.JoinRequestID, inv.IdempotencyKey, inv.ExpiresAt, inv.HandledAt, now, now)
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_invitations(tenant_id,invitation_id,topic,inviter_user_id,target_user_id,message,status,result,join_request_id,idempotency_key,expires_at,handled_at,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
id, inv.InvitationID, inv.Topic, decodeUID(inv.InviterUserID), decodeUID(inv.TargetUserID), inv.Message, inv.Status, inv.Result, inv.JoinRequestID, inv.IdempotencyKey, inv.ExpiresAt, inv.HandledAt, now, now)
if err != nil {
return nil, err
}
if strings.TrimSpace(inv.JoinRequestID) != "" {
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_join_requests(request_id,topic,applicant_user_id,inviter_user_id,source,qr_token_hash,message,status,reject_reason,expires_at,idempotency_key,version,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
inv.JoinRequestID, inv.Topic, decodeUID(inv.TargetUserID), nullableUID(inv.InviterUserID), "invitation", "", inv.Message, t.GroupJoinRequestStatusPending, "", inv.ExpiresAt, inv.IdempotencyKey, 1, now, now)
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_join_requests(tenant_id,request_id,topic,applicant_user_id,inviter_user_id,source,qr_token_hash,message,status,reject_reason,expires_at,idempotency_key,version,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
id, inv.JoinRequestID, inv.Topic, decodeUID(inv.TargetUserID), nullableUID(inv.InviterUserID), "invitation", "", inv.Message, t.GroupJoinRequestStatusPending, "", inv.ExpiresAt, inv.IdempotencyKey, 1, now, now)
if err != nil {
return nil, err
}
@@ -548,10 +548,10 @@ func (a *adapter) TenantGroupInvitationAccept(id t.TenantID, invitationID string
var inv t.GroupInvitation
var handledAt sql.NullTime
err = tx.QueryRowxContext(ctx, `SELECT id,invitation_id,topic,inviter_user_id,target_user_id,message,status,result,
err = tx.QueryRowxContext(ctx, `SELECT tenant_id,id,invitation_id,topic,inviter_user_id,target_user_id,message,status,result,
join_request_id,idempotency_key,expires_at,handled_at,created_at,updated_at
FROM im_group_invitations WHERE invitation_id=? FOR UPDATE`, strings.TrimSpace(invitationID)).
Scan(&inv.ID, &inv.InvitationID, &inv.Topic, &inv.InviterUserRaw, &inv.TargetUserRaw, &inv.Message, &inv.Status,
FROM im_group_invitations WHERE tenant_id=? AND invitation_id=? FOR UPDATE`, id, strings.TrimSpace(invitationID)).
Scan(&inv.TenantID, &inv.ID, &inv.InvitationID, &inv.Topic, &inv.InviterUserRaw, &inv.TargetUserRaw, &inv.Message, &inv.Status,
&inv.Result, &inv.JoinRequestID, &inv.IdempotencyKey, &inv.ExpiresAt, &handledAt, &inv.CreatedAt, &inv.UpdatedAt)
if err == sql.ErrNoRows {
return nil, t.ErrNotFound
@@ -606,15 +606,15 @@ func (a *adapter) TenantGroupInvitationAccept(id t.TenantID, invitationID string
return nil, err
}
if _, err = tx.ExecContext(ctx, `UPDATE im_group_invitations
SET status=?,result=?,handled_at=?,updated_at=? WHERE invitation_id=?`,
t.GroupInvitationStatusJoined, "joined", now, now, inv.InvitationID); err != nil {
SET status=?,result=?,handled_at=?,updated_at=? WHERE tenant_id=? AND invitation_id=?`,
t.GroupInvitationStatusJoined, "joined", now, now, id, inv.InvitationID); err != nil {
return nil, err
}
if strings.TrimSpace(inv.JoinRequestID) != "" {
if _, err = tx.ExecContext(ctx, `UPDATE im_group_join_requests
SET status=?,handled_by=?,handled_at=?,updated_at=?,version=version+1
WHERE topic=? AND request_id=? AND status=?`,
t.GroupJoinRequestStatusAccepted, decodeUID(uid), now, now, inv.Topic, inv.JoinRequestID, t.GroupJoinRequestStatusPending); err != nil {
WHERE tenant_id=? AND topic=? AND request_id=? AND status=?`,
t.GroupJoinRequestStatusAccepted, decodeUID(uid), now, now, id, inv.Topic, inv.JoinRequestID, t.GroupJoinRequestStatusPending); err != nil {
return nil, err
}
}
@@ -651,8 +651,8 @@ func (a *adapter) TenantGroupJoinRequestCreate(id t.TenantID, req *t.GroupJoinRe
if cancel != nil {
defer cancel()
}
existing, err := a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE topic=? AND applicant_user_id=? AND status=? ORDER BY id DESC LIMIT 1",
req.Topic, decodeUID(req.ApplicantUserID), t.GroupJoinRequestStatusPending)
existing, err := a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE tenant_id=? AND topic=? AND applicant_user_id=? AND status=? ORDER BY id DESC LIMIT 1",
id, req.Topic, decodeUID(req.ApplicantUserID), t.GroupJoinRequestStatusPending)
if err == nil {
return existing, nil
}
@@ -664,16 +664,16 @@ func (a *adapter) TenantGroupJoinRequestCreate(id t.TenantID, req *t.GroupJoinRe
return nil, err
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_join_requests(request_id,topic,applicant_user_id,inviter_user_id,source,qr_token_hash,message,status,reject_reason,expires_at,idempotency_key,version,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
req.RequestID, req.Topic, decodeUID(req.ApplicantUserID), nullableUID(req.InviterUserID), req.Source, req.QRTokenHash, req.Message, req.Status, req.RejectReason, req.ExpiresAt, req.IdempotencyKey, req.Version, now, now)
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_join_requests(tenant_id,request_id,topic,applicant_user_id,inviter_user_id,source,qr_token_hash,message,status,reject_reason,expires_at,idempotency_key,version,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
id, req.RequestID, req.Topic, decodeUID(req.ApplicantUserID), nullableUID(req.InviterUserID), req.Source, req.QRTokenHash, req.Message, req.Status, req.RejectReason, req.ExpiresAt, req.IdempotencyKey, req.Version, now, now)
if err != nil {
return nil, err
}
if err = tx.Commit(); err != nil {
return nil, err
}
return a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE request_id=?", req.RequestID)
return a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE tenant_id=? AND request_id=?", id, req.RequestID)
}
func (a *adapter) TenantGroupJoinRequestList(id t.TenantID, topic, status, cursor string, limit int) ([]t.GroupJoinRequest, string, error) {
@@ -682,15 +682,15 @@ func (a *adapter) TenantGroupJoinRequestList(id t.TenantID, topic, status, curso
} else if tenantAdp != a {
return tenantAdp.TenantGroupJoinRequestList(id, topic, status, cursor, limit)
}
where := []string{"r.topic=?"}
args := []any{topic}
where := []string{"r.tenant_id=?", "r.topic=?"}
args := []any{id, topic}
if status != "" && status != "all" {
where = append(where, "r.status=?")
args = append(args, status)
if status == t.GroupJoinRequestStatusPending {
where = append(where, `NOT EXISTS (
SELECT 1 FROM im_group_join_requests AS newer
WHERE newer.topic=r.topic AND newer.applicant_user_id=r.applicant_user_id
WHERE newer.tenant_id=r.tenant_id AND newer.topic=r.topic AND newer.applicant_user_id=r.applicant_user_id
AND newer.status=? AND newer.id>r.id
)`)
args = append(args, status)
@@ -751,7 +751,7 @@ func (a *adapter) TenantGroupJoinRequestResolve(id t.TenantID, topic, requestID
}
defer tx.Rollback()
var current t.GroupJoinRequest
err = tx.QueryRowxContext(ctx, "SELECT * FROM im_group_join_requests WHERE topic=? AND request_id=? FOR UPDATE", topic, requestID).StructScan(&current)
err = tx.QueryRowxContext(ctx, "SELECT * FROM im_group_join_requests WHERE tenant_id=? AND topic=? AND request_id=? FOR UPDATE", id, topic, requestID).StructScan(&current)
if err == sql.ErrNoRows {
return nil, t.ErrNotFound
}
@@ -780,7 +780,7 @@ func (a *adapter) TenantGroupJoinRequestResolve(id t.TenantID, topic, requestID
}
}
if _, err = tx.ExecContext(ctx, `UPDATE im_group_join_requests SET status=?,reject_reason=?,handled_by=?,handled_at=?,updated_at=?,version=version+1
WHERE topic=? AND request_id=? AND status=?`, status, rejectReason, decodeUID(actor), now, now, topic, requestID, t.GroupJoinRequestStatusPending); err != nil {
WHERE tenant_id=? AND topic=? AND request_id=? AND status=?`, status, rejectReason, decodeUID(actor), now, now, id, topic, requestID, t.GroupJoinRequestStatusPending); err != nil {
return nil, err
}
if action == "accept" {
@@ -794,7 +794,7 @@ func (a *adapter) TenantGroupJoinRequestResolve(id t.TenantID, topic, requestID
if err = tx.Commit(); err != nil {
return nil, err
}
return a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE topic=? AND request_id=?", topic, requestID)
return a.groupJoinRequestByQuery(ctx, "SELECT * FROM im_group_join_requests WHERE tenant_id=? AND topic=? AND request_id=?", id, topic, requestID)
}
func (a *adapter) TenantGroupAnnouncementLatest(id t.TenantID, topic string) (*t.GroupAnnouncement, error) {
@@ -807,7 +807,7 @@ func (a *adapter) TenantGroupAnnouncementLatest(id t.TenantID, topic string) (*t
if cancel != nil {
defer cancel()
}
return a.groupAnnouncementByQuery(ctx, "SELECT "+groupAnnouncementSelectColumns(id)+" FROM im_group_announcements WHERE topic=? AND status=? ORDER BY version DESC,id DESC LIMIT 1", topic, t.GroupAnnouncementStatusCurrent)
return a.groupAnnouncementByQuery(ctx, "SELECT "+groupAnnouncementSelectColumns(id)+" FROM im_group_announcements WHERE tenant_id=? AND topic=? AND status=? ORDER BY version DESC,id DESC LIMIT 1", id, topic, t.GroupAnnouncementStatusCurrent)
}
func (a *adapter) TenantGroupAnnouncementGet(id t.TenantID, topic, announcementID string) (*t.GroupAnnouncement, error) {
@@ -820,7 +820,7 @@ func (a *adapter) TenantGroupAnnouncementGet(id t.TenantID, topic, announcementI
if cancel != nil {
defer cancel()
}
return a.groupAnnouncementByQuery(ctx, "SELECT "+groupAnnouncementSelectColumns(id)+" FROM im_group_announcements WHERE topic=? AND announcement_id=? LIMIT 1", topic, announcementID)
return a.groupAnnouncementByQuery(ctx, "SELECT "+groupAnnouncementSelectColumns(id)+" FROM im_group_announcements WHERE tenant_id=? AND topic=? AND announcement_id=? LIMIT 1", id, topic, announcementID)
}
func (a *adapter) TenantGroupAnnouncementPut(id t.TenantID, ann *t.GroupAnnouncement, expectedVersion int) (*t.GroupAnnouncement, error) {
@@ -843,7 +843,7 @@ func (a *adapter) TenantGroupAnnouncementPut(id t.TenantID, ann *t.GroupAnnounce
}
}()
var currentVersion int
err = tx.QueryRowContext(ctx, "SELECT COALESCE(MAX(version),0) FROM im_group_announcements WHERE topic=?", ann.Topic).Scan(&currentVersion)
err = tx.QueryRowContext(ctx, "SELECT COALESCE(MAX(version),0) FROM im_group_announcements WHERE tenant_id=? AND topic=?", id, ann.Topic).Scan(&currentVersion)
if err != nil {
return nil, err
}
@@ -855,7 +855,7 @@ func (a *adapter) TenantGroupAnnouncementPut(id t.TenantID, ann *t.GroupAnnounce
if now.IsZero() {
now = time.Now().UTC().Round(time.Millisecond)
}
if _, err = tx.ExecContext(ctx, "UPDATE im_group_announcements SET status=?,updated_at=? WHERE topic=? AND status=?", t.GroupAnnouncementStatusSuperseded, now, ann.Topic, t.GroupAnnouncementStatusCurrent); err != nil {
if _, err = tx.ExecContext(ctx, "UPDATE im_group_announcements SET status=?,updated_at=? WHERE tenant_id=? AND topic=? AND status=?", t.GroupAnnouncementStatusSuperseded, now, id, ann.Topic, t.GroupAnnouncementStatusCurrent); err != nil {
return nil, err
}
if ann.AnnouncementID == "" {
@@ -864,8 +864,8 @@ func (a *adapter) TenantGroupAnnouncementPut(id t.TenantID, ann *t.GroupAnnounce
if ann.IdempotencyKey == "" {
ann.IdempotencyKey = ann.AnnouncementID
}
if _, err = tx.ExecContext(ctx, `INSERT INTO im_group_announcements(announcement_id,topic,author_user_id,content,status,version,published_at,idempotency_key,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?)`, ann.AnnouncementID, ann.Topic, decodeUID(ann.AuthorUserID), ann.Content, t.GroupAnnouncementStatusCurrent, version, now, ann.IdempotencyKey, now, now); err != nil {
if _, err = tx.ExecContext(ctx, `INSERT INTO im_group_announcements(tenant_id,announcement_id,topic,author_user_id,content,status,version,published_at,idempotency_key,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?)`, id, ann.AnnouncementID, ann.Topic, decodeUID(ann.AuthorUserID), ann.Content, t.GroupAnnouncementStatusCurrent, version, now, ann.IdempotencyKey, now, now); err != nil {
return nil, err
}
if err = tx.Commit(); err != nil {
@@ -888,8 +888,8 @@ func (a *adapter) TenantGroupAnnouncementRead(id t.TenantID, topic, announcement
if err != nil {
return err
}
_, err = a.db.ExecContext(ctx, `INSERT INTO im_group_announcement_reads(id,announcement_id,topic,user_id,read_at)
VALUES(?,?,?,?,?) ON DUPLICATE KEY UPDATE read_at=VALUES(read_at),updated_at=CURRENT_TIMESTAMP(3)`, readID, announcementID, topic, decodeUID(uid), readAt)
_, err = a.db.ExecContext(ctx, `INSERT INTO im_group_announcement_reads(id,tenant_id,announcement_id,topic,user_id,read_at)
VALUES(?,?,?,?,?,?) ON DUPLICATE KEY UPDATE read_at=VALUES(read_at),updated_at=CURRENT_TIMESTAMP(3)`, readID, id, announcementID, topic, decodeUID(uid), readAt)
return err
}
@@ -899,8 +899,8 @@ func (a *adapter) TenantGroupMuteList(id t.TenantID, topic, cursor string, limit
} else if tenantAdp != a {
return tenantAdp.TenantGroupMuteList(id, topic, cursor, limit)
}
where := []string{"topic=?", "status=?"}
args := []any{topic, t.GroupMuteStatusActive}
where := []string{"tenant_id=?", "topic=?", "status=?"}
args := []any{id, topic, t.GroupMuteStatusActive}
if cursor != "" {
parsed, err := strconv.ParseInt(cursor, 10, 64)
if err != nil || parsed <= 0 {
@@ -950,8 +950,8 @@ func (a *adapter) TenantGroupMuteGet(id t.TenantID, topic string, uid t.Uid) (*t
if cancel != nil {
defer cancel()
}
return a.groupMuteByQuery(ctx, "SELECT "+groupMuteSelectColumns+" FROM im_group_mutes WHERE topic=? AND user_id=? AND status=? AND (expires_at IS NULL OR expires_at>?)",
topic, decodeUID(uid), t.GroupMuteStatusActive, now)
return a.groupMuteByQuery(ctx, "SELECT "+groupMuteSelectColumns+" FROM im_group_mutes WHERE tenant_id=? AND topic=? AND user_id=? AND status=? AND (expires_at IS NULL OR expires_at>?)",
id, topic, decodeUID(uid), t.GroupMuteStatusActive, now)
}
func (a *adapter) TenantGroupMuteUpsert(id t.TenantID, mute *t.GroupMute) (*t.GroupMute, error) {
@@ -980,17 +980,17 @@ func (a *adapter) TenantGroupMuteUpsert(id t.TenantID, mute *t.GroupMute) (*t.Gr
if err != nil {
return nil, err
}
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_mutes(id,topic,user_id,muted_by,muted_at,expires_at,reason,status,version)
VALUES(?,?,?,?,?,?,?,?,1)
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_mutes(id,tenant_id,topic,user_id,muted_by,muted_at,expires_at,reason,status,version)
VALUES(?,?,?,?,?,?,?,?,?,1)
ON DUPLICATE KEY UPDATE muted_by=VALUES(muted_by),muted_at=VALUES(muted_at),expires_at=VALUES(expires_at),reason=VALUES(reason),status=VALUES(status),revoked_by=NULL,revoked_at=NULL,version=version+1,updated_at=CURRENT_TIMESTAMP(3)`,
muteID, mute.Topic, decodeUID(mute.UserID), decodeUID(mute.MutedBy), now, mute.ExpiresAt, mute.Reason, mute.Status)
muteID, id, mute.Topic, decodeUID(mute.UserID), decodeUID(mute.MutedBy), now, mute.ExpiresAt, mute.Reason, mute.Status)
if err != nil {
return nil, err
}
if err = tx.Commit(); err != nil {
return nil, err
}
return a.groupMuteByQuery(ctx, "SELECT "+groupMuteSelectColumns+" FROM im_group_mutes WHERE topic=? AND user_id=?", mute.Topic, decodeUID(mute.UserID))
return a.groupMuteByQuery(ctx, "SELECT "+groupMuteSelectColumns+" FROM im_group_mutes WHERE tenant_id=? AND topic=? AND user_id=?", id, mute.Topic, decodeUID(mute.UserID))
}
func (a *adapter) TenantGroupMuteDelete(id t.TenantID, topic string, uid, actor t.Uid, now time.Time) error {
@@ -1008,8 +1008,8 @@ func (a *adapter) TenantGroupMuteDelete(id t.TenantID, topic string, uid, actor
return err
}
defer tx.Rollback()
res, err := tx.ExecContext(ctx, "UPDATE im_group_mutes SET status=?,revoked_by=?,revoked_at=?,version=version+1,updated_at=? WHERE topic=? AND user_id=? AND status=?",
t.GroupMuteStatusRevoked, decodeUID(actor), now, now, topic, decodeUID(uid), t.GroupMuteStatusActive)
res, err := tx.ExecContext(ctx, "UPDATE im_group_mutes SET status=?,revoked_by=?,revoked_at=?,version=version+1,updated_at=? WHERE tenant_id=? AND topic=? AND user_id=? AND status=?",
t.GroupMuteStatusRevoked, decodeUID(actor), now, now, id, topic, decodeUID(uid), t.GroupMuteStatusActive)
if err != nil {
return err
}
@@ -1028,8 +1028,8 @@ func (a *adapter) TenantGroupFileList(id t.TenantID, topic, fileType, query, cur
if strings.TrimSpace(topic) == "" {
return nil, "", t.ErrMalformed
}
where := []string{"topic=?", "status='active'"}
args := []any{strings.TrimSpace(topic)}
where := []string{"tenant_id=?", "topic=?", "status='active'"}
args := []any{id, strings.TrimSpace(topic)}
if fileType != "" {
where = append(where, "file_type=?")
args = append(args, strings.TrimSpace(fileType))
@@ -1051,7 +1051,7 @@ func (a *adapter) TenantGroupFileList(id t.TenantID, topic, fileType, query, cur
if cancel != nil {
defer cancel()
}
rows, err := a.db.QueryxContext(ctx, `SELECT id,group_file_id,topic,file_id,source_topic,source_seq,uploader_id,
rows, err := a.db.QueryxContext(ctx, `SELECT tenant_id,id,group_file_id,topic,file_id,source_topic,source_seq,uploader_id,
file_name,mime_type,file_type,file_size,status,deleted_by,deleted_at,idempotency_key,created_at,updated_at
FROM im_group_files WHERE `+strings.Join(where, " AND ")+` ORDER BY id DESC LIMIT ?`, args...)
if err != nil {
@@ -1108,15 +1108,15 @@ func (a *adapter) TenantGroupFileCreate(id t.TenantID, file *t.GroupFile) (*t.Gr
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx, `INSERT INTO im_group_files
(group_file_id,topic,file_id,source_topic,source_seq,uploader_id,file_name,mime_type,file_type,file_size,status,idempotency_key,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
(tenant_id,group_file_id,topic,file_id,source_topic,source_seq,uploader_id,file_name,mime_type,file_type,file_size,status,idempotency_key,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE
file_name=IF(file_name='', VALUES(file_name), file_name),
mime_type=IF(mime_type='', VALUES(mime_type), mime_type),
file_size=IF(file_size=0, VALUES(file_size), file_size),
file_type=IF(file_type='' OR file_type='file', VALUES(file_type), file_type),
updated_at=updated_at`,
file.GroupFileID, file.Topic, file.FileID, file.SourceTopic, file.SourceSeq, decodeUID(file.UploaderID),
id, file.GroupFileID, file.Topic, file.FileID, file.SourceTopic, file.SourceSeq, decodeUID(file.UploaderID),
file.FileName, file.MIMEType, file.FileType, file.FileSize, file.Status, file.IdempotencyKey, now, now)
if err != nil && !isDupe(err) {
return nil, err
@@ -1127,15 +1127,15 @@ func (a *adapter) TenantGroupFileCreate(id t.TenantID, file *t.GroupFile) (*t.Gr
}
if fid := t.ParseUid(uploadID); !fid.IsZero() {
if a.tenantScopedDB {
_, err = tx.ExecContext(ctx, `INSERT INTO im_filemsglinks(createdat,fileid,topic)
SELECT ?,?,? WHERE NOT EXISTS (
SELECT 1 FROM im_filemsglinks WHERE fileid=? AND topic=?)`,
now, decodeUID(fid), file.Topic, decodeUID(fid), file.Topic)
} else {
_, err = tx.ExecContext(ctx, `INSERT INTO im_filemsglinks(tenant_id,createdat,fileid,topic)
SELECT ?,?,?,? WHERE NOT EXISTS (
SELECT 1 FROM im_filemsglinks WHERE tenant_id=? AND fileid=? AND topic=?)`,
id, now, decodeUID(fid), file.Topic, id, decodeUID(fid), file.Topic)
} else {
_, err = tx.ExecContext(ctx, `INSERT INTO im_filemsglinks(createdat,fileid,topic)
SELECT ?,?,? WHERE NOT EXISTS (
SELECT 1 FROM im_filemsglinks WHERE fileid=? AND topic=?)`,
now, decodeUID(fid), file.Topic, decodeUID(fid), file.Topic)
}
if err != nil {
return nil, err
@@ -1144,7 +1144,7 @@ func (a *adapter) TenantGroupFileCreate(id t.TenantID, file *t.GroupFile) (*t.Gr
if err = tx.Commit(); err != nil {
return nil, err
}
created, err := a.groupFileByQuery(ctx, "SELECT * FROM im_group_files WHERE topic=? AND file_id=?", file.Topic, file.FileID)
created, err := a.groupFileByQuery(ctx, "SELECT * FROM im_group_files WHERE tenant_id=? AND topic=? AND file_id=?", id, file.Topic, file.FileID)
if err != nil {
return nil, err
}
@@ -1200,8 +1200,8 @@ func (a *adapter) TenantGroupFileDelete(id t.TenantID, topic, groupFileID string
}
query := `UPDATE im_group_files
SET status='deleted',deleted_by=?,deleted_at=?,updated_at=?
WHERE topic=? AND group_file_id=? AND status='active'`
args := []any{decodeUID(actor), now, now, strings.TrimSpace(topic), strings.TrimSpace(groupFileID)}
WHERE tenant_id=? AND topic=? AND group_file_id=? AND status='active'`
args := []any{decodeUID(actor), now, now, id, strings.TrimSpace(topic), strings.TrimSpace(groupFileID)}
if !canManage {
query += " AND uploader_id=?"
args = append(args, decodeUID(actor))
@@ -1213,7 +1213,7 @@ func (a *adapter) TenantGroupFileDelete(id t.TenantID, topic, groupFileID string
if affected, _ := res.RowsAffected(); affected == 0 {
return nil, t.ErrNotFound
}
return a.groupFileByQuery(ctx, "SELECT * FROM im_group_files WHERE topic=? AND group_file_id=?", strings.TrimSpace(topic), strings.TrimSpace(groupFileID))
return a.groupFileByQuery(ctx, "SELECT * FROM im_group_files WHERE tenant_id=? AND topic=? AND group_file_id=?", id, strings.TrimSpace(topic), strings.TrimSpace(groupFileID))
}
func (a *adapter) TenantGroupCreate(id t.TenantID, topic *t.Topic, owner t.Uid, ownerPrivate any,
@@ -1319,8 +1319,8 @@ func (a *adapter) TenantGroupInviteMember(id t.TenantID, topic string, inviter,
idempotencyKey += ":" + target.UserId()
}
if _, err = tx.ExecContext(ctx, `INSERT INTO im_group_invitations
(invitation_id,topic,inviter_user_id,target_user_id,message,status,result,idempotency_key,expires_at,handled_at,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?)`, invitationID, topic, decodeUID(inviter), decodeUID(target), message,
(tenant_id,invitation_id,topic,inviter_user_id,target_user_id,message,status,result,idempotency_key,expires_at,handled_at,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)`, id, invitationID, topic, decodeUID(inviter), decodeUID(target), message,
t.GroupInvitationStatusJoined, "joined", idempotencyKey, now.Add(7*24*time.Hour), now, now, now); err != nil {
return false, err
}
@@ -1490,8 +1490,8 @@ func (a *adapter) TenantGroupCanPost(id t.TenantID, topic string, uid t.Uid, adm
var muteAll, memberMuted bool
err := a.db.QueryRowContext(ctx, `SELECT
COALESCE((SELECT mute_all FROM im_group_settings WHERE tenant_id=? AND topic=? AND group_status=? LIMIT 1),0),
EXISTS(SELECT 1 FROM im_group_mutes WHERE topic=? AND user_id=? AND status=? AND (expires_at IS NULL OR expires_at>?))`,
id, topic, t.GroupStatusActive, topic, decodeUID(uid), t.GroupMuteStatusActive, now).Scan(&muteAll, &memberMuted)
EXISTS(SELECT 1 FROM im_group_mutes WHERE tenant_id=? AND topic=? AND user_id=? AND status=? AND (expires_at IS NULL OR expires_at>?))`,
id, topic, t.GroupStatusActive, id, topic, decodeUID(uid), t.GroupMuteStatusActive, now).Scan(&muteAll, &memberMuted)
if err != nil {
return false, err
}
@@ -1549,7 +1549,7 @@ func syncGroupMuteAllTx(tx *sqlx.Tx, tenantID t.TenantID, topic string, muteAll
mode = t.ModeCPublic &^ t.ModeWrite
}
_, err := tx.Exec(tenantShardSQL(tenantID, `UPDATE im_subscriptions AS s
JOIN im_group_members AS gm ON gm.topic=s.topic AND gm.user_id=s.userid
JOIN im_group_members AS gm ON gm.tenant_id=s.tenant_id AND 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
@@ -1611,7 +1611,7 @@ func (a *adapter) groupJoinRequestByQuery(ctx context.Context, query string, arg
func (a *adapter) groupInvitationByQuery(ctx context.Context, query string, args ...any) (*t.GroupInvitation, error) {
var item t.GroupInvitation
var handledAt sql.NullTime
err := a.db.QueryRowxContext(ctx, query, args...).Scan(&item.ID, &item.InvitationID, &item.Topic, &item.InviterUserRaw, &item.TargetUserRaw,
err := a.db.QueryRowxContext(ctx, query, args...).Scan(&item.TenantID, &item.ID, &item.InvitationID, &item.Topic, &item.InviterUserRaw, &item.TargetUserRaw,
&item.Message, &item.Status, &item.Result, &item.JoinRequestID, &item.IdempotencyKey, &item.ExpiresAt, &handledAt, &item.CreatedAt, &item.UpdatedAt)
if err == sql.ErrNoRows {
return nil, t.ErrNotFound
+5
View File
@@ -118,6 +118,7 @@ type GroupMemberListOptions struct {
}
type GroupInvitation struct {
TenantID TenantID `db:"tenant_id"`
ID int64 `db:"id"`
InvitationID string `db:"invitation_id"`
Topic string `db:"topic"`
@@ -137,6 +138,7 @@ type GroupInvitation struct {
}
type GroupJoinRequest struct {
TenantID TenantID `db:"tenant_id"`
ID int64 `db:"id"`
RequestID string `db:"request_id"`
Topic string `db:"topic"`
@@ -160,6 +162,7 @@ type GroupJoinRequest struct {
}
type GroupAnnouncement struct {
TenantID TenantID `db:"tenant_id"`
ID int64 `db:"id"`
AnnouncementID string `db:"announcement_id"`
Topic string `db:"topic"`
@@ -177,6 +180,7 @@ type GroupAnnouncement struct {
}
type GroupMute struct {
TenantID TenantID `db:"tenant_id"`
Topic string `db:"topic"`
UserID Uid `db:"-"`
MutedBy Uid `db:"-"`
@@ -195,6 +199,7 @@ type GroupMute struct {
}
type GroupFile struct {
TenantID TenantID `db:"tenant_id"`
ID int64 `db:"id"`
GroupFileID string `db:"group_file_id"`
Topic string `db:"topic"`