feat: complete shared database tenant sharding
This commit is contained in:
+119
-210
@@ -322,11 +322,11 @@ func messageHeadBool(head t.KVMap, key string) bool {
|
||||
|
||||
func (a *adapter) tenantTopicBumpMutationVersionTx(ctx context.Context, tx *sqlx.Tx, id t.TenantID, topic string, at time.Time) error {
|
||||
if a.tenantScopedDB {
|
||||
_, err := tx.ExecContext(ctx, "UPDATE im_topics SET mutation_version=mutation_version+1,updatedat=?,touchedat=? WHERE name=?",
|
||||
_, err := tx.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET mutation_version=mutation_version+1,updatedat=?,touchedat=? WHERE name=?"),
|
||||
at, at, topic)
|
||||
return err
|
||||
}
|
||||
_, err := tx.ExecContext(ctx, "UPDATE im_topics SET mutation_version=mutation_version+1,updatedat=?,touchedat=? WHERE tenant_id=? AND name=?",
|
||||
_, err := tx.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET mutation_version=mutation_version+1,updatedat=?,touchedat=? WHERE tenant_id=? AND name=?"),
|
||||
at, at, id, topic)
|
||||
return err
|
||||
}
|
||||
@@ -634,7 +634,7 @@ func (a *adapter) TenantUserDelete(id t.TenantID, uid t.Uid, hard bool) error {
|
||||
}()
|
||||
|
||||
var ownTopics []string
|
||||
q := "SELECT name FROM im_topics WHERE tenant_id=? AND owner=?"
|
||||
q := tenantShardSQL(id, "SELECT name FROM im_topics WHERE tenant_id=? AND owner=?")
|
||||
args := []any{id, decoded}
|
||||
if !hard {
|
||||
q += " AND state!=?"
|
||||
@@ -663,20 +663,20 @@ func (a *adapter) TenantUserDelete(id t.TenantID, uid t.Uid, hard bool) error {
|
||||
return err
|
||||
}
|
||||
if len(ownTopics) > 0 {
|
||||
if _, err = tx.Exec("DELETE dl FROM im_dellog AS dl JOIN im_topics AS tp ON tp.tenant_id=dl.tenant_id AND tp.name=dl.topic WHERE tp.tenant_id=? AND tp.owner=?", id, decoded); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "DELETE dl FROM im_dellog AS dl JOIN im_topics AS tp ON tp.tenant_id=dl.tenant_id AND tp.name=dl.topic WHERE tp.tenant_id=? AND tp.owner=?"), id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec(fmt.Sprintf("DELETE m FROM %s AS m JOIN im_topics AS tp ON tp.tenant_id=m.tenant_id AND tp.name=m.topic WHERE tp.tenant_id=? AND tp.owner=?", tenantMessagesTable(id)), id, decoded); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, fmt.Sprintf("DELETE m FROM %s AS m JOIN im_topics AS tp ON tp.tenant_id=m.tenant_id AND tp.name=m.topic WHERE tp.tenant_id=? AND tp.owner=?", tenantMessagesTable(id))), id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
sqlq, params, _ := sqlx.In("DELETE FROM im_subscriptions WHERE tenant_id=? AND topic IN (?)", id, ownAll)
|
||||
sqlq, params, _ := sqlx.In(tenantShardSQL(id, "DELETE FROM im_subscriptions WHERE tenant_id=? AND topic IN (?)"), id, ownAll)
|
||||
if _, err = tx.Exec(tx.Rebind(sqlq), params...); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("DELETE tt FROM im_topictags AS tt JOIN im_topics AS tp ON tp.tenant_id=tt.tenant_id AND tp.name=tt.topic WHERE tp.tenant_id=? AND tp.owner=?", id, decoded); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "DELETE tt FROM im_topictags AS tt JOIN im_topics AS tp ON tp.tenant_id=tt.tenant_id AND tp.name=tt.topic WHERE tp.tenant_id=? AND tp.owner=?"), id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("DELETE FROM im_topics WHERE tenant_id=? AND owner=?", id, decoded); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "DELETE FROM im_topics WHERE tenant_id=? AND owner=?"), id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -694,23 +694,23 @@ func (a *adapter) TenantUserDelete(id t.TenantID, uid t.Uid, hard bool) error {
|
||||
return err
|
||||
}
|
||||
if len(ownAll) > 0 {
|
||||
sqlq, params, _ := sqlx.In("UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic IN (?)", now, now, id, ownAll)
|
||||
sqlq, params, _ := sqlx.In(tenantShardSQL(id, "UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic IN (?)"), now, now, id, ownAll)
|
||||
if _, err = tx.Exec(tx.Rebind(sqlq), params...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err = tx.Exec("UPDATE im_topics SET updatedat=?,touchedat=?,state=?,stateat=? WHERE tenant_id=? AND owner=?",
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_topics SET updatedat=?,touchedat=?,state=?,stateat=? WHERE tenant_id=? AND owner=?"),
|
||||
now, now, t.StateDeleted, now, id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("UPDATE im_topics AS tp JOIN im_subscriptions AS s ON tp.tenant_id=s.tenant_id AND tp.name=s.topic "+
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_topics AS tp JOIN im_subscriptions AS s ON tp.tenant_id=s.tenant_id AND tp.name=s.topic "+
|
||||
"SET tp.updatedat=?,tp.touchedat=?,tp.state=?,tp.stateat=? WHERE tp.tenant_id=? AND tp.owner=0 AND s.userid=? AND tp.name LIKE 'p2p%'",
|
||||
now, now, t.StateDeleted, now, id, decoded); err != nil {
|
||||
), now, now, t.StateDeleted, now, id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("UPDATE im_subscriptions AS s_one JOIN im_subscriptions AS s_two ON s_one.tenant_id=s_two.tenant_id AND s_one.topic=s_two.topic "+
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_subscriptions AS s_one JOIN im_subscriptions AS s_two ON s_one.tenant_id=s_two.tenant_id AND s_one.topic=s_two.topic "+
|
||||
"SET s_two.updatedat=?,s_two.deletedat=? WHERE s_one.tenant_id=? AND s_one.userid=? AND s_one.topic LIKE 'p2p%'",
|
||||
now, now, id, decoded); err != nil {
|
||||
), now, now, id, decoded); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("UPDATE im_users SET updatedat=?,state=?,stateat=? WHERE tenant_id=? AND id=?",
|
||||
@@ -729,13 +729,13 @@ func (a *adapter) tenantTopicStateForUser(tx *sqlx.Tx, tenantID t.TenantID, deco
|
||||
if now.IsZero() {
|
||||
now = t.TimeNow()
|
||||
}
|
||||
if _, err := tx.Exec("UPDATE im_topics SET state=?,stateat=? WHERE tenant_id=? AND owner=? AND state!=?",
|
||||
if _, err := tx.Exec(tenantShardSQL(tenantID, "UPDATE im_topics SET state=?,stateat=? WHERE tenant_id=? AND owner=? AND state!=?"),
|
||||
objState, now, tenantID, decodedUID, t.StateDeleted); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := tx.Exec("UPDATE im_topics AS tp JOIN im_subscriptions AS s ON tp.tenant_id=s.tenant_id AND tp.name=s.topic "+
|
||||
_, err := tx.Exec(tenantShardSQL(tenantID, "UPDATE im_topics AS tp JOIN im_subscriptions AS s ON tp.tenant_id=s.tenant_id AND tp.name=s.topic "+
|
||||
"SET tp.state=?,tp.stateat=? WHERE tp.tenant_id=? AND tp.owner=0 AND s.userid=? AND tp.state!=?",
|
||||
objState, now, tenantID, decodedUID, t.StateDeleted)
|
||||
), objState, now, tenantID, decodedUID, t.StateDeleted)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -822,10 +822,10 @@ func (a *adapter) TenantUserUnreadCount(id t.TenantID, uids ...t.Uid) (map[t.Uid
|
||||
if len(decoded) == 0 {
|
||||
return counts, nil
|
||||
}
|
||||
q, args, _ := sqlx.In("SELECT s.userid,SUM(tp.seqid)-SUM(s.readseqid) AS unreadcount "+
|
||||
q, args, _ := sqlx.In(tenantShardSQL(id, "SELECT s.userid,SUM(tp.seqid)-SUM(s.readseqid) AS unreadcount "+
|
||||
"FROM im_topics AS tp JOIN im_subscriptions AS s ON tp.tenant_id=s.tenant_id AND tp.name=s.topic "+
|
||||
"WHERE s.tenant_id=? AND s.userid IN (?) AND s.deletedat IS NULL AND tp.state!=? "+
|
||||
"AND INSTR(s.modewant,'R')>0 AND INSTR(s.modegiven,'R')>0 GROUP BY s.userid", id, decoded, t.StateDeleted)
|
||||
"AND INSTR(s.modewant,'R')>0 AND INSTR(s.modegiven,'R')>0 GROUP BY s.userid"), id, decoded, t.StateDeleted)
|
||||
ctx, cancel := a.getContext()
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
@@ -886,9 +886,9 @@ func tenantTopicCreate(tx *sqlx.Tx, topic *t.Topic) error {
|
||||
if topic == nil || topic.TenantID.IsZero() {
|
||||
return t.ErrMalformed
|
||||
}
|
||||
_, err := tx.Exec("INSERT INTO im_topics(tenant_id,createdat,updatedat,touchedat,state,name,usebt,owner,access,public,trusted,tags,aux) "+
|
||||
_, err := tx.Exec(tenantShardSQL(topic.TenantID, "INSERT INTO im_topics(tenant_id,createdat,updatedat,touchedat,state,name,usebt,owner,access,public,trusted,tags,aux) "+
|
||||
"VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
topic.TenantID, topic.CreatedAt, topic.UpdatedAt, topic.TouchedAt, topic.State, topic.Id, topic.UseBt,
|
||||
), topic.TenantID, topic.CreatedAt, topic.UpdatedAt, topic.TouchedAt, topic.State, topic.Id, topic.UseBt,
|
||||
decodeUID(t.ParseUid(topic.Owner)), topic.Access, common.ToJSON(topic.Public), common.ToJSON(topic.Trusted),
|
||||
topic.Tags, common.ToJSON(topic.Aux))
|
||||
if err != nil {
|
||||
@@ -913,25 +913,25 @@ func createTenantSubscription(tx *sqlx.Tx, tenantID t.TenantID, sub *t.Subscript
|
||||
DeletedAt sql.NullTime `db:"deletedat"`
|
||||
}{}
|
||||
err := tx.Get(&existing,
|
||||
"SELECT id,deletedat FROM im_subscriptions WHERE tenant_id=? AND topic=? AND userid=? ORDER BY deletedat IS NULL DESC,id ASC LIMIT 1",
|
||||
tenantShardSQL(tenantID, "SELECT id,deletedat FROM im_subscriptions WHERE tenant_id=? AND topic=? AND userid=? ORDER BY deletedat IS NULL DESC,id ASC LIMIT 1"),
|
||||
tenantID, sub.Topic, decodedUID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
if existing.DeletedAt.Valid {
|
||||
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
"delid=0,recvseqid=0,readseqid=0,private=? WHERE tenant_id=? AND id=?",
|
||||
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, existing.ID)
|
||||
), sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, existing.ID)
|
||||
} else {
|
||||
_, err = tx.Exec("UPDATE im_subscriptions SET updatedat=?,modeWant=?,modeGiven=?,private=? WHERE tenant_id=? AND id=?",
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_subscriptions SET updatedat=?,modeWant=?,modeGiven=?,private=? WHERE tenant_id=? AND id=?"),
|
||||
sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, existing.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isOwner {
|
||||
_, err = tx.Exec("UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?", decodedUID, tenantID, sub.Topic)
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?"), decodedUID, tenantID, sub.Topic)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -941,30 +941,30 @@ func createTenantSubscription(tx *sqlx.Tx, tenantID t.TenantID, sub *t.Subscript
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(
|
||||
"INSERT INTO im_subscriptions(id,tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
|
||||
"VALUES(?,?,?,?,NULL,?,?,?,?,?)",
|
||||
tenantShardSQL(tenantID, "INSERT INTO im_subscriptions(id,tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
|
||||
"VALUES(?,?,?,?,NULL,?,?,?,?,?)"),
|
||||
subID, tenantID, sub.CreatedAt, sub.UpdatedAt, decodedUID, sub.Topic, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv)
|
||||
if isIDOutOfRange(err) {
|
||||
_, err = tx.Exec(
|
||||
"INSERT INTO im_subscriptions(tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
|
||||
"VALUES(?,?,?,NULL,?,?,?,?,?)",
|
||||
tenantShardSQL(tenantID, "INSERT INTO im_subscriptions(tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
|
||||
"VALUES(?,?,?,NULL,?,?,?,?,?)"),
|
||||
tenantID, sub.CreatedAt, sub.UpdatedAt, decodedUID, sub.Topic, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv)
|
||||
}
|
||||
|
||||
if err != nil && isDupe(err) {
|
||||
if undelete {
|
||||
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
"delid=0,recvseqid=0,readseqid=0 WHERE tenant_id=? AND topic=? AND userid=?",
|
||||
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), tenantID, sub.Topic, decodedUID)
|
||||
), sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), tenantID, sub.Topic, decodedUID)
|
||||
} else {
|
||||
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
|
||||
"delid=0,recvseqid=0,readseqid=0,private=? WHERE tenant_id=? AND topic=? AND userid=?",
|
||||
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, sub.Topic, decodedUID)
|
||||
), sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, sub.Topic, decodedUID)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && isOwner {
|
||||
_, err = tx.Exec("UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?", decodedUID, tenantID, sub.Topic)
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?"), decodedUID, tenantID, sub.Topic)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1033,7 +1033,7 @@ func (a *adapter) TenantTopicCreateP2P(id t.TenantID, one, two *t.Subscription)
|
||||
topic.ObjHeader.MergeTimes(&one.ObjHeader)
|
||||
topic.TouchedAt = one.GetTouchedAt()
|
||||
var existingTopicID int64
|
||||
err = tx.Get(&existingTopicID, "SELECT id FROM im_topics WHERE tenant_id=? AND name=? ORDER BY id ASC LIMIT 1", id, topic.Id)
|
||||
err = tx.Get(&existingTopicID, tenantShardSQL(id, "SELECT id FROM im_topics WHERE tenant_id=? AND name=? ORDER BY id ASC LIMIT 1"), id, topic.Id)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
@@ -1041,7 +1041,7 @@ func (a *adapter) TenantTopicCreateP2P(id t.TenantID, one, two *t.Subscription)
|
||||
if err = tenantTopicCreate(tx, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if _, err = tx.ExecContext(ctx, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE tenant_id=? AND id=?",
|
||||
} else if _, err = tx.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE tenant_id=? AND id=?"),
|
||||
topic.UpdatedAt, topic.TouchedAt, t.StateOK, id, existingTopicID); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1067,7 +1067,7 @@ func (a *adapter) TenantTopicGet(id t.TenantID, topic string) (*t.Topic, error)
|
||||
var top t.Topic
|
||||
err = a.db.GetContext(ctx, &top,
|
||||
"SELECT tenant_id,createdat,updatedat,state,stateat,touchedat,name AS id,usebt,access,owner,seqid,delid,subcnt,IFNULL(mutation_version,0) AS mutation_version,public,trusted,tags,aux "+
|
||||
"FROM im_topics WHERE tenant_id=? AND name=?", id, topic)
|
||||
tenantShardSQL(id, "FROM im_topics WHERE tenant_id=? AND name=?"), id, topic)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -1077,13 +1077,13 @@ func (a *adapter) TenantTopicGet(id t.TenantID, topic string) (*t.Topic, error)
|
||||
if t.GetTopicCat(topic) == t.TopicCatGrp {
|
||||
var subCnt int
|
||||
if err = a.db.GetContext(ctx, &subCnt,
|
||||
"SELECT COUNT(*) FROM im_subscriptions WHERE tenant_id=? AND topic IN (?,?) AND deletedat IS NULL",
|
||||
tenantShardSQL(id, "SELECT COUNT(*) FROM im_subscriptions WHERE tenant_id=? AND topic IN (?,?) AND deletedat IS NULL"),
|
||||
id, topic, t.GrpToChn(topic)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if subCnt != top.SubCnt {
|
||||
top.SubCnt = subCnt
|
||||
if _, err = a.db.ExecContext(ctx, "UPDATE im_topics SET subcnt=? WHERE tenant_id=? AND name=?", subCnt, id, topic); err != nil {
|
||||
if _, err = a.db.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET subcnt=? WHERE tenant_id=? AND name=?"), subCnt, id, topic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -1106,6 +1106,7 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool
|
||||
}
|
||||
q := `SELECT tenant_id,createdat,updatedat,deletedat,topic,delid,recvseqid,
|
||||
readseqid,modewant,modegiven,private FROM im_subscriptions WHERE tenant_id=? AND userid=?`
|
||||
q = tenantShardSQL(id, q)
|
||||
args := []any{id, decodeUID(uid)}
|
||||
if !keepDeleted {
|
||||
q += " AND deletedat IS NULL"
|
||||
@@ -1190,7 +1191,7 @@ func (a *adapter) TenantTopicsForUser(id t.TenantID, uid t.Uid, keepDeleted bool
|
||||
return nil, err
|
||||
}
|
||||
if len(topq) > 0 {
|
||||
q = "SELECT tenant_id,updatedat,state,touchedat,name AS id,usebt,access,seqid,delid,subcnt,IFNULL(mutation_version,0) AS mutation_version,public,trusted FROM im_topics WHERE tenant_id=? AND name IN (?)"
|
||||
q = tenantShardSQL(id, "SELECT tenant_id,updatedat,state,touchedat,name AS id,usebt,access,seqid,delid,subcnt,IFNULL(mutation_version,0) AS mutation_version,public,trusted FROM im_topics WHERE tenant_id=? AND name IN (?)")
|
||||
q, args, _ = sqlx.In(q, id, topq)
|
||||
if !keepDeleted {
|
||||
q += " AND state!=?"
|
||||
@@ -1306,6 +1307,7 @@ func (a *adapter) TenantUsersForTopic(id t.TenantID, topic string, keepDeleted b
|
||||
FROM im_subscriptions AS s JOIN im_users AS u ON s.tenant_id=u.tenant_id AND s.userid=u.id
|
||||
LEFT JOIN im_user_profiles AS p ON p.tenant_id=s.tenant_id AND p.user_id=s.userid
|
||||
WHERE s.tenant_id=? AND s.topic=?`
|
||||
q = tenantShardSQL(id, q)
|
||||
args := []any{id, topic}
|
||||
if !keepDeleted {
|
||||
q += " AND u.state!=?"
|
||||
@@ -1426,7 +1428,7 @@ func (a *adapter) TenantOwnTopics(id t.TenantID, uid t.Uid) ([]string, error) {
|
||||
if a.tenantScopedDB {
|
||||
return a.OwnTopics(uid)
|
||||
}
|
||||
return a.tenantTopicNames("SELECT name FROM im_topics WHERE tenant_id=? AND owner=? AND state!=?",
|
||||
return a.tenantTopicNames(tenantShardSQL(id, "SELECT name FROM im_topics WHERE tenant_id=? AND owner=? AND state!=?"),
|
||||
id, decodeUID(uid), t.StateDeleted)
|
||||
}
|
||||
|
||||
@@ -1441,8 +1443,8 @@ func (a *adapter) TenantChannelsForUser(id t.TenantID, uid t.Uid) ([]string, err
|
||||
if a.tenantScopedDB {
|
||||
return a.ChannelsForUser(uid)
|
||||
}
|
||||
return a.tenantTopicNames("SELECT topic FROM im_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))
|
||||
return a.tenantTopicNames(tenantShardSQL(id, "SELECT topic FROM im_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))
|
||||
}
|
||||
|
||||
func (a *adapter) TenantTopicShare(id t.TenantID, topic string, subs []*t.Subscription) error {
|
||||
@@ -1480,7 +1482,7 @@ func (a *adapter) TenantTopicShare(id t.TenantID, topic string, subs []*t.Subscr
|
||||
}
|
||||
}
|
||||
if topic != "" {
|
||||
if _, err = tx.Exec("UPDATE im_topics SET subcnt=subcnt+? WHERE tenant_id=? AND name=?", len(subs), id, topic); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_topics SET subcnt=subcnt+? WHERE tenant_id=? AND name=?"), len(subs), id, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1563,11 +1565,7 @@ func groupMessageDeleteList(tx *sqlx.Tx, tenantID t.TenantID, topic string, toDe
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, err = tx.Exec("DELETE FROM im_group_message_topic_shards WHERE tenant_id=? AND topic=?", tenantID, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec("DELETE FROM im_group_message_dedup WHERE tenant_id=? AND topic=?", tenantID, topic)
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
delRanges := toDel.SeqIdRanges
|
||||
if toDel.DeletedFor == "" {
|
||||
@@ -1659,7 +1657,7 @@ func (a *adapter) TenantTopicDelete(id t.TenantID, topic string, isChan, hard bo
|
||||
}
|
||||
}()
|
||||
if hard {
|
||||
q, args, _ := sqlx.In("DELETE FROM im_subscriptions WHERE tenant_id=? AND topic IN (?)", id, topics)
|
||||
q, args, _ := sqlx.In(tenantShardSQL(id, "DELETE FROM im_subscriptions WHERE tenant_id=? AND topic IN (?)"), id, topics)
|
||||
if _, err = tx.Exec(tx.Rebind(q), args...); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1674,16 +1672,16 @@ func (a *adapter) TenantTopicDelete(id t.TenantID, topic string, isChan, hard bo
|
||||
if _, err = tx.Exec("DELETE FROM im_topictags WHERE tenant_id=? AND topic=?", id, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("DELETE FROM im_topics WHERE tenant_id=? AND name=?", id, topic); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "DELETE FROM im_topics WHERE tenant_id=? AND name=?"), id, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
now := t.TimeNow()
|
||||
q, args, _ := sqlx.In("UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic IN (?)", now, now, id, topics)
|
||||
q, args, _ := sqlx.In(tenantShardSQL(id, "UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic IN (?)"), now, now, id, topics)
|
||||
if _, err = tx.Exec(tx.Rebind(q), args...); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec("UPDATE im_topics SET updatedat=?,touchedat=?,state=?,stateat=? WHERE tenant_id=? AND name=?",
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_topics SET updatedat=?,touchedat=?,state=?,stateat=? WHERE tenant_id=? AND name=?"),
|
||||
now, now, t.StateDeleted, now, id, topic); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1706,7 +1704,7 @@ func (a *adapter) TenantTopicUpdateOnMessage(id t.TenantID, topic string, msg *t
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
_, err = a.db.ExecContext(ctx, "UPDATE im_topics SET seqid=?,touchedat=? WHERE tenant_id=? AND name=?",
|
||||
_, err = a.db.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET seqid=?,touchedat=? WHERE tenant_id=? AND name=?"),
|
||||
msg.SeqId, msg.CreatedAt, id, topic)
|
||||
return err
|
||||
}
|
||||
@@ -1727,7 +1725,7 @@ func (a *adapter) TenantTopicUpdateSubCnt(id t.TenantID, topic string) error {
|
||||
defer cancel()
|
||||
}
|
||||
_, err = a.db.ExecContext(ctx,
|
||||
"UPDATE im_topics SET subcnt=(SELECT COUNT(*) FROM im_subscriptions WHERE tenant_id=? AND topic IN (?,?) AND deletedat IS NULL) WHERE tenant_id=? AND name=?",
|
||||
tenantShardSQL(id, "UPDATE im_topics SET subcnt=(SELECT COUNT(*) FROM im_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
|
||||
}
|
||||
@@ -1761,7 +1759,7 @@ func (a *adapter) TenantTopicUpdate(id t.TenantID, topic string, update map[stri
|
||||
}
|
||||
cols, args := common.UpdateByMap(update)
|
||||
args = append(args, id, topic)
|
||||
res, err := tx.Exec("UPDATE im_topics SET "+strings.Join(cols, ",")+" WHERE tenant_id=? AND name=?", args...)
|
||||
res, err := tx.Exec(tenantShardSQL(id, "UPDATE im_topics SET "+strings.Join(cols, ",")+" WHERE tenant_id=? AND name=?"), args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1813,6 +1811,7 @@ func (a *adapter) TenantTopicBumpMutationVersion(id t.TenantID, topic string, at
|
||||
query = "SELECT mutation_version FROM im_topics WHERE tenant_id=? AND name=?"
|
||||
args = []any{id, topic}
|
||||
}
|
||||
query = tenantShardSQL(id, query)
|
||||
if err = tx.GetContext(ctx, &version, query, args...); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -1837,7 +1836,7 @@ func (a *adapter) TenantTopicOwnerChange(id t.TenantID, topic string, owner t.Ui
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
_, err = a.db.ExecContext(ctx, "UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?", decodeUID(owner), id, topic)
|
||||
_, err = a.db.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?"), decodeUID(owner), id, topic)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1858,6 +1857,7 @@ func (a *adapter) TenantSubscriptionGet(id t.TenantID, topic string, uid t.Uid,
|
||||
}
|
||||
query := `SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
|
||||
readseqid,modewant,modegiven,private FROM im_subscriptions WHERE tenant_id=? AND topic=? AND userid=?`
|
||||
query = tenantShardSQL(id, query)
|
||||
if !keepDeleted {
|
||||
query += " AND deletedat IS NULL"
|
||||
}
|
||||
@@ -1890,8 +1890,8 @@ func (a *adapter) TenantSubsForUser(id t.TenantID, uid t.Uid) ([]t.Subscription,
|
||||
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 im_subscriptions WHERE tenant_id=? AND userid=? AND deletedat IS NULL`,
|
||||
rows, err := a.db.Queryx(tenantShardSQL(id, `SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
|
||||
readseqid,modewant,modegiven FROM im_subscriptions WHERE tenant_id=? AND userid=? AND deletedat IS NULL`),
|
||||
id, decodeUID(uid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1923,6 +1923,7 @@ func (a *adapter) TenantSubsForTopic(id t.TenantID, topic string, keepDeleted bo
|
||||
}
|
||||
q := `SELECT tenant_id,createdat,updatedat,deletedat,userid AS user,topic,delid,recvseqid,
|
||||
readseqid,modewant,modegiven,private FROM im_subscriptions WHERE tenant_id=? AND topic=?`
|
||||
q = tenantShardSQL(id, q)
|
||||
args := []any{id, topic}
|
||||
if !keepDeleted {
|
||||
q += " AND deletedat IS NULL"
|
||||
@@ -1976,7 +1977,7 @@ func (a *adapter) TenantSubsUpdate(id t.TenantID, topic string, uid t.Uid, updat
|
||||
return a.SubsUpdate(topic, uid, update)
|
||||
}
|
||||
cols, args := common.UpdateByMap(update)
|
||||
q := "UPDATE im_subscriptions SET " + strings.Join(cols, ",") + " WHERE tenant_id=? AND topic=?"
|
||||
q := tenantShardSQL(id, "UPDATE im_subscriptions SET ") + strings.Join(cols, ",") + " WHERE tenant_id=? AND topic=?"
|
||||
args = append(args, id, topic)
|
||||
if !uid.IsZero() {
|
||||
q += " AND userid=?"
|
||||
@@ -2016,7 +2017,7 @@ func (a *adapter) TenantSubsDelete(id t.TenantID, topic string, uid t.Uid) error
|
||||
}()
|
||||
now := t.TimeNow()
|
||||
decoded := decodeUID(uid)
|
||||
res, err := tx.Exec("UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic=? AND userid=? AND deletedat IS NULL",
|
||||
res, err := tx.Exec(tenantShardSQL(id, "UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND topic=? AND userid=? AND deletedat IS NULL"),
|
||||
now, now, id, topic, decoded)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -2030,7 +2031,7 @@ func (a *adapter) TenantSubsDelete(id t.TenantID, topic string, uid t.Uid) error
|
||||
}
|
||||
}
|
||||
if t.GetTopicCat(topic) == t.TopicCatGrp {
|
||||
if _, err = tx.Exec("UPDATE im_topics SET subcnt=subcnt-1 WHERE tenant_id=? AND name=?", id, t.ChnToGrp(topic)); err != nil {
|
||||
if _, err = tx.Exec(tenantShardSQL(id, "UPDATE im_topics SET subcnt=subcnt-1 WHERE tenant_id=? AND name=?"), id, t.ChnToGrp(topic)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -2038,7 +2039,7 @@ func (a *adapter) TenantSubsDelete(id t.TenantID, topic string, uid t.Uid) error
|
||||
}
|
||||
|
||||
func tenantSubsDelForUser(tx *sqlx.Tx, tenantID t.TenantID, decodedUID int64, hard bool) error {
|
||||
rows, err := tx.Query("SELECT topic FROM im_subscriptions WHERE tenant_id=? AND userid=? AND deletedat IS NULL", tenantID, decodedUID)
|
||||
rows, err := tx.Query(tenantShardSQL(tenantID, "SELECT topic FROM im_subscriptions WHERE tenant_id=? AND userid=? AND deletedat IS NULL"), tenantID, decodedUID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2060,16 +2061,16 @@ func tenantSubsDelForUser(tx *sqlx.Tx, tenantID t.TenantID, decodedUID int64, ha
|
||||
return err
|
||||
}
|
||||
if len(topics) > 0 {
|
||||
q, args, _ := sqlx.In("UPDATE im_topics SET subcnt=subcnt-1 WHERE tenant_id=? AND name IN (?)", tenantID, topics)
|
||||
q, args, _ := sqlx.In(tenantShardSQL(tenantID, "UPDATE im_topics SET subcnt=subcnt-1 WHERE tenant_id=? AND name IN (?)"), tenantID, topics)
|
||||
if _, err = tx.Exec(tx.Rebind(q), args...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if hard {
|
||||
_, err = tx.Exec("DELETE FROM im_subscriptions WHERE tenant_id=? AND userid=?", tenantID, decodedUID)
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "DELETE FROM im_subscriptions WHERE tenant_id=? AND userid=?"), tenantID, decodedUID)
|
||||
} else {
|
||||
now := t.TimeNow()
|
||||
_, err = tx.Exec("UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND userid=? AND deletedat IS NULL",
|
||||
_, err = tx.Exec(tenantShardSQL(tenantID, "UPDATE im_subscriptions SET updatedat=?,deletedat=? WHERE tenant_id=? AND userid=? AND deletedat IS NULL"),
|
||||
now, now, tenantID, decodedUID)
|
||||
}
|
||||
return err
|
||||
@@ -2111,6 +2112,7 @@ func (a *adapter) TenantFind(id t.TenantID, caller, promoPrefix string, req [][]
|
||||
"FROM im_topics AS t JOIN im_topictags AS tg ON t.tenant_id=tg.tenant_id AND t.name=tg.topic " +
|
||||
"WHERE t.tenant_id=? AND " + stateConstraint + "tg.tag IN (?" + strings.Repeat(",?", len(allTags)-1) + ") " +
|
||||
"GROUP BY t.name,t.createdat,t.updatedat,t.usebt,t.access,t.subcnt,t.public,t.trusted,t.tags "
|
||||
query = tenantShardSQL(id, query)
|
||||
if len(allReq) > 0 {
|
||||
q, addArgs := common.DisjunctionSql(req, "tg.tag")
|
||||
query += q
|
||||
@@ -2177,8 +2179,8 @@ func (a *adapter) TenantFindOne(id t.TenantID, tag string) (string, error) {
|
||||
defer cancel()
|
||||
}
|
||||
rows, err := a.db.QueryxContext(ctx,
|
||||
"SELECT tp.name AS topic FROM im_topics AS tp LEFT JOIN im_topictags AS tt ON tp.tenant_id=tt.tenant_id AND tp.name=tt.topic "+
|
||||
"WHERE tp.tenant_id=? AND tt.tag=? LIMIT 1", id, tag)
|
||||
tenantShardSQL(id, "SELECT tp.name AS topic FROM im_topics AS tp LEFT JOIN im_topictags AS tt ON tp.tenant_id=tt.tenant_id AND tp.name=tt.topic "+
|
||||
"WHERE tp.tenant_id=? AND tt.tag=? LIMIT 1"), id, tag)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -2273,17 +2275,6 @@ func (a *adapter) TenantGroupMessageSave(id t.TenantID, msg *t.Message) error {
|
||||
}
|
||||
defer tx.Rollback()
|
||||
messageID := store.DecodeUid(msg.Uid())
|
||||
if clientMsgID.Valid {
|
||||
if _, err = tx.ExecContext(ctx, `INSERT INTO im_group_message_dedup
|
||||
(tenant_id,topic,from_user,client_msg_id,seqid,shard_month,message_id,status,expires_at)
|
||||
VALUES(?,?,?,?,?,?,?,'done',?)`, id, msg.Topic, decodeUID(t.ParseUid(msg.From)), clientMsgID,
|
||||
msg.SeqId, msg.ShardMonth, messageID, time.Now().UTC().Add(30*24*time.Hour)); err != nil {
|
||||
if isDupe(err) {
|
||||
return t.ErrDuplicate
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
query := fmt.Sprintf(`INSERT INTO %s
|
||||
(tenant_id,message_id,topic,group_id,seqid,from_user,client_msg_id,msg_type,status,content,head,mentioned_user_ids,mention_all,
|
||||
file_count,content_size,version,created_at,updated_at,content_nonce,key_version)
|
||||
@@ -2298,21 +2289,6 @@ func (a *adapter) TenantGroupMessageSave(id t.TenantID, msg *t.Message) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.ExecContext(ctx, `INSERT INTO im_group_message_topic_shards
|
||||
(tenant_id,topic,shard_month,min_seq,max_seq,message_count,min_created_at,max_created_at)
|
||||
VALUES(?,?,?,?,?,1,?,?) ON DUPLICATE KEY UPDATE
|
||||
min_seq=LEAST(min_seq,VALUES(min_seq)),max_seq=GREATEST(max_seq,VALUES(max_seq)),
|
||||
message_count=message_count+1,min_created_at=LEAST(min_created_at,VALUES(min_created_at)),
|
||||
max_created_at=GREATEST(max_created_at,VALUES(max_created_at))`,
|
||||
id, msg.Topic, msg.ShardMonth, msg.SeqId, msg.SeqId, msg.CreatedAt, msg.CreatedAt); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.ExecContext(ctx, `UPDATE im_group_message_shards SET row_count=row_count+1,
|
||||
min_created_at=IF(min_created_at IS NULL,?,LEAST(min_created_at,?)),
|
||||
max_created_at=IF(max_created_at IS NULL,?,GREATEST(max_created_at,?)) WHERE tenant_id=? AND shard_month=?`,
|
||||
msg.CreatedAt, msg.CreatedAt, msg.CreatedAt, msg.CreatedAt, id, msg.ShardMonth); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
@@ -2366,19 +2342,6 @@ func (a *adapter) TenantGroupMessageGetByClientID(id t.TenantID, topic string, f
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
var seq int64
|
||||
if err = a.db.QueryRowContext(ctx, `SELECT seqid FROM im_group_message_dedup
|
||||
WHERE tenant_id=? AND topic=? AND from_user=? AND client_msg_id=?`, id, topic, decodeUID(from), clientMsgID).Scan(&seq); err == nil {
|
||||
msg, getErr := tenantGroupMessageGetOne(a.db, ctx, id, topic, seq, "")
|
||||
if getErr == nil {
|
||||
return msg, nil
|
||||
}
|
||||
if getErr != sql.ErrNoRows {
|
||||
return nil, getErr
|
||||
}
|
||||
} else if err != sql.ErrNoRows {
|
||||
return nil, err
|
||||
}
|
||||
tables, err := groupMessageTablesForTopic(a.db, ctx, id, topic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -3111,14 +3074,14 @@ func (a *adapter) TenantMessageMutations(id t.TenantID, topic string, uid t.Uid,
|
||||
}
|
||||
var currentVersion int64
|
||||
if a.tenantScopedDB {
|
||||
if err := a.db.GetContext(ctx, ¤tVersion, "SELECT IFNULL(mutation_version,0) FROM im_topics WHERE name=?", topic); err != nil {
|
||||
if err := a.db.GetContext(ctx, ¤tVersion, tenantShardSQL(id, "SELECT IFNULL(mutation_version,0) FROM im_topics WHERE name=?"), topic); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, "", false, 0, t.ErrNotFound
|
||||
}
|
||||
return nil, "", false, 0, err
|
||||
}
|
||||
} else {
|
||||
if err := a.db.GetContext(ctx, ¤tVersion, "SELECT IFNULL(mutation_version,0) FROM im_topics WHERE tenant_id=? AND name=?", id, topic); err != nil {
|
||||
if err := a.db.GetContext(ctx, ¤tVersion, tenantShardSQL(id, "SELECT IFNULL(mutation_version,0) FROM im_topics WHERE tenant_id=? AND name=?"), id, topic); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, "", false, 0, t.ErrNotFound
|
||||
}
|
||||
@@ -5261,7 +5224,7 @@ func (a *adapter) TenantFileUserHasAccess(id t.TenantID, fid string, uid t.Uid)
|
||||
defer cancel()
|
||||
}
|
||||
var allowed int
|
||||
err = a.db.GetContext(ctx, &allowed, fmt.Sprintf(`
|
||||
err = a.db.GetContext(ctx, &allowed, tenantShardSQL(id, fmt.Sprintf(`
|
||||
SELECT COUNT(*) FROM im_fileuploads AS fu
|
||||
WHERE fu.tenant_id=? AND (fu.id=? OR fu.location=? OR fu.location LIKE ?) AND fu.status=? AND (
|
||||
fu.userid=?
|
||||
@@ -5310,7 +5273,7 @@ func (a *adapter) TenantFileUserHasAccess(id t.TenantID, fid string, uid t.Uid)
|
||||
WHERE (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)),
|
||||
) LIMIT 1`, tenantFriendshipsTable(id), tenantMessagesTable(id))),
|
||||
id, decodeUID(fileID), fileID.String32(), "%/"+fileID.String32(), t.UploadCompleted, decodeUID(uid), decodeUID(uid), decodeUID(uid), t.RelationshipFriend,
|
||||
decodeUID(uid), decodeUID(uid), t.GroupMemberStatusActive, decodeUID(uid), decodeUID(uid),
|
||||
decodeUID(uid), fid, fid)
|
||||
@@ -5379,33 +5342,14 @@ func (a *adapter) TenantVerificationCreate(id t.TenantID, vc *t.VerificationCode
|
||||
return t.ErrMalformed
|
||||
}
|
||||
|
||||
ctx, cancel := a.getContextForTx()
|
||||
ctx, cancel := a.getContext()
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
tx, err := a.db.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
now := t.TimeNow()
|
||||
_, err = tx.ExecContext(ctx,
|
||||
`UPDATE im_verification_codes
|
||||
SET state=?,updated_at=?
|
||||
WHERE tenant_id=? AND scene=? AND phone_hash=? AND state=?`,
|
||||
t.VerificationStateExpired, now, id, vc.Scene, vc.PhoneHash, t.VerificationStatePending)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vc.CreatedAt = now
|
||||
vc.UpdatedAt = now
|
||||
_, err = tx.ExecContext(ctx,
|
||||
_, err := a.db.ExecContext(ctx,
|
||||
`INSERT INTO im_verification_codes
|
||||
(tenant_id,challenge_id,scene,action,phone_hash,phone_mask,target_user,code_hash,state,attempts,max_attempts,
|
||||
expires_at,resend_after,created_at,updated_at)
|
||||
@@ -5418,7 +5362,7 @@ func (a *adapter) TenantVerificationCreate(id t.TenantID, vc *t.VerificationCode
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *adapter) TenantVerificationGet(id t.TenantID, challengeID string) (*t.VerificationCode, error) {
|
||||
@@ -5854,23 +5798,10 @@ func (a *adapter) TenantActionTokenCreate(id t.TenantID, token *t.ActionToken) e
|
||||
token.TokenID == "" || token.Action == "" || token.TokenHash == "" || token.ExpiresAt.IsZero() {
|
||||
return t.ErrMalformed
|
||||
}
|
||||
ctx, cancel := a.getContext()
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
now := t.TimeNow()
|
||||
token.CreatedAt = now
|
||||
token.UpdatedAt = now
|
||||
_, err := a.db.ExecContext(ctx,
|
||||
`INSERT INTO im_action_tokens
|
||||
(tenant_id,user_id,token_id,action,target,token_hash,state,expires_at,created_at,updated_at)
|
||||
VALUES(?,?,?,?,?,?,?,?,?,?)`,
|
||||
id, decodeUID(token.UserID), token.TokenID, token.Action, token.Target, token.TokenHash, token.State,
|
||||
token.ExpiresAt, token.CreatedAt, token.UpdatedAt)
|
||||
if isDupe(err) {
|
||||
return t.ErrDuplicate
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *adapter) TenantActionTokenConsume(id t.TenantID, uid t.Uid, token, action, target string, now time.Time) (*t.ActionToken, error) {
|
||||
@@ -5893,50 +5824,7 @@ func (a *adapter) TenantActionTokenConsume(id t.TenantID, uid t.Uid, token, acti
|
||||
if !ok || tokenID == "" || secret == "" {
|
||||
return nil, t.ErrMalformed
|
||||
}
|
||||
tokenHash := securityTokenHash(id, uid, action, target, tokenID, secret)
|
||||
ctx, cancel := a.getContextForTx()
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
tx, err := a.db.BeginTxx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
var at t.ActionToken
|
||||
err = tx.GetContext(ctx, &at,
|
||||
`SELECT id,user_id,token_id,action,target,token_hash,state,expires_at,consumed_at,created_at,updated_at
|
||||
FROM im_action_tokens
|
||||
WHERE tenant_id=? AND user_id=? AND token_id=? AND action=? AND target=? LIMIT 1`,
|
||||
id, decodeUID(uid), tokenID, action, target)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, t.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if at.State != 0 || at.TokenHash != tokenHash || !now.Before(at.ExpiresAt) {
|
||||
return nil, t.ErrNotFound
|
||||
}
|
||||
res, err := tx.ExecContext(ctx,
|
||||
`UPDATE im_action_tokens SET state=1,consumed_at=?,updated_at=?
|
||||
WHERE tenant_id=? AND user_id=? AND token_id=? AND action=? AND target=? AND state=0 AND expires_at>?`,
|
||||
now, now, id, decodeUID(uid), tokenID, action, target, now)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rows, _ := res.RowsAffected(); rows == 0 {
|
||||
return nil, t.ErrNotFound
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
at.TenantID = id
|
||||
return &at, nil
|
||||
return nil, t.ErrUnsupported
|
||||
}
|
||||
|
||||
func (a *adapter) TenantIndependentPasswordGet(id t.TenantID, uid t.Uid, purpose string) (*t.IndependentPassword, error) {
|
||||
@@ -6166,7 +6054,7 @@ func (a *adapter) TenantSystemNotificationCreate(id t.TenantID, notification *t.
|
||||
notification.CreatedAt = now
|
||||
notification.UpdatedAt = now
|
||||
_, err := a.db.ExecContext(ctx,
|
||||
`INSERT INTO im_system_notifications
|
||||
tenantShardSQL(id, `INSERT INTO im_system_notifications
|
||||
(tenant_id,user_id,event_id,event_type,title,summary,action,read_at,created_at,updated_at)
|
||||
VALUES(?,?,?,?,?,?,?,?,?,?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
@@ -6174,7 +6062,7 @@ func (a *adapter) TenantSystemNotificationCreate(id t.TenantID, notification *t.
|
||||
title=VALUES(title),
|
||||
summary=VALUES(summary),
|
||||
action=VALUES(action),
|
||||
updated_at=VALUES(updated_at)`,
|
||||
updated_at=VALUES(updated_at)`),
|
||||
id, decodeUID(notification.UserID), notification.EventID, notification.EventType, notification.Title,
|
||||
notification.Summary, common.ToJSON(notification.Action), notification.ReadAt, notification.CreatedAt, notification.UpdatedAt)
|
||||
return err
|
||||
@@ -6207,6 +6095,7 @@ func (a *adapter) TenantSystemNotificationList(id t.TenantID, uid t.Uid, cursor
|
||||
query := `SELECT id,user_id,event_id,event_type,title,summary,action,read_at,created_at,updated_at
|
||||
FROM im_system_notifications
|
||||
WHERE tenant_id=? AND user_id=?`
|
||||
query = tenantShardSQL(id, query)
|
||||
args := []any{id, decodeUID(uid)}
|
||||
if lastID > 0 {
|
||||
query += " AND id<?"
|
||||
@@ -6265,7 +6154,7 @@ func (a *adapter) TenantSystemNotificationUnreadCount(id t.TenantID, uid t.Uid)
|
||||
}
|
||||
var count int
|
||||
if err := a.db.GetContext(ctx, &count,
|
||||
`SELECT COUNT(*) FROM im_system_notifications WHERE tenant_id=? AND user_id=? AND read_at IS NULL`,
|
||||
tenantShardSQL(id, `SELECT COUNT(*) FROM im_system_notifications WHERE tenant_id=? AND user_id=? AND read_at IS NULL`),
|
||||
id, decodeUID(uid)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -6292,25 +6181,25 @@ func (a *adapter) TenantSystemNotificationUnreadCountByEventPrefix(id t.TenantID
|
||||
}
|
||||
var count int
|
||||
if err := a.db.GetContext(ctx, &count,
|
||||
`SELECT COUNT(*) FROM im_system_notifications WHERE tenant_id=? AND user_id=? AND read_at IS NULL AND event_type LIKE ?`,
|
||||
tenantShardSQL(id, `SELECT COUNT(*) FROM im_system_notifications WHERE tenant_id=? AND user_id=? AND read_at IS NULL AND event_type LIKE ?`),
|
||||
id, decodeUID(uid), eventPrefix+"%"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (a *adapter) TenantSystemNotificationMarkRead(id t.TenantID, uid t.Uid, eventID string, readAt time.Time) error {
|
||||
func (a *adapter) TenantSystemNotificationMarkRead(id t.TenantID, uid t.Uid, eventID string, readAt time.Time) (*t.SystemNotification, error) {
|
||||
if !a.tenantScopedDB {
|
||||
tenantAdp, err := a.routedTenantAdapter(id)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if tenantAdp != a {
|
||||
return tenantAdp.TenantSystemNotificationMarkRead(id, uid, eventID, readAt)
|
||||
}
|
||||
}
|
||||
if err := validTenant(id); err != nil || uid.IsZero() || eventID == "" {
|
||||
return t.ErrMalformed
|
||||
return nil, t.ErrMalformed
|
||||
}
|
||||
if readAt.IsZero() {
|
||||
readAt = t.TimeNow()
|
||||
@@ -6319,18 +6208,38 @@ func (a *adapter) TenantSystemNotificationMarkRead(id t.TenantID, uid t.Uid, eve
|
||||
if cancel != nil {
|
||||
defer cancel()
|
||||
}
|
||||
res, err := a.db.ExecContext(ctx,
|
||||
`UPDATE im_system_notifications
|
||||
SET read_at=?,updated_at=?
|
||||
WHERE tenant_id=? AND user_id=? AND event_id=?`,
|
||||
_, err := a.db.ExecContext(ctx,
|
||||
tenantShardSQL(id, `UPDATE im_system_notifications
|
||||
SET read_at=COALESCE(read_at,?),updated_at=?
|
||||
WHERE tenant_id=? AND user_id=? AND event_id=?`),
|
||||
readAt, readAt, id, decodeUID(uid), eventID)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if rows, _ := res.RowsAffected(); rows == 0 {
|
||||
return t.ErrNotFound
|
||||
notification, err := a.tenantSystemNotificationGet(ctx, id, uid, eventID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil
|
||||
return notification, nil
|
||||
}
|
||||
|
||||
func (a *adapter) tenantSystemNotificationGet(ctx context.Context, id t.TenantID, uid t.Uid, eventID string) (*t.SystemNotification, error) {
|
||||
var notification t.SystemNotification
|
||||
err := a.db.QueryRowxContext(ctx, tenantShardSQL(id, `SELECT id,user_id,event_id,event_type,title,summary,action,read_at,created_at,updated_at
|
||||
FROM im_system_notifications
|
||||
WHERE tenant_id=? AND user_id=? AND event_id=?`),
|
||||
id, decodeUID(uid), eventID).StructScan(¬ification)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, t.ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if action, ok := common.FromJSON(notification.Action).(map[string]any); ok {
|
||||
notification.Action = t.KVMap(action)
|
||||
}
|
||||
notification.TenantID = id
|
||||
return ¬ification, nil
|
||||
}
|
||||
|
||||
func (a *adapter) TenantFriendRequestCreate(id t.TenantID, req *t.FriendRequest) (*t.FriendRequest, error) {
|
||||
@@ -6705,10 +6614,10 @@ func (a *adapter) TenantFriendRequestAccept(id t.TenantID, requestID string, act
|
||||
targetSub.SetTouchedAt(handledAt)
|
||||
targetSub.SetPublic(applicantUser.Public)
|
||||
targetSub.SetTrusted(applicantUser.Trusted)
|
||||
if err = createSubscription(tx, applicantSub, true); err != nil {
|
||||
if err = createTenantSubscription(tx, id, applicantSub, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = createSubscription(tx, targetSub, true); err != nil {
|
||||
if err = createTenantSubscription(tx, id, targetSub, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
topicRow := &t.Topic{TenantID: id, ObjHeader: t.ObjHeader{Id: topic, CreatedAt: handledAt, UpdatedAt: handledAt}, TouchedAt: handledAt}
|
||||
@@ -6721,7 +6630,7 @@ func (a *adapter) TenantFriendRequestAccept(id t.TenantID, requestID string, act
|
||||
if !isDupe(err) {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = tx.ExecContext(ctx, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE tenant_id=? AND name=?",
|
||||
if _, err = tx.ExecContext(ctx, tenantShardSQL(id, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE tenant_id=? AND name=?"),
|
||||
handledAt, handledAt, t.StateOK, id, topic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user