feat: add chapter eight call records

This commit is contained in:
richjohnrambo
2026-08-13 16:14:57 +08:00
parent 92d0066a02
commit dfcccbb761
9 changed files with 711 additions and 20 deletions
+4
View File
@@ -289,6 +289,10 @@ type TenantBusinessAdapter interface {
TenantMessageGetDeleted(t.TenantID, string, t.Uid, *t.QueryOpt) ([]t.DelMessage, error)
TenantMessageSearch(t.TenantID, string, t.Uid, string, string, string, int) ([]t.Message, string, error)
TenantCallCreate(t.TenantID, *t.CallRecord) error
TenantCallAccept(t.TenantID, string, int, time.Time) error
TenantCallFinish(t.TenantID, string, int, string, int64, time.Time) error
TenantFavoriteCreate(t.TenantID, *t.FavoriteItem) (*t.FavoriteItem, error)
TenantFavoriteList(t.TenantID, t.Uid, string, string, string, int) ([]t.FavoriteItem, string, error)
TenantFavoriteGet(t.TenantID, t.Uid, string) (*t.FavoriteItem, error)
+85 -3
View File
@@ -791,6 +791,9 @@ func (a *adapter) CreateDb(reset bool) error {
if err = createIMRelationTables(tx); err != nil {
return err
}
if err = createIMCallTables(tx); err != nil {
return err
}
// Deletion log
if _, err = tx.Exec(
@@ -919,6 +922,34 @@ func createIMNotificationTables(tx *sql.Tx) error {
return err
}
func createIMCallTables(tx *sql.Tx) error {
_, err := tx.Exec(
`CREATE TABLE im_call_records(
id BIGINT NOT NULL AUTO_INCREMENT,
call_id VARCHAR(64) NOT NULL,
topic CHAR(25) NOT NULL,
seq_id INT NOT NULL,
caller_id BIGINT NOT NULL,
callee_id BIGINT NOT NULL,
call_type VARCHAR(16) NOT NULL,
status VARCHAR(32) NOT NULL,
end_reason VARCHAR(64) NOT NULL DEFAULT '',
duration_ms BIGINT NOT NULL DEFAULT 0,
started_at DATETIME(3) NOT NULL,
accepted_at DATETIME(3),
finished_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_call_records_call(call_id),
UNIQUE INDEX uk_im_call_records_topic_seq(topic, seq_id),
INDEX idx_im_call_records_caller(caller_id, id DESC),
INDEX idx_im_call_records_callee(callee_id, id DESC),
INDEX idx_im_call_records_status(status, updated_at)
)`)
return err
}
func ensureTenantRoutingColumns(a *adapter) error {
statements := []string{
"ALTER TABLE im_tenant ADD COLUMN db_name VARCHAR(128) NOT NULL DEFAULT '' AFTER tenant_desc",
@@ -1258,7 +1289,7 @@ func (a *adapter) TenantAuthDelScheme(tenantID t.TenantID, uid t.Uid, scheme str
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx, "DELETE FROM auth WHERE tenant_id=? AND userid=? AND scheme=?",
_, err = a.db.ExecContext(ctx, "DELETE FROM auth WHERE tenant_id=? AND userid=? AND scheme=?",
tenantID, store.DecodeUid(uid), scheme)
return err
}
@@ -3942,7 +3973,7 @@ func (a *adapter) TenantCredFail(tenantID t.TenantID, uid t.Uid, method string)
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx, "UPDATE credentials SET updatedat=?,retries=retries+1 "+
_, err = a.db.ExecContext(ctx, "UPDATE credentials SET updatedat=?,retries=retries+1 "+
"WHERE tenant_id=? AND userid=? AND method=? AND done=FALSE",
t.TimeNow(), tenantID, store.DecodeUid(uid), method)
return err
@@ -3983,7 +4014,7 @@ func (a *adapter) TenantCredGetActive(tenantID t.TenantID, uid t.Uid, method str
defer cancel()
}
var cred t.Credential
err := a.db.GetContext(ctx, &cred, "SELECT createdat,updatedat,method,value,resp,done,retries "+
err = a.db.GetContext(ctx, &cred, "SELECT createdat,updatedat,method,value,resp,done,retries "+
"FROM credentials WHERE tenant_id=? AND userid=? AND deletedat IS NULL AND method=? AND done=FALSE",
tenantID, store.DecodeUid(uid), method)
if err == sql.ErrNoRows {
@@ -4292,6 +4323,57 @@ func (a *adapter) FileLinkAttachments(topic string, userId, msgId t.Uid, fids []
return tx.Commit()
}
func (a *adapter) FileUserHasAccess(fid string, uid t.Uid) (bool, error) {
if uid.IsZero() {
return false, t.ErrMalformed
}
fileID := t.ParseUid(fid)
if fileID.IsZero() {
return false, t.ErrMalformed
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
var allowed int
err := a.db.GetContext(ctx, &allowed, `
SELECT COUNT(*) FROM fileuploads AS fu
WHERE fu.id=? AND fu.status=? AND (
fu.userid=?
OR EXISTS (
SELECT 1 FROM filemsglinks AS fml
WHERE fml.fileid=fu.id AND fml.userid=?
)
OR EXISTS (
SELECT 1 FROM filemsglinks AS fml
INNER JOIN subscriptions AS s
ON s.topic=fml.topic AND s.userid=?
WHERE fml.fileid=fu.id AND fml.topic IS NOT NULL
AND s.deletedat IS NULL AND INSTR(s.modewant,'R')>0 AND INSTR(s.modegiven,'R')>0
)
OR EXISTS (
SELECT 1 FROM filemsglinks AS fml
INNER JOIN messages AS m
ON m.id=fml.msgid
INNER JOIN subscriptions AS s
ON s.topic=m.topic AND s.userid=?
WHERE fml.fileid=fu.id AND fml.msgid IS NOT NULL
AND m.deletedat IS NULL AND m.recalled_at IS NULL
AND s.deletedat IS NULL AND INSTR(s.modewant,'R')>0 AND INSTR(s.modegiven,'R')>0
AND NOT EXISTS (
SELECT 1 FROM dellog AS d
WHERE d.topic=m.topic AND d.deletedfor=?
AND d.low<=m.seqid AND (d.hi=0 OR d.hi>m.seqid)
)
)
) LIMIT 1`,
store.DecodeUid(fileID), t.UploadCompleted, store.DecodeUid(uid), store.DecodeUid(uid), store.DecodeUid(uid), store.DecodeUid(uid), store.DecodeUid(uid))
if err != nil {
return false, err
}
return allowed > 0, nil
}
// PCacheGet reads a persistet cache entry.
func (a *adapter) PCacheGet(key string) (string, error) {
ctx, cancel := a.getContext()
+225 -12
View File
@@ -127,6 +127,9 @@ func (a *adapter) TenantUserCreate(id t.TenantID, user *t.User) error {
if err != nil || user == nil || user.TenantID != id {
return t.ErrMalformed
}
if tenantAdp.tenantScopedDB {
return tenantAdp.UserCreate(user)
}
return tenantAdp.UserCreate(user)
}
@@ -139,12 +142,16 @@ func (a *adapter) TenantUserGet(id t.TenantID, uid t.Uid) (*t.User, error) {
user, err := tenantAdp.UserGet(uid)
return stampTenantUser(id, user), err
}
if a.tenantScopedDB {
user, err := a.UserGet(uid)
return stampTenantUser(id, user), err
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
var user t.User
err := a.db.GetContext(ctx, &user, "SELECT * FROM users WHERE tenant_id=? AND id=? AND state!=?",
err = a.db.GetContext(ctx, &user, "SELECT * FROM users WHERE tenant_id=? AND id=? AND state!=?",
id, decodeUID(uid), t.StateDeleted)
if err == sql.ErrNoRows {
return nil, nil
@@ -165,6 +172,10 @@ func (a *adapter) TenantUserGetAll(id t.TenantID, uids ...t.Uid) ([]t.User, erro
users, err := tenantAdp.UserGetAll(uids...)
return stampTenantUsers(id, users), err
}
if a.tenantScopedDB {
users, err := a.UserGetAll(uids...)
return stampTenantUsers(id, users), err
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
@@ -185,7 +196,13 @@ func (a *adapter) tenantUserGetAllTx(ctx context.Context, tx *sqlx.Tx, id t.Tena
if len(args) == 0 {
return nil, nil
}
q, params, _ := sqlx.In("SELECT * FROM users WHERE tenant_id=? AND id IN (?) AND state!=?", id, args, t.StateDeleted)
var q string
var params []any
if a.tenantScopedDB {
q, params, _ = sqlx.In("SELECT * FROM users WHERE id IN (?) AND state!=?", args, t.StateDeleted)
} else {
q, params, _ = sqlx.In("SELECT * FROM users WHERE tenant_id=? AND id IN (?) AND state!=?", id, args, t.StateDeleted)
}
query := a.db.Rebind(q)
var rows *sqlx.Rows
var err error
@@ -219,6 +236,9 @@ func (a *adapter) TenantUserDelete(id t.TenantID, uid t.Uid, hard bool) error {
if tenantAdp != a {
return tenantAdp.UserDelete(uid, hard)
}
if a.tenantScopedDB {
return a.UserDelete(uid, hard)
}
decoded := decodeUID(uid)
ctx, cancel := a.getContextForTx()
if cancel != nil {
@@ -351,6 +371,9 @@ func (a *adapter) TenantUserUpdate(id t.TenantID, uid t.Uid, update map[string]a
if tenantAdp != a {
return tenantAdp.UserUpdate(uid, update)
}
if a.tenantScopedDB {
return a.UserUpdate(uid, update)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -399,6 +422,9 @@ func (a *adapter) TenantUserUpdateTags(id t.TenantID, uid t.Uid, add, remove, re
if tenantAdp != a {
return tenantAdp.UserUpdateTags(uid, add, remove, reset)
}
if a.tenantScopedDB {
return a.UserUpdateTags(uid, add, remove, reset)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -446,6 +472,9 @@ func (a *adapter) TenantUserUnreadCount(id t.TenantID, uids ...t.Uid) (map[t.Uid
if tenantAdp != a {
return tenantAdp.UserUnreadCount(uids...)
}
if a.tenantScopedDB {
return a.UserUnreadCount(uids...)
}
counts := make(map[t.Uid]int, len(uids))
var decoded []any
for _, uid := range uids {
@@ -489,6 +518,9 @@ func (a *adapter) TenantUserGetUnvalidated(id t.TenantID, before time.Time, limi
if tenantAdp != a {
return tenantAdp.UserGetUnvalidated(before, limit)
}
if a.tenantScopedDB {
return a.UserGetUnvalidated(before, limit)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
@@ -537,6 +569,9 @@ func (a *adapter) TenantTopicCreate(id t.TenantID, topic *t.Topic) error {
if tenantAdp != a {
return tenantAdp.TopicCreate(topic)
}
if a.tenantScopedDB {
return a.TopicCreate(topic)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -564,6 +599,9 @@ func (a *adapter) TenantTopicCreateP2P(id t.TenantID, one, two *t.Subscription)
if tenantAdp != a {
return tenantAdp.TopicCreateP2P(one, two)
}
if a.tenantScopedDB {
return a.TopicCreateP2P(one, two)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -601,12 +639,16 @@ func (a *adapter) TenantTopicGet(id t.TenantID, topic string) (*t.Topic, error)
top, err := tenantAdp.TopicGet(topic)
return stampTenantTopic(id, top), err
}
if a.tenantScopedDB {
top, err := a.TopicGet(topic)
return stampTenantTopic(id, top), err
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
var top t.Topic
err := a.db.GetContext(ctx, &top,
err = a.db.GetContext(ctx, &top,
"SELECT tenant_id,createdat,updatedat,state,stateat,touchedat,name AS id,usebt,access,owner,seqid,delid,subcnt,public,trusted,tags,aux "+
"FROM topics WHERE tenant_id=? AND name=?", id, topic)
if err == sql.ErrNoRows {
@@ -642,6 +684,10 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool
subs, err := tenantAdp.TopicsForUser(uid, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
if a.tenantScopedDB {
subs, err := a.TopicsForUser(uid, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
q := `SELECT tenant_id,createdat,updatedat,deletedat,topic,delid,recvseqid,
readseqid,modewant,modegiven,private FROM subscriptions WHERE tenant_id=? AND userid=?`
args := []any{id, decodeUID(uid)}
@@ -805,6 +851,10 @@ func (a *adapter) TenantUsersForTopic(id t.TenantID, topic string, keepDeleted b
subs, err := tenantAdp.UsersForTopic(topic, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
if a.tenantScopedDB {
subs, err := a.UsersForTopic(topic, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
tcat := t.GetTopicCat(topic)
q := `SELECT s.tenant_id,s.createdat,s.updatedat,s.deletedat,s.userid,s.topic,s.delid,s.recvseqid,
s.readseqid,s.modewant,s.modegiven,u.public,u.trusted,u.lastseen,u.useragent,s.private
@@ -924,6 +974,9 @@ func (a *adapter) TenantOwnTopics(id t.TenantID, uid t.Uid) ([]string, error) {
if tenantAdp != a {
return tenantAdp.OwnTopics(uid)
}
if a.tenantScopedDB {
return a.OwnTopics(uid)
}
return a.tenantTopicNames("SELECT name FROM topics WHERE tenant_id=? AND owner=? AND state!=?",
id, decodeUID(uid), t.StateDeleted)
}
@@ -936,6 +989,9 @@ func (a *adapter) TenantChannelsForUser(id t.TenantID, uid t.Uid) ([]string, err
if tenantAdp != a {
return tenantAdp.ChannelsForUser(uid)
}
if a.tenantScopedDB {
return a.ChannelsForUser(uid)
}
return a.tenantTopicNames("SELECT topic FROM subscriptions WHERE tenant_id=? AND userid=? AND topic LIKE 'chn%' "+
"AND INSTR(modewant,'P')>0 AND INSTR(modegiven,'P')>0 AND deletedat IS NULL", id, decodeUID(uid))
}
@@ -953,6 +1009,9 @@ func (a *adapter) TenantTopicShare(id t.TenantID, topic string, subs []*t.Subscr
if tenantAdp != a {
return tenantAdp.TopicShare(topic, subs)
}
if a.tenantScopedDB {
return a.TopicShare(topic, subs)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -1046,6 +1105,9 @@ func (a *adapter) TenantTopicDelete(id t.TenantID, topic string, isChan, hard bo
if tenantAdp != a {
return tenantAdp.TopicDelete(topic, isChan, hard)
}
if a.tenantScopedDB {
return a.TopicDelete(topic, isChan, hard)
}
topics := []any{topic}
if isChan {
topics = append(topics, t.GrpToChn(topic))
@@ -1099,11 +1161,14 @@ func (a *adapter) TenantTopicUpdateOnMessage(id t.TenantID, topic string, msg *t
if tenantAdp != a {
return tenantAdp.TopicUpdateOnMessage(topic, msg)
}
if a.tenantScopedDB {
return a.TopicUpdateOnMessage(topic, msg)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx, "UPDATE topics SET seqid=?,touchedat=? WHERE tenant_id=? AND name=?",
_, err = a.db.ExecContext(ctx, "UPDATE topics SET seqid=?,touchedat=? WHERE tenant_id=? AND name=?",
msg.SeqId, msg.CreatedAt, id, topic)
return err
}
@@ -1116,11 +1181,14 @@ func (a *adapter) TenantTopicUpdateSubCnt(id t.TenantID, topic string) error {
if tenantAdp != a {
return tenantAdp.TopicUpdateSubCnt(topic)
}
if a.tenantScopedDB {
return a.TopicUpdateSubCnt(topic)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
_, err = a.db.ExecContext(ctx,
"UPDATE topics SET subcnt=(SELECT COUNT(*) FROM subscriptions WHERE tenant_id=? AND topic IN (?,?) AND deletedat IS NULL) WHERE tenant_id=? AND name=?",
id, topic, t.GrpToChn(topic), id, topic)
return err
@@ -1134,6 +1202,9 @@ func (a *adapter) TenantTopicUpdate(id t.TenantID, topic string, update map[stri
if tenantAdp != a {
return tenantAdp.TopicUpdate(topic, update)
}
if a.tenantScopedDB {
return a.TopicUpdate(topic, update)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -1178,11 +1249,14 @@ func (a *adapter) TenantTopicOwnerChange(id t.TenantID, topic string, owner t.Ui
if tenantAdp != a {
return tenantAdp.TopicOwnerChange(topic, owner)
}
if a.tenantScopedDB {
return a.TopicOwnerChange(topic, owner)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx, "UPDATE topics SET owner=? WHERE tenant_id=? AND name=?", decodeUID(owner), id, topic)
_, err = a.db.ExecContext(ctx, "UPDATE topics SET owner=? WHERE tenant_id=? AND name=?", decodeUID(owner), id, topic)
return err
}
@@ -1198,6 +1272,13 @@ func (a *adapter) TenantSubscriptionGet(id t.TenantID, topic string, uid t.Uid,
}
return sub, err
}
if a.tenantScopedDB {
sub, err := a.SubscriptionGet(topic, uid, keepDeleted)
if sub != nil {
sub.TenantID = id
}
return sub, err
}
query := `SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
readseqid,modewant,modegiven,private FROM subscriptions WHERE tenant_id=? AND topic=? AND userid=?`
if !keepDeleted {
@@ -1208,7 +1289,7 @@ func (a *adapter) TenantSubscriptionGet(id t.TenantID, topic string, uid t.Uid,
defer cancel()
}
var sub t.Subscription
err := a.db.GetContext(ctx, &sub, query, id, topic, decodeUID(uid))
err = a.db.GetContext(ctx, &sub, query, id, topic, decodeUID(uid))
if err == sql.ErrNoRows {
return nil, nil
}
@@ -1229,6 +1310,10 @@ func (a *adapter) TenantSubsForUser(id t.TenantID, uid t.Uid) ([]t.Subscription,
subs, err := tenantAdp.SubsForUser(uid)
return stampTenantSubs(id, subs), err
}
if a.tenantScopedDB {
subs, err := a.SubsForUser(uid)
return stampTenantSubs(id, subs), err
}
rows, err := a.db.Queryx(`SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
readseqid,modewant,modegiven FROM subscriptions WHERE tenant_id=? AND userid=? AND deletedat IS NULL`,
id, decodeUID(uid))
@@ -1257,6 +1342,10 @@ func (a *adapter) TenantSubsForTopic(id t.TenantID, topic string, keepDeleted bo
subs, err := tenantAdp.SubsForTopic(topic, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
if a.tenantScopedDB {
subs, err := a.SubsForTopic(topic, keepDeleted, opts)
return stampTenantSubs(id, subs), err
}
q := `SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
readseqid,modewant,modegiven,private FROM subscriptions WHERE tenant_id=? AND topic=?`
args := []any{id, topic}
@@ -1305,6 +1394,9 @@ func (a *adapter) TenantSubsUpdate(id t.TenantID, topic string, uid t.Uid, updat
if tenantAdp != a {
return tenantAdp.SubsUpdate(topic, uid, update)
}
if a.tenantScopedDB {
return a.SubsUpdate(topic, uid, update)
}
cols, args := common.UpdateByMap(update)
q := "UPDATE subscriptions SET " + strings.Join(cols, ",") + " WHERE tenant_id=? AND topic=?"
args = append(args, id, topic)
@@ -1316,7 +1408,7 @@ func (a *adapter) TenantSubsUpdate(id t.TenantID, topic string, uid t.Uid, updat
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx, q, args...)
_, err = a.db.ExecContext(ctx, q, args...)
return err
}
@@ -1328,6 +1420,9 @@ func (a *adapter) TenantSubsDelete(id t.TenantID, topic string, uid t.Uid) error
if tenantAdp != a {
return tenantAdp.SubsDelete(topic, uid)
}
if a.tenantScopedDB {
return a.SubsDelete(topic, uid)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -1411,6 +1506,10 @@ func (a *adapter) TenantFind(id t.TenantID, caller, promoPrefix string, req [][]
subs, err := tenantAdp.Find(caller, promoPrefix, req, opt, activeOnly)
return stampTenantSubs(id, subs), err
}
if a.tenantScopedDB {
subs, err := a.Find(caller, promoPrefix, req, opt, activeOnly)
return stampTenantSubs(id, subs), err
}
allReq := t.FlattenDoubleSlice(req)
allTags := append(append([]string{}, allReq...), opt...)
if len(allTags) == 0 {
@@ -1513,6 +1612,9 @@ func (a *adapter) TenantFindOne(id t.TenantID, tag string) (string, error) {
if tenantAdp != a {
return tenantAdp.FindOne(tag)
}
if a.tenantScopedDB {
return a.FindOne(tag)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
@@ -1546,6 +1648,9 @@ func (a *adapter) TenantMessageSave(id t.TenantID, msg *t.Message) error {
if tenantAdp != a {
return tenantAdp.MessageSave(msg)
}
if a.tenantScopedDB {
return a.MessageSave(msg)
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
@@ -1729,6 +1834,10 @@ func (a *adapter) TenantMessageGetAll(id t.TenantID, topic string, uid t.Uid, op
msgs, err := tenantAdp.MessageGetAll(topic, uid, opts)
return stampTenantMessages(id, msgs), err
}
if a.tenantScopedDB {
msgs, err := a.MessageGetAll(topic, uid, opts)
return stampTenantMessages(id, msgs), err
}
limit := a.maxMessageResults
args := []any{id, topic, id, decodeUID(uid)}
seq := ""
@@ -1856,6 +1965,95 @@ func (a *adapter) TenantMessageSearch(id t.TenantID, topic string, uid t.Uid, qu
return msgs, nextCursor, nil
}
func (a *adapter) TenantCallCreate(id t.TenantID, record *t.CallRecord) error {
if !a.tenantScopedDB {
tenantAdp, err := a.routedTenantAdapter(id)
if err != nil {
return err
}
if tenantAdp != a {
return tenantAdp.TenantCallCreate(id, record)
}
}
if err := validTenant(id); err != nil || record == nil || record.TenantID != id || record.CallID == "" ||
record.Topic == "" || record.SeqID <= 0 || record.CallerID.IsZero() || record.CalleeID.IsZero() ||
record.CallType == "" {
return t.ErrMalformed
}
now := t.TimeNow()
if record.StartedAt.IsZero() {
record.StartedAt = now
}
record.CreatedAt = now
record.UpdatedAt = now
if record.Status == "" {
record.Status = t.CallStatusStarted
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
`INSERT INTO im_call_records
(call_id,topic,seq_id,caller_id,callee_id,call_type,status,end_reason,duration_ms,started_at,accepted_at,finished_at,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE updated_at=VALUES(updated_at)`,
record.CallID, record.Topic, record.SeqID, decodeUID(record.CallerID), decodeUID(record.CalleeID),
record.CallType, record.Status, record.EndReason, record.DurationMS, record.StartedAt, record.AcceptedAt,
record.FinishedAt, record.CreatedAt, record.UpdatedAt)
return err
}
func (a *adapter) TenantCallAccept(id t.TenantID, callID string, seq int, acceptedAt time.Time) error {
if !a.tenantScopedDB {
tenantAdp, err := a.routedTenantAdapter(id)
if err != nil {
return err
}
if tenantAdp != a {
return tenantAdp.TenantCallAccept(id, callID, seq, acceptedAt)
}
}
if err := validTenant(id); err != nil || callID == "" || seq <= 0 || acceptedAt.IsZero() {
return t.ErrMalformed
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
`UPDATE im_call_records
SET status=?,accepted_at=?,updated_at=?
WHERE call_id=? AND seq_id=? AND status=?`,
t.CallStatusAccepted, acceptedAt, acceptedAt, callID, seq, t.CallStatusStarted)
return err
}
func (a *adapter) TenantCallFinish(id t.TenantID, callID string, seq int, status string, durationMS int64, finishedAt time.Time) error {
if !a.tenantScopedDB {
tenantAdp, err := a.routedTenantAdapter(id)
if err != nil {
return err
}
if tenantAdp != a {
return tenantAdp.TenantCallFinish(id, callID, seq, status, durationMS, finishedAt)
}
}
if err := validTenant(id); err != nil || callID == "" || seq <= 0 || finishedAt.IsZero() || durationMS < 0 {
return t.ErrMalformed
}
ctx, cancel := a.getContext()
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
`UPDATE im_call_records
SET status=?,end_reason=?,duration_ms=?,finished_at=?,updated_at=?
WHERE call_id=? AND seq_id=?`,
status, status, durationMS, finishedAt, finishedAt, callID, seq)
return err
}
func tenantMessageGetOne(q sqlx.QueryerContext, ctx context.Context, tenantID t.TenantID, topic string, seq int, suffix string) (*t.Message, error) {
row := struct {
t.Message
@@ -2071,6 +2269,9 @@ func (a *adapter) TenantMessageDeleteList(id t.TenantID, topic string, del *t.De
if tenantAdp != a {
return tenantAdp.MessageDeleteList(topic, del)
}
if a.tenantScopedDB {
return a.MessageDeleteList(topic, del)
}
ctx, cancel := a.getContextForTx()
if cancel != nil {
defer cancel()
@@ -2102,6 +2303,13 @@ func (a *adapter) TenantMessageGetDeleted(id t.TenantID, topic string, uid t.Uid
}
return deleted, err
}
if a.tenantScopedDB {
deleted, err := a.MessageGetDeleted(topic, uid, opts)
for i := range deleted {
deleted[i].TenantID = id
}
return deleted, err
}
limit, lower, upper := a.maxResults, 0, 1<<31-1
if opts != nil {
if opts.Since > 0 {
@@ -2312,7 +2520,7 @@ func (a *adapter) TenantFileStartUpload(id t.TenantID, fd *t.FileDef) error {
if cancel != nil {
defer cancel()
}
_, err := a.db.ExecContext(ctx,
_, err = a.db.ExecContext(ctx,
"INSERT INTO fileuploads(tenant_id,id,createdat,updatedat,userid,status,mimetype,size,etag,location) VALUES(?,?,?,?,?,?,?,?,?,?)",
id, decodeUID(fd.Uid()), fd.CreatedAt, fd.UpdatedAt, user, fd.Status, fd.MimeType, fd.Size, fd.ETag, fd.Location)
return err
@@ -2384,7 +2592,7 @@ func (a *adapter) TenantFileGet(id t.TenantID, fid string) (*t.FileDef, error) {
defer cancel()
}
var fd t.FileDef
err := a.db.GetContext(ctx, &fd,
err = a.db.GetContext(ctx, &fd,
"SELECT tenant_id,id,createdat,updatedat,userid AS user,status,mimetype,size,IFNULL(etag,'') AS etag,location "+
"FROM fileuploads WHERE tenant_id=? AND id=?", id, decodeUID(fileID))
if err == sql.ErrNoRows {
@@ -2544,7 +2752,7 @@ func (a *adapter) TenantFileUserHasAccess(id t.TenantID, fid string, uid t.Uid)
defer cancel()
}
var allowed int
err := a.db.GetContext(ctx, &allowed, `
err = a.db.GetContext(ctx, &allowed, `
SELECT COUNT(*) FROM fileuploads AS fu
WHERE fu.tenant_id=? AND fu.id=? AND fu.status=? AND (
fu.userid=?
@@ -3638,7 +3846,12 @@ func (a *adapter) TenantFriendRequestAccept(id t.TenantID, requestID string, act
return nil, err
}
topicRow := &t.Topic{TenantID: id, ObjHeader: t.ObjHeader{Id: topic, CreatedAt: handledAt, UpdatedAt: handledAt}, TouchedAt: handledAt}
if err = tenantTopicCreate(tx, topicRow); err != nil {
if a.tenantScopedDB {
err = a.topicCreate(tx, topicRow)
} else {
err = tenantTopicCreate(tx, topicRow)
}
if err != nil {
if !isDupe(err) {
return nil, err
}