diff --git a/cmd/server/main.go b/cmd/server/main.go index 0398acf..a475453 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -118,6 +118,8 @@ func initFlags() { flag.BoolVar(&flagPrintVersion, "version", false, "print version number and build date") + /* cblgh: TODO change this to use a db.Config.SetPrivacyMode function; guessing database is not loaded yet tho. + * maybe we remove this flag entirely / replace with a small cli tool? idk*/ flag.Func("mode", "the privacy mode (values: open, community, restricted) determining room access controls", func(val string) error { privacyMode := roomdb.ParsePrivacyMode(val) err := privacyMode.IsValid() @@ -228,7 +230,7 @@ func runroomsrv() error { r := repo.New(repoDir) - // open the sqlite version of the admindb + // open the sqlite version of the roomdb db, err := sqlite.Open(r) if err != nil { return fmt.Errorf("failed to initiate database: %w", err) @@ -242,7 +244,7 @@ func runroomsrv() error { db.Aliases, db.AuthWithSSB, bridge, - config, + db.Config, httpsDomain, opts...) if err != nil { @@ -291,8 +293,12 @@ func runroomsrv() error { handlers.Databases{ Aliases: db.Aliases, AuthFallback: db.AuthFallback, +<<<<<<< HEAD AuthWithSSB: db.AuthWithSSB, Config: config, +======= + Config: db.Config, +>>>>>>> a66b343 (persist privacy mode in sqlite :>) DeniedKeys: db.DeniedKeys, Invites: db.Invites, Notices: db.Notices, diff --git a/roomdb/sqlite/config.go b/roomdb/sqlite/config.go new file mode 100644 index 0000000..2fdf977 --- /dev/null +++ b/roomdb/sqlite/config.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +package sqlite + +import ( + "context" + "database/sql" + "fmt" + + "github.com/ssb-ngi-pointer/go-ssb-room/roomdb" + "github.com/ssb-ngi-pointer/go-ssb-room/roomdb/sqlite/models" +) + +// cblgh: ask cryptix about the details of the syntax of the "compiler assertion" below +// why two parens? this does not look like a typical type assertion? e.g. .(type) +// hm-maybe this is a type conversion, forcing "nil" to be a *Aliases? +var _ roomdb.AliasesService = (*Aliases)(nil) + +// the database will only ever store one row, which contains all the room settings +const configRowID = 0 + +/* Config basically enables long-term memory for the server when it comes to storing settings. Currently, the only +* stored settings is the privacy mode of the room. +*/ +type Config struct { + db *sql.DB +} + +// cblgh questions: +// * is storing the entire config in a single row really ugly? ._. +func (c Config) GetPrivacyMode(ctx context.Context) (roomdb.PrivacyMode, error) { + config, err := models.FindConfig(ctx, c.db, configRowID) + if err != nil { + return roomdb.ModeUnknown, err + } + + // use a type conversion to tell compiler the returned value is a roomdb.PrivacyMode + pm := (roomdb.PrivacyMode)(config.PrivacyMode) + err = pm.IsValid() + if err != nil { + return roomdb.ModeUnknown, err + } + + return pm, nil +} diff --git a/roomdb/sqlite/migrations/03-config.sql b/roomdb/sqlite/migrations/03-config.sql new file mode 100644 index 0000000..b4c323c --- /dev/null +++ b/roomdb/sqlite/migrations/03-config.sql @@ -0,0 +1,14 @@ +-- +migrate Up +-- the configuration settings for this room, currently only privacy modes +CREATE TABLE config ( + id integer NOT NULL PRIMARY KEY, + privacyMode integer NOT NULL -- open, community, restricted +); + +-- the config table will only ever contain one row: the rooms current settings +-- we update that row whenever the config changes. +-- to have something to update, we insert the first and only row at id 0 +INSERT INTO config (id, privacyMode) VALUES ( + 0, -- the constant id we will query + 1 -- community is the default mode unless overridden +); diff --git a/roomdb/sqlite/models/boil_table_names.go b/roomdb/sqlite/models/boil_table_names.go index ea8aa6a..ece3a54 100644 --- a/roomdb/sqlite/models/boil_table_names.go +++ b/roomdb/sqlite/models/boil_table_names.go @@ -6,6 +6,7 @@ package models var TableNames = struct { SIWSSBSessions string Aliases string + Config string DeniedKeys string FallbackPasswords string Invites string @@ -16,6 +17,7 @@ var TableNames = struct { }{ SIWSSBSessions: "SIWSSB_sessions", Aliases: "aliases", + Config: "config", DeniedKeys: "denied_keys", FallbackPasswords: "fallback_passwords", Invites: "invites", diff --git a/roomdb/sqlite/models/config.go b/roomdb/sqlite/models/config.go new file mode 100644 index 0000000..e4871d5 --- /dev/null +++ b/roomdb/sqlite/models/config.go @@ -0,0 +1,779 @@ +// Code generated by SQLBoiler 4.5.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "database/sql" + "fmt" + "reflect" + "strings" + "sync" + "time" + + "github.com/friendsofgo/errors" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "github.com/volatiletech/sqlboiler/v4/queries/qmhelper" + "github.com/volatiletech/strmangle" +) + +// Config is an object representing the database table. +type Config struct { + ID int64 `boil:"id" json:"id" toml:"id" yaml:"id"` + PrivacyMode int64 `boil:"privacyMode" json:"privacyMode" toml:"privacyMode" yaml:"privacyMode"` + + R *configR `boil:"-" json:"-" toml:"-" yaml:"-"` + L configL `boil:"-" json:"-" toml:"-" yaml:"-"` +} + +var ConfigColumns = struct { + ID string + PrivacyMode string +}{ + ID: "id", + PrivacyMode: "privacyMode", +} + +// Generated where + +var ConfigWhere = struct { + ID whereHelperint64 + PrivacyMode whereHelperint64 +}{ + ID: whereHelperint64{field: "\"config\".\"id\""}, + PrivacyMode: whereHelperint64{field: "\"config\".\"privacyMode\""}, +} + +// ConfigRels is where relationship names are stored. +var ConfigRels = struct { +}{} + +// configR is where relationships are stored. +type configR struct { +} + +// NewStruct creates a new relationship struct +func (*configR) NewStruct() *configR { + return &configR{} +} + +// configL is where Load methods for each relationship are stored. +type configL struct{} + +var ( + configAllColumns = []string{"id", "privacyMode"} + configColumnsWithoutDefault = []string{"privacyMode"} + configColumnsWithDefault = []string{"id"} + configPrimaryKeyColumns = []string{"id"} +) + +type ( + // ConfigSlice is an alias for a slice of pointers to Config. + // This should generally be used opposed to []Config. + ConfigSlice []*Config + // ConfigHook is the signature for custom Config hook methods + ConfigHook func(context.Context, boil.ContextExecutor, *Config) error + + configQuery struct { + *queries.Query + } +) + +// Cache for insert, update and upsert +var ( + configType = reflect.TypeOf(&Config{}) + configMapping = queries.MakeStructMapping(configType) + configPrimaryKeyMapping, _ = queries.BindMapping(configType, configMapping, configPrimaryKeyColumns) + configInsertCacheMut sync.RWMutex + configInsertCache = make(map[string]insertCache) + configUpdateCacheMut sync.RWMutex + configUpdateCache = make(map[string]updateCache) + configUpsertCacheMut sync.RWMutex + configUpsertCache = make(map[string]insertCache) +) + +var ( + // Force time package dependency for automated UpdatedAt/CreatedAt. + _ = time.Second + // Force qmhelper dependency for where clause generation (which doesn't + // always happen) + _ = qmhelper.Where +) + +var configBeforeInsertHooks []ConfigHook +var configBeforeUpdateHooks []ConfigHook +var configBeforeDeleteHooks []ConfigHook +var configBeforeUpsertHooks []ConfigHook + +var configAfterInsertHooks []ConfigHook +var configAfterSelectHooks []ConfigHook +var configAfterUpdateHooks []ConfigHook +var configAfterDeleteHooks []ConfigHook +var configAfterUpsertHooks []ConfigHook + +// doBeforeInsertHooks executes all "before insert" hooks. +func (o *Config) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configBeforeInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpdateHooks executes all "before Update" hooks. +func (o *Config) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configBeforeUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeDeleteHooks executes all "before Delete" hooks. +func (o *Config) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configBeforeDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doBeforeUpsertHooks executes all "before Upsert" hooks. +func (o *Config) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configBeforeUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterInsertHooks executes all "after Insert" hooks. +func (o *Config) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configAfterInsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterSelectHooks executes all "after Select" hooks. +func (o *Config) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configAfterSelectHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpdateHooks executes all "after Update" hooks. +func (o *Config) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configAfterUpdateHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterDeleteHooks executes all "after Delete" hooks. +func (o *Config) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configAfterDeleteHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// doAfterUpsertHooks executes all "after Upsert" hooks. +func (o *Config) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) { + if boil.HooksAreSkipped(ctx) { + return nil + } + + for _, hook := range configAfterUpsertHooks { + if err := hook(ctx, exec, o); err != nil { + return err + } + } + + return nil +} + +// AddConfigHook registers your hook function for all future operations. +func AddConfigHook(hookPoint boil.HookPoint, configHook ConfigHook) { + switch hookPoint { + case boil.BeforeInsertHook: + configBeforeInsertHooks = append(configBeforeInsertHooks, configHook) + case boil.BeforeUpdateHook: + configBeforeUpdateHooks = append(configBeforeUpdateHooks, configHook) + case boil.BeforeDeleteHook: + configBeforeDeleteHooks = append(configBeforeDeleteHooks, configHook) + case boil.BeforeUpsertHook: + configBeforeUpsertHooks = append(configBeforeUpsertHooks, configHook) + case boil.AfterInsertHook: + configAfterInsertHooks = append(configAfterInsertHooks, configHook) + case boil.AfterSelectHook: + configAfterSelectHooks = append(configAfterSelectHooks, configHook) + case boil.AfterUpdateHook: + configAfterUpdateHooks = append(configAfterUpdateHooks, configHook) + case boil.AfterDeleteHook: + configAfterDeleteHooks = append(configAfterDeleteHooks, configHook) + case boil.AfterUpsertHook: + configAfterUpsertHooks = append(configAfterUpsertHooks, configHook) + } +} + +// One returns a single config record from the query. +func (q configQuery) One(ctx context.Context, exec boil.ContextExecutor) (*Config, error) { + o := &Config{} + + queries.SetLimit(q.Query, 1) + + err := q.Bind(ctx, exec, o) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: failed to execute a one query for config") + } + + if err := o.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + + return o, nil +} + +// All returns all Config records from the query. +func (q configQuery) All(ctx context.Context, exec boil.ContextExecutor) (ConfigSlice, error) { + var o []*Config + + err := q.Bind(ctx, exec, &o) + if err != nil { + return nil, errors.Wrap(err, "models: failed to assign all query results to Config slice") + } + + if len(configAfterSelectHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterSelectHooks(ctx, exec); err != nil { + return o, err + } + } + } + + return o, nil +} + +// Count returns the count of all Config records in the query. +func (q configQuery) Count(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return 0, errors.Wrap(err, "models: failed to count config rows") + } + + return count, nil +} + +// Exists checks if the row exists in the table. +func (q configQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (bool, error) { + var count int64 + + queries.SetSelect(q.Query, nil) + queries.SetCount(q.Query) + queries.SetLimit(q.Query, 1) + + err := q.Query.QueryRowContext(ctx, exec).Scan(&count) + if err != nil { + return false, errors.Wrap(err, "models: failed to check if config exists") + } + + return count > 0, nil +} + +// Configs retrieves all the records using an executor. +func Configs(mods ...qm.QueryMod) configQuery { + mods = append(mods, qm.From("\"config\"")) + return configQuery{NewQuery(mods...)} +} + +// FindConfig retrieves a single record by ID with an executor. +// If selectCols is empty Find will return all columns. +func FindConfig(ctx context.Context, exec boil.ContextExecutor, iD int64, selectCols ...string) (*Config, error) { + configObj := &Config{} + + sel := "*" + if len(selectCols) > 0 { + sel = strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, selectCols), ",") + } + query := fmt.Sprintf( + "select %s from \"config\" where \"id\"=?", sel, + ) + + q := queries.Raw(query, iD) + + err := q.Bind(ctx, exec, configObj) + if err != nil { + if errors.Cause(err) == sql.ErrNoRows { + return nil, sql.ErrNoRows + } + return nil, errors.Wrap(err, "models: unable to select from config") + } + + return configObj, nil +} + +// Insert a single record using an executor. +// See boil.Columns.InsertColumnSet documentation to understand column list inference for inserts. +func (o *Config) Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error { + if o == nil { + return errors.New("models: no config provided for insertion") + } + + var err error + + if err := o.doBeforeInsertHooks(ctx, exec); err != nil { + return err + } + + nzDefaults := queries.NonZeroDefaultSet(configColumnsWithDefault, o) + + key := makeCacheKey(columns, nzDefaults) + configInsertCacheMut.RLock() + cache, cached := configInsertCache[key] + configInsertCacheMut.RUnlock() + + if !cached { + wl, returnColumns := columns.InsertColumnSet( + configAllColumns, + configColumnsWithDefault, + configColumnsWithoutDefault, + nzDefaults, + ) + + cache.valueMapping, err = queries.BindMapping(configType, configMapping, wl) + if err != nil { + return err + } + cache.retMapping, err = queries.BindMapping(configType, configMapping, returnColumns) + if err != nil { + return err + } + if len(wl) != 0 { + cache.query = fmt.Sprintf("INSERT INTO \"config\" (\"%s\") %%sVALUES (%s)%%s", strings.Join(wl, "\",\""), strmangle.Placeholders(dialect.UseIndexPlaceholders, len(wl), 1, 1)) + } else { + cache.query = "INSERT INTO \"config\" %sDEFAULT VALUES%s" + } + + var queryOutput, queryReturning string + + if len(cache.retMapping) != 0 { + cache.retQuery = fmt.Sprintf("SELECT \"%s\" FROM \"config\" WHERE %s", strings.Join(returnColumns, "\",\""), strmangle.WhereClause("\"", "\"", 0, configPrimaryKeyColumns)) + } + + cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning) + } + + value := reflect.Indirect(reflect.ValueOf(o)) + vals := queries.ValuesFromMapping(value, cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, vals) + } + result, err := exec.ExecContext(ctx, cache.query, vals...) + + if err != nil { + return errors.Wrap(err, "models: unable to insert into config") + } + + var lastID int64 + var identifierCols []interface{} + + if len(cache.retMapping) == 0 { + goto CacheNoHooks + } + + lastID, err = result.LastInsertId() + if err != nil { + return ErrSyncFail + } + + o.ID = int64(lastID) + if lastID != 0 && len(cache.retMapping) == 1 && cache.retMapping[0] == configMapping["id"] { + goto CacheNoHooks + } + + identifierCols = []interface{}{ + o.ID, + } + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.retQuery) + fmt.Fprintln(writer, identifierCols...) + } + err = exec.QueryRowContext(ctx, cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...) + if err != nil { + return errors.Wrap(err, "models: unable to populate default values for config") + } + +CacheNoHooks: + if !cached { + configInsertCacheMut.Lock() + configInsertCache[key] = cache + configInsertCacheMut.Unlock() + } + + return o.doAfterInsertHooks(ctx, exec) +} + +// Update uses an executor to update the Config. +// See boil.Columns.UpdateColumnSet documentation to understand column list inference for updates. +// Update does not automatically update the record in case of default values. Use .Reload() to refresh the records. +func (o *Config) Update(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) (int64, error) { + var err error + if err = o.doBeforeUpdateHooks(ctx, exec); err != nil { + return 0, err + } + key := makeCacheKey(columns, nil) + configUpdateCacheMut.RLock() + cache, cached := configUpdateCache[key] + configUpdateCacheMut.RUnlock() + + if !cached { + wl := columns.UpdateColumnSet( + configAllColumns, + configPrimaryKeyColumns, + ) + + if !columns.IsWhitelist() { + wl = strmangle.SetComplement(wl, []string{"created_at"}) + } + if len(wl) == 0 { + return 0, errors.New("models: unable to update config, could not build whitelist") + } + + cache.query = fmt.Sprintf("UPDATE \"config\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, wl), + strmangle.WhereClause("\"", "\"", 0, configPrimaryKeyColumns), + ) + cache.valueMapping, err = queries.BindMapping(configType, configMapping, append(wl, configPrimaryKeyColumns...)) + if err != nil { + return 0, err + } + } + + values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, cache.query) + fmt.Fprintln(writer, values) + } + var result sql.Result + result, err = exec.ExecContext(ctx, cache.query, values...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update config row") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by update for config") + } + + if !cached { + configUpdateCacheMut.Lock() + configUpdateCache[key] = cache + configUpdateCacheMut.Unlock() + } + + return rowsAff, o.doAfterUpdateHooks(ctx, exec) +} + +// UpdateAll updates all rows with the specified column values. +func (q configQuery) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + queries.SetUpdate(q.Query, cols) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all for config") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected for config") + } + + return rowsAff, nil +} + +// UpdateAll updates all rows with the specified column values, using an executor. +func (o ConfigSlice) UpdateAll(ctx context.Context, exec boil.ContextExecutor, cols M) (int64, error) { + ln := int64(len(o)) + if ln == 0 { + return 0, nil + } + + if len(cols) == 0 { + return 0, errors.New("models: update all requires at least one column argument") + } + + colNames := make([]string, len(cols)) + args := make([]interface{}, len(cols)) + + i := 0 + for name, value := range cols { + colNames[i] = name + args[i] = value + i++ + } + + // Append all of the primary key values for each column + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), configPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := fmt.Sprintf("UPDATE \"config\" SET %s WHERE %s", + strmangle.SetParamNames("\"", "\"", 0, colNames), + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, configPrimaryKeyColumns, len(o))) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to update all in config slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: unable to retrieve rows affected all in update all config") + } + return rowsAff, nil +} + +// Delete deletes a single Config record with an executor. +// Delete will match against the primary key column to find the record to delete. +func (o *Config) Delete(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if o == nil { + return 0, errors.New("models: no Config provided for delete") + } + + if err := o.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), configPrimaryKeyMapping) + sql := "DELETE FROM \"config\" WHERE \"id\"=?" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args...) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete from config") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by delete for config") + } + + if err := o.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + + return rowsAff, nil +} + +// DeleteAll deletes all matching rows. +func (q configQuery) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if q.Query == nil { + return 0, errors.New("models: no configQuery provided for delete all") + } + + queries.SetDelete(q.Query) + + result, err := q.Query.ExecContext(ctx, exec) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from config") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for config") + } + + return rowsAff, nil +} + +// DeleteAll deletes all rows in the slice, using an executor. +func (o ConfigSlice) DeleteAll(ctx context.Context, exec boil.ContextExecutor) (int64, error) { + if len(o) == 0 { + return 0, nil + } + + if len(configBeforeDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doBeforeDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + var args []interface{} + for _, obj := range o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), configPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "DELETE FROM \"config\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, configPrimaryKeyColumns, len(o)) + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, args) + } + result, err := exec.ExecContext(ctx, sql, args...) + if err != nil { + return 0, errors.Wrap(err, "models: unable to delete all from config slice") + } + + rowsAff, err := result.RowsAffected() + if err != nil { + return 0, errors.Wrap(err, "models: failed to get rows affected by deleteall for config") + } + + if len(configAfterDeleteHooks) != 0 { + for _, obj := range o { + if err := obj.doAfterDeleteHooks(ctx, exec); err != nil { + return 0, err + } + } + } + + return rowsAff, nil +} + +// Reload refetches the object from the database +// using the primary keys with an executor. +func (o *Config) Reload(ctx context.Context, exec boil.ContextExecutor) error { + ret, err := FindConfig(ctx, exec, o.ID) + if err != nil { + return err + } + + *o = *ret + return nil +} + +// ReloadAll refetches every row with matching primary key column values +// and overwrites the original object slice with the newly updated slice. +func (o *ConfigSlice) ReloadAll(ctx context.Context, exec boil.ContextExecutor) error { + if o == nil || len(*o) == 0 { + return nil + } + + slice := ConfigSlice{} + var args []interface{} + for _, obj := range *o { + pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), configPrimaryKeyMapping) + args = append(args, pkeyArgs...) + } + + sql := "SELECT \"config\".* FROM \"config\" WHERE " + + strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), 0, configPrimaryKeyColumns, len(*o)) + + q := queries.Raw(sql, args...) + + err := q.Bind(ctx, exec, &slice) + if err != nil { + return errors.Wrap(err, "models: unable to reload all in ConfigSlice") + } + + *o = slice + + return nil +} + +// ConfigExists checks if the Config row exists. +func ConfigExists(ctx context.Context, exec boil.ContextExecutor, iD int64) (bool, error) { + var exists bool + sql := "select exists(select 1 from \"config\" where \"id\"=? limit 1)" + + if boil.IsDebug(ctx) { + writer := boil.DebugWriterFrom(ctx) + fmt.Fprintln(writer, sql) + fmt.Fprintln(writer, iD) + } + row := exec.QueryRowContext(ctx, sql, iD) + + err := row.Scan(&exists) + if err != nil { + return false, errors.Wrap(err, "models: unable to check if config exists") + } + + return exists, nil +} diff --git a/roomdb/sqlite/new.go b/roomdb/sqlite/new.go index 10700fd..8485d14 100644 --- a/roomdb/sqlite/new.go +++ b/roomdb/sqlite/new.go @@ -38,6 +38,7 @@ type Database struct { Members Members Aliases Aliases Invites Invites + Config Config DeniedKeys DeniedKeys @@ -103,6 +104,7 @@ func Open(r repo.Interface) (*Database, error) { Aliases: Aliases{db}, AuthFallback: AuthFallback{db}, AuthWithSSB: AuthWithSSB{db}, + Config: Config{db}, DeniedKeys: DeniedKeys{db}, Invites: Invites{db: db, members: ml}, Notices: Notices{db}, diff --git a/web/handlers/admin/invites.go b/web/handlers/admin/invites.go index c3e1615..f465c9f 100644 --- a/web/handlers/admin/invites.go +++ b/web/handlers/admin/invites.go @@ -63,11 +63,11 @@ func (h invitesHandler) create(w http.ResponseWriter, req *http.Request) (interf if err != nil { return nil, err } - /* We want to check: - * 1. the room's privacy mode - * 2. the role of the member trying to create the invite - * and deny unallowed requests (e.g. member creating invite in ModeRestricted) - */ + /* We want to check: + * 1. the room's privacy mode + * 2. the role of the member trying to create the invite + * and deny unallowed requests (e.g. member creating invite in ModeRestricted) + */ switch pm { case roomdb.ModeOpen: case roomdb.ModeCommunity: