Add various deleted flags to entities | Add active to subscriptions | Add DeleteUser && DeleteChannel endpoints [skip-tests]
This commit is contained in:
@@ -182,7 +182,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
if schemaFrom == schemaTo-1 {
|
||||
|
||||
migSQL := db.schema[schemaTo].MigScript
|
||||
if migSQL == "" {
|
||||
if len(migSQL) == 0 {
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts []string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
|
||||
schemaHashMeta, err := db.ReadMetaString(tctx, "schema_hash")
|
||||
if err != nil {
|
||||
@@ -215,9 +215,13 @@ func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts
|
||||
|
||||
log.Info().Msgf("Upgrade schema from %d -> %d", currSchemaVers, resultSchemVers)
|
||||
|
||||
_, err = tx.Exec(tctx, stmts, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
for i, stmt := range stmts {
|
||||
log.Info().Msgf("SQL-Migration of [%s]: %d/%d", db.name, i+1, len(stmts))
|
||||
|
||||
_, err := tx.Exec(tctx, stmt, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
schemHashDBAfter, err := sq.HashSqliteDatabase(tctx, tx)
|
||||
|
@@ -13,7 +13,7 @@ func (db *Database) GetChannelByName(ctx db.TxContext, userid models.UserID, cha
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE owner_user_id = :uid AND internal_name = :nam LIMIT 1", sq.PP{"uid": userid, "nam": chanName}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE owner_user_id = :uid AND internal_name = :nam AND deleted=0 LIMIT 1", sq.PP{"uid": userid, "nam": chanName}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) GetChannelByID(ctx db.TxContext, chanid models.ChannelID) (*models.Channel, error) {
|
||||
@@ -22,7 +22,7 @@ func (db *Database) GetChannelByID(ctx db.TxContext, chanid models.ChannelID) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE channel_id = :cid LIMIT 1", sq.PP{"cid": chanid}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE channel_id = :cid AND deleted=0 LIMIT 1", sq.PP{"cid": chanid}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
type CreateChanel struct {
|
||||
@@ -49,6 +49,7 @@ func (db *Database) CreateChannel(ctx db.TxContext, userid models.UserID, dispNa
|
||||
TimestampCreated: models.NowSCNTime(),
|
||||
TimestampLastSent: nil,
|
||||
MessagesSent: 0,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "channels", entity)
|
||||
@@ -67,7 +68,7 @@ func (db *Database) ListChannelsByOwner(ctx db.TxContext, userid models.UserID,
|
||||
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
sql := "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub ON channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid" + order
|
||||
sql := "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub ON channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE channels.deleted=0 AND owner_user_id = :ouid" + order
|
||||
|
||||
pp := sq.PP{
|
||||
"ouid": userid,
|
||||
@@ -90,9 +91,11 @@ func (db *Database) ListChannelsBySubscriber(ctx db.TxContext, userid models.Use
|
||||
confCond = " AND sub.confirmed = 0"
|
||||
}
|
||||
|
||||
cond := "channels.deleted=0 AND sub.subscription_id IS NOT NULL " + confCond
|
||||
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
sql := "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE sub.subscription_id IS NOT NULL " + confCond + order
|
||||
sql := "SELECT channels.*, sub.* " + "FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid AND sub.deleted=0 WHERE " + cond + order
|
||||
|
||||
pp := sq.PP{
|
||||
"subuid": userid,
|
||||
@@ -114,9 +117,11 @@ func (db *Database) ListChannelsByAccess(ctx db.TxContext, userid models.UserID,
|
||||
confCond = "OR (sub.subscription_id IS NOT NULL AND sub.confirmed = 0)"
|
||||
}
|
||||
|
||||
cond := "channels.deleted=0 AND (owner_user_id = :ouid " + confCond + ")"
|
||||
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
sql := "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid " + confCond + order
|
||||
sql := "SELECT channels.*, sub.* " + "FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid AND sub.deleted=0 WHERE " + cond + order
|
||||
|
||||
pp := sq.PP{
|
||||
"ouid": userid,
|
||||
@@ -139,13 +144,14 @@ func (db *Database) GetChannel(ctx db.TxContext, userid models.UserID, channelid
|
||||
|
||||
selectors := "channels.*, sub.*"
|
||||
|
||||
join := "LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid"
|
||||
join := "LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid AND sub.deleted=0"
|
||||
|
||||
cond := "channels.channel_id = :cid"
|
||||
if enforceOwner {
|
||||
cond = "owner_user_id = :ouid AND channels.channel_id = :cid"
|
||||
params["ouid"] = userid
|
||||
}
|
||||
cond += " AND channels.deleted=0"
|
||||
|
||||
sql := "SELECT " + selectors + " FROM channels " + join + " WHERE " + cond + " LIMIT 1"
|
||||
|
||||
@@ -160,7 +166,7 @@ func (db *Database) IncChannelMessageCounter(ctx db.TxContext, channel *models.C
|
||||
|
||||
now := time.Now()
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET messages_sent = messages_sent+1, timestamp_lastsent = :ts WHERE channel_id = :cid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET messages_sent = messages_sent+1, timestamp_lastsent = :ts WHERE channel_id = :cid AND deleted=0", sq.PP{
|
||||
"ts": time2DB(now),
|
||||
"cid": channel.ChannelID,
|
||||
})
|
||||
@@ -180,7 +186,7 @@ func (db *Database) UpdateChannelSubscribeKey(ctx db.TxContext, channelid models
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET subscribe_key = :key WHERE channel_id = :cid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET subscribe_key = :key WHERE channel_id = :cid AND deleted=0", sq.PP{
|
||||
"key": newkey,
|
||||
"cid": channelid,
|
||||
})
|
||||
@@ -197,7 +203,7 @@ func (db *Database) UpdateChannelDisplayName(ctx db.TxContext, channelid models.
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET display_name = :nam WHERE channel_id = :cid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET display_name = :nam WHERE channel_id = :cid AND deleted=0", sq.PP{
|
||||
"nam": dispname,
|
||||
"cid": channelid,
|
||||
})
|
||||
@@ -214,7 +220,7 @@ func (db *Database) UpdateChannelDescriptionName(ctx db.TxContext, channelid mod
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET description_name = :nam WHERE channel_id = :cid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET description_name = :nam WHERE channel_id = :cid AND deleted=0", sq.PP{
|
||||
"nam": descname,
|
||||
"cid": channelid,
|
||||
})
|
||||
@@ -224,3 +230,31 @@ func (db *Database) UpdateChannelDescriptionName(ctx db.TxContext, channelid mod
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteChannelsOfUser(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET deleted=1 WHERE owner_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteChannel(ctx db.TxContext, channelid models.ChannelID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE channels SET deleted=1 WHERE channel_id = :cid AND deleted=0", sq.PP{"cid": channelid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ func (db *Database) CreateClient(ctx db.TxContext, userid models.UserID, ctype m
|
||||
AgentModel: agentModel,
|
||||
AgentVersion: agentVersion,
|
||||
Name: name,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "clients", entity)
|
||||
@@ -159,3 +160,17 @@ func (db *Database) UpdateClientDescriptionName(ctx db.TxContext, clientid model
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteClientsOfUser(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE clients SET deleted=1 WHERE user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -182,7 +182,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
if schemaFrom == schemaTo-1 {
|
||||
|
||||
migSQL := db.schema[schemaTo].MigScript
|
||||
if migSQL == "" {
|
||||
if len(migSQL) == 0 {
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts []string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
|
||||
schemaHashMeta, err := db.ReadMetaString(tctx, "schema_hash")
|
||||
if err != nil {
|
||||
@@ -215,9 +215,13 @@ func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts
|
||||
|
||||
log.Info().Msgf("Upgrade schema from %d -> %d", currSchemaVers, resultSchemVers)
|
||||
|
||||
_, err = tx.Exec(tctx, stmts, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
for i, stmt := range stmts {
|
||||
log.Info().Msgf("SQL-Migration of [%s]: %d/%d", db.name, i+1, len(stmts))
|
||||
|
||||
_, err := tx.Exec(tctx, stmt, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
schemHashDBAfter, err := sq.HashSqliteDatabase(tctx, tx)
|
||||
|
@@ -29,6 +29,7 @@ func (db *Database) CreateRetryDelivery(ctx db.TxContext, client models.Client,
|
||||
RetryCount: 0,
|
||||
NextDelivery: models.NewSCNTimePtr(&next),
|
||||
FCMMessageID: nil,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "deliveries", entity)
|
||||
@@ -58,6 +59,7 @@ func (db *Database) CreateSuccessDelivery(ctx db.TxContext, client models.Client
|
||||
RetryCount: 0,
|
||||
NextDelivery: nil,
|
||||
FCMMessageID: langext.Ptr(fcmDelivID),
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "deliveries", entity)
|
||||
@@ -74,7 +76,7 @@ func (db *Database) ListRetrieableDeliveries(ctx db.TxContext, pageSize int) ([]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QueryAll[models.Delivery](ctx, tx, "SELECT * FROM deliveries WHERE status = 'RETRY' AND next_delivery < :next ORDER BY next_delivery ASC LIMIT :lim", sq.PP{
|
||||
return sq.QueryAll[models.Delivery](ctx, tx, "SELECT * FROM deliveries WHERE status = 'RETRY' AND next_delivery < :next AND deleted=0 ORDER BY next_delivery ASC LIMIT :lim", sq.PP{
|
||||
"next": time2DB(time.Now()),
|
||||
"lim": pageSize,
|
||||
}, sq.SModeExtended, sq.Safe)
|
||||
@@ -86,7 +88,7 @@ func (db *Database) SetDeliverySuccess(ctx db.TxContext, delivery models.Deliver
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'SUCCESS', next_delivery = NULL, retry_count = :rc, timestamp_finalized = :ts, fcm_message_id = :fcm WHERE delivery_id = :did", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'SUCCESS', next_delivery = NULL, retry_count = :rc, timestamp_finalized = :ts, fcm_message_id = :fcm WHERE delivery_id = :did AND deleted=0", sq.PP{
|
||||
"rc": delivery.RetryCount + 1,
|
||||
"ts": time2DB(time.Now()),
|
||||
"fcm": fcmDelivID,
|
||||
@@ -105,7 +107,7 @@ func (db *Database) SetDeliveryFailed(ctx db.TxContext, delivery models.Delivery
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, retry_count = :rc, timestamp_finalized = :ts WHERE delivery_id = :did",
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, retry_count = :rc, timestamp_finalized = :ts WHERE delivery_id = :did AND deleted=0",
|
||||
sq.PP{
|
||||
"rc": delivery.RetryCount + 1,
|
||||
"ts": time2DB(time.Now()),
|
||||
@@ -124,7 +126,7 @@ func (db *Database) SetDeliveryRetry(ctx db.TxContext, delivery models.Delivery)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'RETRY', next_delivery = :next, retry_count = :rc WHERE delivery_id = :did", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'RETRY', next_delivery = :next, retry_count = :rc WHERE delivery_id = :did AND deleted=0", sq.PP{
|
||||
"next": time2DB(scn.NextDeliveryTimestamp(time.Now())),
|
||||
"rc": delivery.RetryCount + 1,
|
||||
"did": delivery.DeliveryID,
|
||||
@@ -142,7 +144,7 @@ func (db *Database) CancelPendingDeliveries(ctx db.TxContext, messageID models.M
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, timestamp_finalized = :ts WHERE message_id = :mid AND status = 'RETRY'", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, timestamp_finalized = :ts WHERE message_id = :mid AND status = 'RETRY' AND deleted=0", sq.PP{
|
||||
"ts": time.Now(),
|
||||
"mid": messageID,
|
||||
})
|
||||
@@ -152,3 +154,31 @@ func (db *Database) CancelPendingDeliveries(ctx db.TxContext, messageID models.M
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteDeliveriesOfUser(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET deleted=1 WHERE receiver_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteDeliveriesOfChannel(ctx db.TxContext, channelid models.ChannelID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET deleted=1 WHERE (SELECT channel_id FROM messages WHERE messages.message_id = deliveries.message_id) = :cid AND deleted=0", sq.PP{"cid": channelid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ func (db *Database) CreateKeyToken(ctx db.TxContext, name string, owner models.U
|
||||
Token: token,
|
||||
Permissions: permissions,
|
||||
MessagesSent: 0,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "keytokens", entity)
|
||||
@@ -42,7 +43,7 @@ func (db *Database) ListKeyTokens(ctx db.TxContext, ownerID models.UserID) ([]mo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QueryAll[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE owner_user_id = :uid ORDER BY keytokens.timestamp_created DESC, keytokens.keytoken_id ASC", sq.PP{"uid": ownerID}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QueryAll[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE owner_user_id = :uid AND deleted=0 ORDER BY keytokens.timestamp_created DESC, keytokens.keytoken_id ASC", sq.PP{"uid": ownerID}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) GetKeyToken(ctx db.TxContext, userid models.UserID, keyTokenid models.KeyTokenID) (models.KeyToken, error) {
|
||||
@@ -51,7 +52,7 @@ func (db *Database) GetKeyToken(ctx db.TxContext, userid models.UserID, keyToken
|
||||
return models.KeyToken{}, err
|
||||
}
|
||||
|
||||
return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE owner_user_id = :uid AND keytoken_id = :cid LIMIT 1", sq.PP{
|
||||
return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE owner_user_id = :uid AND keytoken_id = :cid AND deleted=0 LIMIT 1", sq.PP{
|
||||
"uid": userid,
|
||||
"cid": keyTokenid,
|
||||
}, sq.SModeExtended, sq.Safe)
|
||||
@@ -63,7 +64,7 @@ func (db *Database) GetKeyTokenByID(ctx db.TxContext, keyTokenid models.KeyToken
|
||||
return models.KeyToken{}, err
|
||||
}
|
||||
|
||||
return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE keytoken_id = :cid LIMIT 1", sq.PP{"cid": keyTokenid}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE keytoken_id = :cid AND deleted=0 LIMIT 1", sq.PP{"cid": keyTokenid}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) GetKeyTokenByToken(ctx db.TxContext, key string) (*models.KeyToken, error) {
|
||||
@@ -72,7 +73,7 @@ func (db *Database) GetKeyTokenByToken(ctx db.TxContext, key string) (*models.Ke
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE token = :key LIMIT 1", sq.PP{"key": key}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingleOpt[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE token = :key AND deleted=0 LIMIT 1", sq.PP{"key": key}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) DeleteKeyToken(ctx db.TxContext, keyTokenid models.KeyTokenID) error {
|
||||
@@ -81,7 +82,7 @@ func (db *Database) DeleteKeyToken(ctx db.TxContext, keyTokenid models.KeyTokenI
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "DELETE FROM keytokens WHERE keytoken_id = :tid", sq.PP{"tid": keyTokenid})
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET deleted=1 WHERE keytoken_id = :tid AND deleted=0", sq.PP{"tid": keyTokenid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -95,7 +96,7 @@ func (db *Database) UpdateKeyTokenName(ctx db.TxContext, keyTokenid models.KeyTo
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET name = :nam WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET name = :nam WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"nam": name,
|
||||
"tid": keyTokenid,
|
||||
})
|
||||
@@ -112,7 +113,7 @@ func (db *Database) UpdateKeyTokenPermissions(ctx db.TxContext, keyTokenid model
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET permissions = :prm WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET permissions = :prm WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"tid": keyTokenid,
|
||||
"prm": perm.String(),
|
||||
})
|
||||
@@ -129,7 +130,7 @@ func (db *Database) UpdateKeyTokenAllChannels(ctx db.TxContext, keyTokenid model
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET all_channels = :all WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET all_channels = :all WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"tid": keyTokenid,
|
||||
"all": bool2DB(allChannels),
|
||||
})
|
||||
@@ -146,7 +147,7 @@ func (db *Database) UpdateKeyTokenChannels(ctx db.TxContext, keyTokenid models.K
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET channels = :cha WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET channels = :cha WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"tid": keyTokenid,
|
||||
"cha": strings.Join(langext.ArrMap(channels, func(v models.ChannelID) string { return v.String() }), ";"),
|
||||
})
|
||||
@@ -165,7 +166,7 @@ func (db *Database) IncKeyTokenMessageCounter(ctx db.TxContext, keyToken *models
|
||||
|
||||
now := time.Now()
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET messages_sent = messages_sent+1, timestamp_lastused = :ts WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET messages_sent = messages_sent+1, timestamp_lastused = :ts WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"ts": time2DB(now),
|
||||
"tid": keyToken.KeyTokenID,
|
||||
})
|
||||
@@ -185,7 +186,7 @@ func (db *Database) UpdateKeyTokenLastUsed(ctx db.TxContext, keyTokenid models.K
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET timestamp_lastused = :ts WHERE keytoken_id = :tid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET timestamp_lastused = :ts WHERE keytoken_id = :tid AND deleted=0", sq.PP{
|
||||
"ts": time2DB(time.Now()),
|
||||
"tid": keyTokenid,
|
||||
})
|
||||
@@ -195,3 +196,46 @@ func (db *Database) UpdateKeyTokenLastUsed(ctx db.TxContext, keyTokenid models.K
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteKeyTokensOfUser(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET deleted=1 WHERE owner_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteChannelFromKeyTokens(ctx db.TxContext, channelid models.ChannelID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tok, err := sq.QueryAll[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE instr(channels, :cid) AND deleted=0", sq.PP{"cid": channelid}, sq.SModeExtended, sq.Safe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, t := range tok {
|
||||
|
||||
newChanList := models.ChannelIDArr(langext.ArrRemove(t.Channels, channelid))
|
||||
|
||||
chanListDB, err := newChanList.MarshalToDB(newChanList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE keytokens SET channels=:clist WHERE owner_user_id = :uid AND deleted=0", sq.PP{"clist": chanListDB})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ func (db *Database) GetMessageByUserMessageID(ctx db.TxContext, usrMsgId string)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.Message](ctx, tx, "SELECT * FROM messages WHERE usr_message_id = :umid LIMIT 1", sq.PP{"umid": usrMsgId}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingleOpt[models.Message](ctx, tx, "SELECT * FROM messages WHERE usr_message_id = :umid LIMIT 1", sq.PP{"umid": usrMsgId}, sq.SModeExtended, sq.Safe) // no deleted=0 check!
|
||||
}
|
||||
|
||||
func (db *Database) GetMessage(ctx db.TxContext, scnMessageID models.MessageID, allowDeleted bool) (models.Message, error) {
|
||||
@@ -45,6 +45,7 @@ func (db *Database) CreateMessage(ctx db.TxContext, senderUserID models.UserID,
|
||||
SenderUserID: senderUserID,
|
||||
ChannelInternalName: channel.InternalName,
|
||||
ChannelID: channel.ChannelID,
|
||||
ChannelOwnerUserID: channel.OwnerUserID,
|
||||
SenderIP: senderIP,
|
||||
SenderName: senderName,
|
||||
TimestampReal: models.NowSCNTime(),
|
||||
@@ -164,3 +165,45 @@ func (db *Database) CountMessages(ctx db.TxContext, filter models.MessageFilter)
|
||||
|
||||
return countRes, nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMessagesOfUserBySenderUserID(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE messages SET deleted=1 WHERE sender_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMessagesOfUserByChannelOwnerUserID(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE messages SET deleted=1 WHERE channel_owner_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMessagesOfChannel(ctx db.TxContext, channelid models.ChannelID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE messages SET deleted=1 WHERE channel_id = :cid AND deleted=0", sq.PP{"cid": channelid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ func (db *Database) ListSenderNames(ctx db.TxContext, userid models.UserID, incl
|
||||
prepParams := sq.PP{"uid": userid}
|
||||
|
||||
if includeForeignSubscribed {
|
||||
sqlStr = "SELECT sender_name AS name, MAX(timestamp_real) AS ts_last, MIN(timestamp_real) AS ts_first, COUNT(*) AS count FROM messages LEFT JOIN subscriptions AS subs on messages.channel_id = subs.channel_id WHERE (subs.subscriber_user_id = :uid AND subs.confirmed = 1) AND sender_NAME NOT NULL GROUP BY sender_name ORDER BY ts_last DESC"
|
||||
sqlStr = "SELECT sender_name AS name, MAX(timestamp_real) AS ts_last, MIN(timestamp_real) AS ts_first, COUNT(*) AS count FROM messages LEFT JOIN subscriptions AS subs ON messages.channel_id = subs.channel_id AND subs.deleted=0 WHERE (subs.subscriber_user_id = :uid AND subs.confirmed = 1) AND sender_NAME NOT NULL GROUP BY sender_name ORDER BY ts_last DESC"
|
||||
} else {
|
||||
sqlStr = "SELECT sender_name AS name, MAX(timestamp_real) AS ts_last, MIN(timestamp_real) AS ts_first, COUNT(*) AS count FROM messages WHERE sender_user_id = :uid AND sender_NAME NOT NULL GROUP BY sender_name ORDER BY ts_last DESC"
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@ func (db *Database) CreateSubscription(ctx db.TxContext, subscriberUID models.Us
|
||||
ChannelInternalName: channel.InternalName,
|
||||
TimestampCreated: models.NowSCNTime(),
|
||||
Confirmed: confirmed,
|
||||
Active: true,
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
_, err = sq.InsertSingle(ctx, tx, "subscriptions", entity)
|
||||
@@ -40,7 +42,7 @@ func (db *Database) ListSubscriptions(ctx db.TxContext, filter models.Subscripti
|
||||
|
||||
orderClause := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
sqlQuery := "SELECT " + "subscriptions.*" + " FROM subscriptions " + filterJoin + " WHERE ( " + filterCond + " ) " + orderClause
|
||||
sqlQuery := "SELECT " + "subscriptions.*" + " FROM subscriptions " + filterJoin + " WHERE ( " + filterCond + " ) AND subscriptions.deleted=0 " + orderClause
|
||||
|
||||
return sq.QueryAll[models.Subscription](ctx, tx, sqlQuery, prepParams, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
@@ -51,7 +53,7 @@ func (db *Database) GetSubscription(ctx db.TxContext, subid models.SubscriptionI
|
||||
return models.Subscription{}, err
|
||||
}
|
||||
|
||||
return sq.QuerySingle[models.Subscription](ctx, tx, "SELECT * FROM subscriptions WHERE subscription_id = :sid LIMIT 1", sq.PP{"sid": subid}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingle[models.Subscription](ctx, tx, "SELECT * FROM subscriptions WHERE subscription_id = :sid AND deleted=0 LIMIT 1", sq.PP{"sid": subid}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) GetSubscriptionBySubscriber(ctx db.TxContext, subscriberId models.UserID, channelId models.ChannelID) (*models.Subscription, error) {
|
||||
@@ -60,7 +62,7 @@ func (db *Database) GetSubscriptionBySubscriber(ctx db.TxContext, subscriberId m
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.Subscription](ctx, tx, "SELECT * FROM subscriptions WHERE subscriber_user_id = :suid AND channel_id = :cid LIMIT 1", sq.PP{
|
||||
return sq.QuerySingleOpt[models.Subscription](ctx, tx, "SELECT * FROM subscriptions WHERE subscriber_user_id = :suid AND channel_id = :cid AND deleted=0 LIMIT 1", sq.PP{
|
||||
"suid": subscriberId,
|
||||
"cid": channelId,
|
||||
}, sq.SModeExtended, sq.Safe)
|
||||
@@ -72,7 +74,7 @@ func (db *Database) DeleteSubscription(ctx db.TxContext, subid models.Subscripti
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "DELETE FROM subscriptions WHERE subscription_id = :sid", sq.PP{"sid": subid})
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET deleted=1 WHERE subscription_id = :sid AND deleted=0", sq.PP{"sid": subid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -86,7 +88,7 @@ func (db *Database) UpdateSubscriptionConfirmed(ctx db.TxContext, subscriptionID
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET confirmed = :conf WHERE subscription_id = :sid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET confirmed = :conf WHERE subscription_id = :sid AND deleted=0", sq.PP{
|
||||
"conf": confirmed,
|
||||
"sid": subscriptionID,
|
||||
})
|
||||
@@ -96,3 +98,62 @@ func (db *Database) UpdateSubscriptionConfirmed(ctx db.TxContext, subscriptionID
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) UpdateSubscriptionActive(ctx db.TxContext, subscriptionID models.SubscriptionID, active bool) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET active = :act WHERE subscription_id = :sid AND deleted=0", sq.PP{
|
||||
"act": active,
|
||||
"sid": subscriptionID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteSubscriptionsOfUserByChannelOwner(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET deleted=1 WHERE channel_owner_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteSubscriptionsOfUserBySubscriber(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET deleted=1 WHERE subscriber_user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteSubscriptionsByChannel(ctx db.TxContext, channelid models.ChannelID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE subscriptions SET deleted=1 WHERE channel_id = :cid AND deleted=0", sq.PP{"cid": channelid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ func (db *Database) CreateUser(ctx db.TxContext, protoken *string, username *str
|
||||
IsPro: protoken != nil,
|
||||
ProToken: protoken,
|
||||
UserExtra: models.UserExtra{},
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
entity.PreMarshal()
|
||||
@@ -45,7 +46,7 @@ func (db *Database) ClearProTokens(ctx db.TxContext, protoken string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET is_pro=0, pro_token=NULL WHERE pro_token = :tok", sq.PP{"tok": protoken})
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET is_pro=0, pro_token=NULL WHERE pro_token = :tok AND deleted=0", sq.PP{"tok": protoken})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -59,7 +60,7 @@ func (db *Database) GetUser(ctx db.TxContext, userid models.UserID) (models.User
|
||||
return models.User{}, err
|
||||
}
|
||||
|
||||
return sq.QuerySingle[models.User](ctx, tx, "SELECT * FROM users WHERE user_id = :uid LIMIT 1", sq.PP{"uid": userid}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingle[models.User](ctx, tx, "SELECT * FROM users WHERE user_id = :uid AND deleted=0 LIMIT 1", sq.PP{"uid": userid}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) GetUserOpt(ctx db.TxContext, userid models.UserID) (*models.User, error) {
|
||||
@@ -68,7 +69,7 @@ func (db *Database) GetUserOpt(ctx db.TxContext, userid models.UserID) (*models.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sq.QuerySingleOpt[models.User](ctx, tx, "SELECT * FROM users WHERE user_id = :uid LIMIT 1", sq.PP{"uid": userid}, sq.SModeExtended, sq.Safe)
|
||||
return sq.QuerySingleOpt[models.User](ctx, tx, "SELECT * FROM users WHERE user_id = :uid AND deleted=0 LIMIT 1", sq.PP{"uid": userid}, sq.SModeExtended, sq.Safe)
|
||||
}
|
||||
|
||||
func (db *Database) UpdateUserUsername(ctx db.TxContext, userid models.UserID, username *string) error {
|
||||
@@ -77,7 +78,7 @@ func (db *Database) UpdateUserUsername(ctx db.TxContext, userid models.UserID, u
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET username = :nam WHERE user_id = :uid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET username = :nam WHERE user_id = :uid AND deleted=0", sq.PP{
|
||||
"nam": username,
|
||||
"uid": userid,
|
||||
})
|
||||
@@ -94,7 +95,7 @@ func (db *Database) UpdateUserProToken(ctx db.TxContext, userid models.UserID, p
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET pro_token = :tok, is_pro = :pro WHERE user_id = :uid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET pro_token = :tok, is_pro = :pro WHERE user_id = :uid AND deleted=0", sq.PP{
|
||||
"tok": protoken,
|
||||
"pro": bool2DB(protoken != nil),
|
||||
"uid": userid,
|
||||
@@ -119,7 +120,7 @@ func (db *Database) IncUserMessageCounter(ctx db.TxContext, user *models.User) e
|
||||
user.QuotaUsed = quota
|
||||
user.QuotaUsedDay = langext.Ptr(scn.QuotaDayString())
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET timestamp_lastsent = :ts, messages_sent = messages_sent+1, quota_used = :qu, quota_used_day = :qd WHERE user_id = :uid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET timestamp_lastsent = :ts, messages_sent = messages_sent+1, quota_used = :qu, quota_used_day = :qd WHERE user_id = :uid AND deleted=0", sq.PP{
|
||||
"ts": time2DB(now),
|
||||
"qu": user.QuotaUsed,
|
||||
"qd": user.QuotaUsedDay,
|
||||
@@ -141,7 +142,7 @@ func (db *Database) UpdateUserLastRead(ctx db.TxContext, userid models.UserID) e
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET timestamp_lastread = :ts WHERE user_id = :uid", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET timestamp_lastread = :ts WHERE user_id = :uid AND deleted=0", sq.PP{
|
||||
"ts": time2DB(time.Now()),
|
||||
"uid": userid,
|
||||
})
|
||||
@@ -151,3 +152,17 @@ func (db *Database) UpdateUserLastRead(ctx db.TxContext, userid models.UserID) e
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteUser(ctx db.TxContext, userid models.UserID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE users SET deleted=1 WHERE user_id = :uid AND deleted=0", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -182,7 +182,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
if schemaFrom == schemaTo-1 {
|
||||
|
||||
migSQL := db.schema[schemaTo].MigScript
|
||||
if migSQL == "" {
|
||||
if len(migSQL) == 0 {
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ func (db *Database) migrateSingle(tctx *simplectx.SimpleContext, tx sq.Tx, schem
|
||||
return exerr.New(exerr.TypeInternal, fmt.Sprintf("missing %s migration from %d to %d", db.name, schemaFrom, schemaTo)).Build()
|
||||
}
|
||||
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts []string, currSchemaVers int, resultSchemVers int, resultHash string, post func(tctx *simplectx.SimpleContext, tx sq.Tx) error) error {
|
||||
|
||||
schemaHashMeta, err := db.ReadMetaString(tctx, "schema_hash")
|
||||
if err != nil {
|
||||
@@ -215,9 +215,13 @@ func (db *Database) migrateBySQL(tctx *simplectx.SimpleContext, tx sq.Tx, stmts
|
||||
|
||||
log.Info().Msgf("Upgrade schema from %d -> %d", currSchemaVers, resultSchemVers)
|
||||
|
||||
_, err = tx.Exec(tctx, stmts, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
for i, stmt := range stmts {
|
||||
log.Info().Msgf("SQL-Migration of [%s]: %d/%d", db.name, i+1, len(stmts))
|
||||
|
||||
_, err := tx.Exec(tctx, stmt, sq.PP{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
schemHashDBAfter, err := sq.HashSqliteDatabase(tctx, tx)
|
||||
|
@@ -3,12 +3,13 @@ package schema
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Def struct {
|
||||
SQL string
|
||||
Hash string
|
||||
MigScript string
|
||||
MigScript []string
|
||||
}
|
||||
|
||||
//go:embed *.ddl
|
||||
@@ -16,29 +17,30 @@ type Def struct {
|
||||
var assets embed.FS
|
||||
|
||||
var PrimarySchema = map[int]Def{
|
||||
0: {"", "", ""},
|
||||
1: {readDDL("primary_1.ddl"), "f2b2847f32681a7178e405553beea4a324034915a0c5a5dc70b3c6abbcc852f2", ""},
|
||||
2: {readDDL("primary_2.ddl"), "07ed1449114416ed043084a30e0722a5f97bf172161338d2f7106a8dfd387d0a", ""},
|
||||
3: {readDDL("primary_3.ddl"), "65c2125ad0e12d02490cf2275f0067ef3c62a8522edf9a35ee8aa3f3c09b12e8", ""},
|
||||
0: {"", "", nil},
|
||||
1: {readDDL("primary_1.ddl"), "f2b2847f32681a7178e405553beea4a324034915a0c5a5dc70b3c6abbcc852f2", nil},
|
||||
2: {readDDL("primary_2.ddl"), "07ed1449114416ed043084a30e0722a5f97bf172161338d2f7106a8dfd387d0a", nil},
|
||||
3: {readDDL("primary_3.ddl"), "65c2125ad0e12d02490cf2275f0067ef3c62a8522edf9a35ee8aa3f3c09b12e8", nil},
|
||||
4: {readDDL("primary_4.ddl"), "cb022156ab0e7aea39dd0c985428c43cae7d60e41ca8e9e5a84c774b3019d2ca", readMig("primary_migration_3_4.sql")},
|
||||
5: {readDDL("primary_5.ddl"), "9d6217ba4a3503cfe090f72569367f95a413bb14e9effe49ffeabbf255bce8dd", readMig("primary_migration_4_5.sql")},
|
||||
6: {readDDL("primary_6.ddl"), "8e83d20bcd008082713f248ae8cd558335a37a37ce90bd8c86e782da640ee160", readMig("primary_migration_5_6.sql")},
|
||||
7: {readDDL("primary_7.ddl"), "90d8dbc460afe025f9b74cda5c16bb8e58b178df275223bd2531907a8d8c36c3", readMig("primary_migration_6_7.sql")},
|
||||
8: {readDDL("primary_8.ddl"), "746f6005c7a573b8816e5993ecd1d949fe2552b0134ba63bab8b4d5b2b5058ad", readMig("primary_migration_7_8.sql")},
|
||||
9: {readDDL("primary_9.ddl"), "0fd1eacb03364153b2a2096106b1a11cc48ae764db52c2896dab9725b55ed188", readMig("primary_migration_8_9.sql")},
|
||||
}
|
||||
|
||||
var PrimarySchemaVersion = len(PrimarySchema) - 1
|
||||
|
||||
var RequestsSchema = map[int]Def{
|
||||
0: {"", "", ""},
|
||||
1: {readDDL("requests_1.ddl"), "ebb0a5748b605e8215437413b738279670190ca8159b6227cfc2aa13418b41e9", ""},
|
||||
0: {"", "", nil},
|
||||
1: {readDDL("requests_1.ddl"), "ebb0a5748b605e8215437413b738279670190ca8159b6227cfc2aa13418b41e9", nil},
|
||||
}
|
||||
|
||||
var RequestsSchemaVersion = len(RequestsSchema) - 1
|
||||
|
||||
var LogsSchema = map[int]Def{
|
||||
0: {"", "", ""},
|
||||
1: {readDDL("logs_1.ddl"), "65fba477c04095effc3a8e1bb79fe7547b8e52e983f776f156266eddc4f201d7", ""},
|
||||
0: {"", "", nil},
|
||||
1: {readDDL("logs_1.ddl"), "65fba477c04095effc3a8e1bb79fe7547b8e52e983f776f156266eddc4f201d7", nil},
|
||||
}
|
||||
|
||||
var LogsSchemaVersion = len(LogsSchema) - 1
|
||||
@@ -51,10 +53,51 @@ func readDDL(name string) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func readMig(name string) string {
|
||||
func readMig(name string) []string {
|
||||
data, err := assets.ReadFile(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(data)
|
||||
return splitMigration(string(data))
|
||||
}
|
||||
|
||||
func splitMigration(input string) []string {
|
||||
arr := make([]string, 0)
|
||||
|
||||
acc := ""
|
||||
|
||||
waitForEnd := false
|
||||
|
||||
for _, line := range strings.Split(input, "\n") {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "--") {
|
||||
continue
|
||||
}
|
||||
|
||||
acc += line
|
||||
|
||||
if strings.HasSuffix(strings.TrimSpace(line), "BEGIN") || strings.HasPrefix(strings.TrimSpace(line), "BEGIN") {
|
||||
waitForEnd = true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "END") {
|
||||
waitForEnd = false
|
||||
}
|
||||
|
||||
if strings.HasSuffix(acc, ";") && !waitForEnd {
|
||||
arr = append(arr, acc)
|
||||
acc = ""
|
||||
continue
|
||||
} else {
|
||||
acc += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
if strings.TrimSpace(acc) != "" {
|
||||
arr = append(arr, acc)
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
249
scnserver/db/schema/primary_9.ddl
Normal file
249
scnserver/db/schema/primary_9.ddl
Normal file
@@ -0,0 +1,249 @@
|
||||
CREATE TABLE users
|
||||
(
|
||||
user_id TEXT NOT NULL,
|
||||
|
||||
username TEXT NULL DEFAULT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastread INTEGER NULL DEFAULT NULL,
|
||||
timestamp_lastsent INTEGER NULL DEFAULT NULL,
|
||||
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
|
||||
quota_used INTEGER NOT NULL DEFAULT '0',
|
||||
quota_used_day TEXT NULL DEFAULT NULL,
|
||||
|
||||
is_pro INTEGER CHECK(is_pro IN (0, 1)) NOT NULL DEFAULT 0,
|
||||
pro_token TEXT NULL DEFAULT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (user_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_users_protoken" ON users (pro_token) WHERE pro_token IS NOT NULL AND deleted=0;
|
||||
|
||||
|
||||
CREATE TABLE keytokens
|
||||
(
|
||||
keytoken_id TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastused INTEGER NULL DEFAULT NULL,
|
||||
|
||||
name TEXT NOT NULL,
|
||||
|
||||
owner_user_id TEXT NOT NULL,
|
||||
|
||||
all_channels INTEGER CHECK(all_channels IN (0, 1)) NOT NULL,
|
||||
channels TEXT NOT NULL,
|
||||
token TEXT NOT NULL,
|
||||
permissions TEXT NOT NULL,
|
||||
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (keytoken_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_keytokens_token" ON keytokens (token);
|
||||
|
||||
|
||||
CREATE TABLE clients
|
||||
(
|
||||
client_id TEXT NOT NULL,
|
||||
|
||||
user_id TEXT NOT NULL,
|
||||
type TEXT CHECK(type IN ('ANDROID','IOS','LINUX','MACOS','WINDOWS')) NOT NULL,
|
||||
fcm_token TEXT NOT NULL,
|
||||
name TEXT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
|
||||
agent_model TEXT NOT NULL,
|
||||
agent_version TEXT NOT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (client_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_clients_userid" ON clients (user_id);
|
||||
CREATE INDEX "idx_clients_deleted" ON clients (deleted);
|
||||
CREATE UNIQUE INDEX "idx_clients_fcmtoken" ON clients (fcm_token) WHERE deleted=0;
|
||||
|
||||
|
||||
CREATE TABLE channels
|
||||
(
|
||||
channel_id TEXT NOT NULL,
|
||||
|
||||
owner_user_id TEXT NOT NULL,
|
||||
|
||||
internal_name TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
description_name TEXT NULL,
|
||||
|
||||
subscribe_key TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastsent INTEGER NULL DEFAULT NULL,
|
||||
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (channel_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_channels_identity" ON channels (owner_user_id, internal_name) WHERE deleted=0;
|
||||
|
||||
CREATE TABLE subscriptions
|
||||
(
|
||||
subscription_id TEXT NOT NULL,
|
||||
|
||||
subscriber_user_id TEXT NOT NULL,
|
||||
channel_owner_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
|
||||
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL,
|
||||
active INTEGER CHECK(active IN (0, 1)) NOT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (subscription_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_subscriptions_ref" ON subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name) WHERE deleted=0;
|
||||
CREATE INDEX "idx_subscriptions_chan" ON subscriptions (channel_id);
|
||||
CREATE INDEX "idx_subscriptions_subuser" ON subscriptions (subscriber_user_id);
|
||||
CREATE INDEX "idx_subscriptions_ownuser" ON subscriptions (channel_owner_user_id);
|
||||
CREATE INDEX "idx_subscriptions_tsc" ON subscriptions (timestamp_created);
|
||||
CREATE INDEX "idx_subscriptions_conf" ON subscriptions (confirmed);
|
||||
|
||||
|
||||
CREATE TABLE messages
|
||||
(
|
||||
message_id TEXT NOT NULL,
|
||||
sender_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
channel_owner_user_id TEXT NOT NULL,
|
||||
sender_ip TEXT NOT NULL,
|
||||
sender_name TEXT NULL,
|
||||
|
||||
timestamp_real INTEGER NOT NULL,
|
||||
timestamp_client INTEGER NULL,
|
||||
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NULL,
|
||||
priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL,
|
||||
usr_message_id TEXT NULL,
|
||||
|
||||
used_key_id TEXT NOT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (message_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_messages_channel" ON messages (channel_internal_name COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_channel_nc" ON messages (channel_internal_name COLLATE NOCASE);
|
||||
CREATE UNIQUE INDEX "idx_messages_idempotency" ON messages (sender_user_id, usr_message_id COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_senderip" ON messages (sender_ip COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_sendername" ON messages (sender_name COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_sendername_nc" ON messages (sender_name COLLATE NOCASE);
|
||||
CREATE INDEX "idx_messages_title" ON messages (title COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_title_nc" ON messages (title COLLATE NOCASE);
|
||||
CREATE INDEX "idx_messages_usedkey" ON messages (sender_user_id, used_key_id);
|
||||
CREATE INDEX "idx_messages_deleted" ON messages (deleted);
|
||||
|
||||
|
||||
CREATE VIRTUAL TABLE messages_fts USING fts5
|
||||
(
|
||||
channel_internal_name,
|
||||
sender_name,
|
||||
title,
|
||||
content,
|
||||
|
||||
tokenize = unicode61,
|
||||
content = 'messages',
|
||||
content_rowid = 'rowid'
|
||||
);
|
||||
|
||||
CREATE TRIGGER fts_insert AFTER INSERT ON messages BEGIN
|
||||
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content) VALUES (new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_update AFTER UPDATE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
INSERT INTO messages_fts ( rowid, channel_internal_name, sender_name, title, content) VALUES ( new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_delete AFTER DELETE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
END;
|
||||
|
||||
|
||||
CREATE TABLE deliveries
|
||||
(
|
||||
delivery_id TEXT NOT NULL,
|
||||
|
||||
message_id TEXT NOT NULL,
|
||||
receiver_user_id TEXT NOT NULL,
|
||||
receiver_client_id TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_finalized INTEGER NULL,
|
||||
|
||||
|
||||
status TEXT CHECK(status IN ('RETRY','SUCCESS','FAILED')) NOT NULL,
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
next_delivery INTEGER NULL DEFAULT NULL,
|
||||
|
||||
fcm_message_id TEXT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (delivery_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_deliveries_receiver" ON deliveries (message_id, receiver_client_id);
|
||||
|
||||
|
||||
CREATE TABLE compat_ids
|
||||
(
|
||||
old INTEGER NOT NULL,
|
||||
new TEXT NOT NULL,
|
||||
type TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_compatids_new" ON compat_ids (new);
|
||||
CREATE UNIQUE INDEX "idx_compatids_old" ON compat_ids (old, type);
|
||||
|
||||
|
||||
CREATE TABLE compat_acks
|
||||
(
|
||||
user_id TEXT NOT NULL,
|
||||
message_id TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_compatacks_userid" ON compat_acks (user_id);
|
||||
CREATE UNIQUE INDEX "idx_compatacks_messageid" ON compat_acks (message_id);
|
||||
CREATE UNIQUE INDEX "idx_compatacks_userid_messageid" ON compat_acks (user_id, message_id);
|
||||
|
||||
|
||||
CREATE TABLE compat_clients
|
||||
(
|
||||
client_id TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_compatclient_clientid" ON compat_clients (client_id);
|
||||
|
||||
|
||||
CREATE TABLE `meta`
|
||||
(
|
||||
meta_key TEXT NOT NULL,
|
||||
value_int INTEGER NULL,
|
||||
value_txt TEXT NULL,
|
||||
value_real REAL NULL,
|
||||
value_blob BLOB NULL,
|
||||
|
||||
PRIMARY KEY (meta_key)
|
||||
) STRICT;
|
||||
|
||||
|
||||
INSERT INTO meta (meta_key, value_int) VALUES ('schema', 3)
|
320
scnserver/db/schema/primary_migration_8_9.sql
Normal file
320
scnserver/db/schema/primary_migration_8_9.sql
Normal file
@@ -0,0 +1,320 @@
|
||||
|
||||
-- Add deleted to channels ( migrate existing as '0' )
|
||||
-- Add deleted to keytokens ( migrate existing as '0' )
|
||||
-- Add deleted to subscriptions ( migrate existing as '0' )
|
||||
-- Add deleted to users ( migrate existing as '0' )
|
||||
-- Add deleted to deliveries ( migrate existing as '0' )
|
||||
--
|
||||
-- Add active to subcsriptions ( migrate existing as '1' )
|
||||
--
|
||||
-- Add channel_owner_id to messages ( migrate existing by looking up channel )
|
||||
--
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_users_protoken";
|
||||
|
||||
CREATE TABLE __new_users
|
||||
(
|
||||
user_id TEXT NOT NULL,
|
||||
username TEXT NULL DEFAULT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastread INTEGER NULL DEFAULT NULL,
|
||||
timestamp_lastsent INTEGER NULL DEFAULT NULL,
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
quota_used INTEGER NOT NULL DEFAULT '0',
|
||||
quota_used_day TEXT NULL DEFAULT NULL,
|
||||
is_pro INTEGER CHECK(is_pro IN (0, 1)) NOT NULL DEFAULT 0,
|
||||
pro_token TEXT NULL DEFAULT NULL,
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (user_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_users
|
||||
SELECT
|
||||
user_id,
|
||||
username,
|
||||
timestamp_created,
|
||||
timestamp_lastread,
|
||||
timestamp_lastsent,
|
||||
messages_sent,
|
||||
quota_used,
|
||||
quota_used_day,
|
||||
is_pro,
|
||||
pro_token,
|
||||
0 AS deleted
|
||||
FROM users;
|
||||
|
||||
DROP TABLE users;
|
||||
|
||||
ALTER TABLE __new_users RENAME TO users;
|
||||
|
||||
CREATE UNIQUE INDEX "idx_users_protoken" ON users (pro_token) WHERE pro_token IS NOT NULL AND deleted=0;
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_keytokens_token";
|
||||
|
||||
CREATE TABLE __new_keytokens
|
||||
(
|
||||
keytoken_id TEXT NOT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastused INTEGER NULL DEFAULT NULL,
|
||||
name TEXT NOT NULL,
|
||||
owner_user_id TEXT NOT NULL,
|
||||
all_channels INTEGER CHECK(all_channels IN (0, 1)) NOT NULL,
|
||||
channels TEXT NOT NULL,
|
||||
token TEXT NOT NULL,
|
||||
permissions TEXT NOT NULL,
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (keytoken_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_keytokens
|
||||
SELECT
|
||||
keytoken_id,
|
||||
timestamp_created,
|
||||
timestamp_lastused,
|
||||
name,
|
||||
owner_user_id,
|
||||
all_channels,
|
||||
channels,
|
||||
token,
|
||||
permissions,
|
||||
messages_sent,
|
||||
0 AS deleted
|
||||
FROM keytokens;
|
||||
|
||||
DROP TABLE keytokens;
|
||||
|
||||
ALTER TABLE __new_keytokens RENAME TO keytokens;
|
||||
|
||||
CREATE UNIQUE INDEX "idx_keytokens_token" ON keytokens (token);
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_deliveries_receiver";
|
||||
|
||||
CREATE TABLE __new_deliveries
|
||||
(
|
||||
delivery_id TEXT NOT NULL,
|
||||
message_id TEXT NOT NULL,
|
||||
receiver_user_id TEXT NOT NULL,
|
||||
receiver_client_id TEXT NOT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_finalized INTEGER NULL,
|
||||
status TEXT CHECK(status IN ('RETRY','SUCCESS','FAILED')) NOT NULL,
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
next_delivery INTEGER NULL DEFAULT NULL,
|
||||
fcm_message_id TEXT NULL,
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (delivery_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_deliveries
|
||||
SELECT delivery_id,
|
||||
message_id,
|
||||
receiver_user_id,
|
||||
receiver_client_id,
|
||||
timestamp_created,
|
||||
timestamp_finalized,
|
||||
status,
|
||||
retry_count,
|
||||
next_delivery,
|
||||
fcm_message_id,
|
||||
0 as deleted
|
||||
FROM deliveries;
|
||||
|
||||
DROP TABLE deliveries;
|
||||
|
||||
ALTER TABLE __new_deliveries RENAME TO deliveries;
|
||||
|
||||
CREATE INDEX "idx_deliveries_receiver" ON deliveries (message_id, receiver_client_id);
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_messages_channel";
|
||||
DROP INDEX "idx_messages_channel_nc";
|
||||
DROP INDEX "idx_messages_idempotency";
|
||||
DROP INDEX "idx_messages_senderip";
|
||||
DROP INDEX "idx_messages_sendername";
|
||||
DROP INDEX "idx_messages_sendername_nc";
|
||||
DROP INDEX "idx_messages_title";
|
||||
DROP INDEX "idx_messages_title_nc";
|
||||
DROP INDEX "idx_messages_usedkey";
|
||||
DROP INDEX "idx_messages_deleted";
|
||||
|
||||
CREATE TABLE __new_messages
|
||||
(
|
||||
message_id TEXT NOT NULL,
|
||||
sender_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
channel_owner_user_id TEXT NOT NULL,
|
||||
sender_ip TEXT NOT NULL,
|
||||
sender_name TEXT NULL,
|
||||
timestamp_real INTEGER NOT NULL,
|
||||
timestamp_client INTEGER NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NULL,
|
||||
priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL,
|
||||
usr_message_id TEXT NULL,
|
||||
used_key_id TEXT NOT NULL,
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (message_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_messages
|
||||
SELECT
|
||||
m.message_id,
|
||||
m.sender_user_id,
|
||||
m.channel_internal_name,
|
||||
m.channel_id,
|
||||
c.owner_user_id,
|
||||
m.sender_ip,
|
||||
m.sender_name,
|
||||
m.timestamp_real,
|
||||
m.timestamp_client,
|
||||
m.title,
|
||||
m.content,
|
||||
m.priority,
|
||||
m.usr_message_id,
|
||||
m.used_key_id,
|
||||
m.deleted
|
||||
FROM messages m
|
||||
JOIN channels c ON m.channel_id = c.channel_id;
|
||||
|
||||
DROP TABLE messages;
|
||||
|
||||
ALTER TABLE __new_messages RENAME TO messages;
|
||||
|
||||
CREATE INDEX "idx_messages_channel" ON messages (channel_internal_name COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_channel_nc" ON messages (channel_internal_name COLLATE NOCASE);
|
||||
CREATE UNIQUE INDEX "idx_messages_idempotency" ON messages (sender_user_id, usr_message_id COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_senderip" ON messages (sender_ip COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_sendername" ON messages (sender_name COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_sendername_nc" ON messages (sender_name COLLATE NOCASE);
|
||||
CREATE INDEX "idx_messages_title" ON messages (title COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_title_nc" ON messages (title COLLATE NOCASE);
|
||||
CREATE INDEX "idx_messages_usedkey" ON messages (sender_user_id, used_key_id);
|
||||
CREATE INDEX "idx_messages_deleted" ON messages (deleted);
|
||||
|
||||
DROP TRIGGER IF EXISTS fts_insert;
|
||||
DROP TRIGGER IF EXISTS fts_update;
|
||||
DROP TRIGGER IF EXISTS fts_delete;
|
||||
DROP TABLE IF EXISTS messages_fts;
|
||||
|
||||
CREATE VIRTUAL TABLE messages_fts USING fts5
|
||||
(
|
||||
channel_internal_name,
|
||||
sender_name,
|
||||
title,
|
||||
content,
|
||||
|
||||
tokenize = unicode61,
|
||||
content = 'messages',
|
||||
content_rowid = 'rowid'
|
||||
);
|
||||
|
||||
CREATE TRIGGER fts_insert AFTER INSERT ON messages BEGIN
|
||||
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content) VALUES (new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_update AFTER UPDATE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
INSERT INTO messages_fts ( rowid, channel_internal_name, sender_name, title, content) VALUES ( new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_delete AFTER DELETE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
END;
|
||||
|
||||
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content)
|
||||
SELECT rowid, channel_internal_name, sender_name, title, content FROM messages;
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_channels_identity";
|
||||
|
||||
CREATE TABLE __new_channels
|
||||
(
|
||||
channel_id TEXT NOT NULL,
|
||||
owner_user_id TEXT NOT NULL,
|
||||
internal_name TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
description_name TEXT NULL,
|
||||
subscribe_key TEXT NOT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastsent INTEGER NULL DEFAULT NULL,
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (channel_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_channels
|
||||
SELECT
|
||||
channel_id,
|
||||
owner_user_id,
|
||||
internal_name,
|
||||
display_name,
|
||||
description_name,
|
||||
subscribe_key,
|
||||
timestamp_created,
|
||||
timestamp_lastsent,
|
||||
messages_sent,
|
||||
0 AS deleted
|
||||
FROM channels;
|
||||
|
||||
DROP TABLE channels;
|
||||
ALTER TABLE __new_channels RENAME TO channels;
|
||||
|
||||
CREATE UNIQUE INDEX "idx_channels_identity" ON channels (owner_user_id, internal_name) WHERE deleted=0;
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
DROP INDEX "idx_subscriptions_ref";
|
||||
DROP INDEX "idx_subscriptions_chan";
|
||||
DROP INDEX "idx_subscriptions_subuser";
|
||||
DROP INDEX "idx_subscriptions_ownuser";
|
||||
DROP INDEX "idx_subscriptions_tsc";
|
||||
DROP INDEX "idx_subscriptions_conf";
|
||||
|
||||
CREATE TABLE __new_subscriptions
|
||||
(
|
||||
subscription_id TEXT NOT NULL,
|
||||
subscriber_user_id TEXT NOT NULL,
|
||||
channel_owner_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL,
|
||||
active INTEGER CHECK(active IN (0, 1)) NOT NULL,
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (subscription_id)
|
||||
) STRICT;
|
||||
|
||||
INSERT INTO __new_subscriptions
|
||||
SELECT
|
||||
subscription_id,
|
||||
subscriber_user_id,
|
||||
channel_owner_user_id,
|
||||
channel_internal_name,
|
||||
channel_id,
|
||||
timestamp_created,
|
||||
confirmed,
|
||||
1 AS active,
|
||||
0 AS deleted
|
||||
FROM subscriptions;
|
||||
|
||||
DROP TABLE subscriptions;
|
||||
ALTER TABLE __new_subscriptions RENAME TO subscriptions;
|
||||
|
||||
CREATE UNIQUE INDEX "idx_subscriptions_ref" ON subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name) WHERE deleted=0;
|
||||
CREATE INDEX "idx_subscriptions_chan" ON subscriptions (channel_id);
|
||||
CREATE INDEX "idx_subscriptions_subuser" ON subscriptions (subscriber_user_id);
|
||||
CREATE INDEX "idx_subscriptions_ownuser" ON subscriptions (channel_owner_user_id);
|
||||
CREATE INDEX "idx_subscriptions_tsc" ON subscriptions (timestamp_created);
|
||||
CREATE INDEX "idx_subscriptions_conf" ON subscriptions (confirmed);
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------
|
Reference in New Issue
Block a user