From f12059c760ee59a6b462a5daae885494b89620a4 Mon Sep 17 00:00:00 2001 From: mstar Date: Fri, 11 Jul 2025 10:12:52 +0200 Subject: [PATCH] Drop feeds/merge them into user --- devserver/linstrom.toml | 18 +- storage-new/dbgen/feeds.gen.go | 744 ----------------------- storage-new/dbgen/gen.go | 8 - storage-new/dbgen/note_to_feeds.gen.go | 59 +- storage-new/dbgen/users.gen.go | 6 +- storage-new/models/0allTypes.go | 1 - storage-new/models/Feed.go | 37 -- storage-new/models/NoteToFeed.go | 4 +- storage-new/models/User.go | 6 + storage-new/models/UserToUserRelation.go | 4 - storage-new/self.go | 26 - web/debug/users.go | 11 - web/public/api/activitypub/inbox.go | 74 +-- 13 files changed, 78 insertions(+), 920 deletions(-) delete mode 100644 storage-new/dbgen/feeds.gen.go delete mode 100644 storage-new/models/Feed.go diff --git a/devserver/linstrom.toml b/devserver/linstrom.toml index 4c50a14..7658202 100644 --- a/devserver/linstrom.toml +++ b/devserver/linstrom.toml @@ -38,15 +38,27 @@ [self] server_actor_display_name = "Server actor" server_display_name = "Linstrom" + server_description = "A social media server running Linstrom" +# Get data via commands in docker container (binary path is /garage) +# commands can be seen here: https://garagehq.deuxfleurs.fr/documentation/quick-start/ [s3] - key_id = "GK458f9d7315fc6c9686c41045" - secret = "b6d1c8ec97052b8a40ae953de34f336170d85554fbe7875acce0ff51464724ee" + key_id = "GK400d4be33cd08213625cf349" + secret = "10be5b60c9de5b15f05cc6a391f5a676fe7dea86e1133e715b98d45bb4c1fc3b" region = "garage" - endpoint = "http://localhost:3900" + endpoint = "localhost:3900" use_ssl = false bucket_name = "linstrom-bucket" +[transcoder] + shared_directory = "/tmp/linstrom-transcoder" + secret = "The same secret as configured in the transcoder" + server_address = "127.0.0.1" + server_port = 5594 + ignore_transcoder = false + [experimental] use_ed25519_keys = false auth_fetch_for_server_actor = false + id_generator = "xid" + http3_support = false diff --git a/storage-new/dbgen/feeds.gen.go b/storage-new/dbgen/feeds.gen.go deleted file mode 100644 index 2c7b893..0000000 --- a/storage-new/dbgen/feeds.gen.go +++ /dev/null @@ -1,744 +0,0 @@ -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. - -package dbgen - -import ( - "context" - "database/sql" - - "git.mstar.dev/mstar/linstrom/storage-new/models" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "gorm.io/gorm/schema" - - "gorm.io/gen" - "gorm.io/gen/field" - - "gorm.io/plugin/dbresolver" -) - -func newFeed(db *gorm.DB, opts ...gen.DOOption) feed { - _feed := feed{} - - _feed.feedDo.UseDB(db, opts...) - _feed.feedDo.UseModel(&models.Feed{}) - - tableName := _feed.feedDo.TableName() - _feed.ALL = field.NewAsterisk(tableName) - _feed.ID = field.NewUint(tableName, "id") - _feed.CreatedAt = field.NewTime(tableName, "created_at") - _feed.UpdatedAt = field.NewTime(tableName, "updated_at") - _feed.DeletedAt = field.NewField(tableName, "deleted_at") - _feed.Name = field.NewString(tableName, "name") - _feed.OwnerId = field.NewString(tableName, "owner_id") - _feed.IsDefault = field.NewBool(tableName, "is_default") - _feed.PublicKey = field.NewField(tableName, "public_key") - _feed.Owner = feedBelongsToOwner{ - db: db.Session(&gorm.Session{}), - - RelationField: field.NewRelation("Owner", "models.User"), - Server: struct { - field.RelationField - Icon struct { - field.RelationField - } - Metadata struct { - field.RelationField - RemoteServer struct { - field.RelationField - } - } - }{ - RelationField: field.NewRelation("Owner.Server", "models.RemoteServer"), - Icon: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Server.Icon", "models.MediaMetadata"), - }, - Metadata: struct { - field.RelationField - RemoteServer struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.Server.Metadata", "models.RemoteServerMetadata"), - RemoteServer: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Server.Metadata.RemoteServer", "models.RemoteServer"), - }, - }, - }, - Icon: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Icon", "models.MediaMetadata"), - }, - Background: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Background", "models.MediaMetadata"), - }, - Banner: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Banner", "models.MediaMetadata"), - }, - RemoteInfo: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.RemoteInfo", "models.UserRemoteLinks"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.RemoteInfo.User", "models.User"), - }, - }, - InfoFields: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.InfoFields", "models.UserInfoField"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.InfoFields.User", "models.User"), - }, - }, - BeingTypes: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.BeingTypes", "models.UserToBeing"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.BeingTypes.User", "models.User"), - }, - }, - Tags: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.Tags", "models.UserToTag"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Tags.User", "models.User"), - }, - }, - Relations: struct { - field.RelationField - User struct { - field.RelationField - } - TargetUser struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.Relations", "models.UserToUserRelation"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Relations.User", "models.User"), - }, - TargetUser: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Relations.TargetUser", "models.User"), - }, - }, - Pronouns: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.Pronouns", "models.UserToPronoun"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Pronouns.User", "models.User"), - }, - }, - Roles: struct { - field.RelationField - User struct { - field.RelationField - } - Role struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.Roles", "models.UserToRole"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Roles.User", "models.User"), - }, - Role: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.Roles.Role", "models.Role"), - }, - }, - AuthMethods: struct { - field.RelationField - User struct { - field.RelationField - } - }{ - RelationField: field.NewRelation("Owner.AuthMethods", "models.UserAuthMethod"), - User: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Owner.AuthMethods.User", "models.User"), - }, - }, - } - - _feed.fillFieldMap() - - return _feed -} - -type feed struct { - feedDo - - ALL field.Asterisk - ID field.Uint - CreatedAt field.Time - UpdatedAt field.Time - DeletedAt field.Field - Name field.String - OwnerId field.String - IsDefault field.Bool - PublicKey field.Field - Owner feedBelongsToOwner - - fieldMap map[string]field.Expr -} - -func (f feed) Table(newTableName string) *feed { - f.feedDo.UseTable(newTableName) - return f.updateTableName(newTableName) -} - -func (f feed) As(alias string) *feed { - f.feedDo.DO = *(f.feedDo.As(alias).(*gen.DO)) - return f.updateTableName(alias) -} - -func (f *feed) updateTableName(table string) *feed { - f.ALL = field.NewAsterisk(table) - f.ID = field.NewUint(table, "id") - f.CreatedAt = field.NewTime(table, "created_at") - f.UpdatedAt = field.NewTime(table, "updated_at") - f.DeletedAt = field.NewField(table, "deleted_at") - f.Name = field.NewString(table, "name") - f.OwnerId = field.NewString(table, "owner_id") - f.IsDefault = field.NewBool(table, "is_default") - f.PublicKey = field.NewField(table, "public_key") - - f.fillFieldMap() - - return f -} - -func (f *feed) GetFieldByName(fieldName string) (field.OrderExpr, bool) { - _f, ok := f.fieldMap[fieldName] - if !ok || _f == nil { - return nil, false - } - _oe, ok := _f.(field.OrderExpr) - return _oe, ok -} - -func (f *feed) fillFieldMap() { - f.fieldMap = make(map[string]field.Expr, 9) - f.fieldMap["id"] = f.ID - f.fieldMap["created_at"] = f.CreatedAt - f.fieldMap["updated_at"] = f.UpdatedAt - f.fieldMap["deleted_at"] = f.DeletedAt - f.fieldMap["name"] = f.Name - f.fieldMap["owner_id"] = f.OwnerId - f.fieldMap["is_default"] = f.IsDefault - f.fieldMap["public_key"] = f.PublicKey - -} - -func (f feed) clone(db *gorm.DB) feed { - f.feedDo.ReplaceConnPool(db.Statement.ConnPool) - f.Owner.db = db.Session(&gorm.Session{Initialized: true}) - f.Owner.db.Statement.ConnPool = db.Statement.ConnPool - return f -} - -func (f feed) replaceDB(db *gorm.DB) feed { - f.feedDo.ReplaceDB(db) - f.Owner.db = db.Session(&gorm.Session{}) - return f -} - -type feedBelongsToOwner struct { - db *gorm.DB - - field.RelationField - - Server struct { - field.RelationField - Icon struct { - field.RelationField - } - Metadata struct { - field.RelationField - RemoteServer struct { - field.RelationField - } - } - } - Icon struct { - field.RelationField - } - Background struct { - field.RelationField - } - Banner struct { - field.RelationField - } - RemoteInfo struct { - field.RelationField - User struct { - field.RelationField - } - } - InfoFields struct { - field.RelationField - User struct { - field.RelationField - } - } - BeingTypes struct { - field.RelationField - User struct { - field.RelationField - } - } - Tags struct { - field.RelationField - User struct { - field.RelationField - } - } - Relations struct { - field.RelationField - User struct { - field.RelationField - } - TargetUser struct { - field.RelationField - } - } - Pronouns struct { - field.RelationField - User struct { - field.RelationField - } - } - Roles struct { - field.RelationField - User struct { - field.RelationField - } - Role struct { - field.RelationField - } - } - AuthMethods struct { - field.RelationField - User struct { - field.RelationField - } - } -} - -func (a feedBelongsToOwner) Where(conds ...field.Expr) *feedBelongsToOwner { - if len(conds) == 0 { - return &a - } - - exprs := make([]clause.Expression, 0, len(conds)) - for _, cond := range conds { - exprs = append(exprs, cond.BeCond().(clause.Expression)) - } - a.db = a.db.Clauses(clause.Where{Exprs: exprs}) - return &a -} - -func (a feedBelongsToOwner) WithContext(ctx context.Context) *feedBelongsToOwner { - a.db = a.db.WithContext(ctx) - return &a -} - -func (a feedBelongsToOwner) Session(session *gorm.Session) *feedBelongsToOwner { - a.db = a.db.Session(session) - return &a -} - -func (a feedBelongsToOwner) Model(m *models.Feed) *feedBelongsToOwnerTx { - return &feedBelongsToOwnerTx{a.db.Model(m).Association(a.Name())} -} - -func (a feedBelongsToOwner) Unscoped() *feedBelongsToOwner { - a.db = a.db.Unscoped() - return &a -} - -type feedBelongsToOwnerTx struct{ tx *gorm.Association } - -func (a feedBelongsToOwnerTx) Find() (result *models.User, err error) { - return result, a.tx.Find(&result) -} - -func (a feedBelongsToOwnerTx) Append(values ...*models.User) (err error) { - targetValues := make([]interface{}, len(values)) - for i, v := range values { - targetValues[i] = v - } - return a.tx.Append(targetValues...) -} - -func (a feedBelongsToOwnerTx) Replace(values ...*models.User) (err error) { - targetValues := make([]interface{}, len(values)) - for i, v := range values { - targetValues[i] = v - } - return a.tx.Replace(targetValues...) -} - -func (a feedBelongsToOwnerTx) Delete(values ...*models.User) (err error) { - targetValues := make([]interface{}, len(values)) - for i, v := range values { - targetValues[i] = v - } - return a.tx.Delete(targetValues...) -} - -func (a feedBelongsToOwnerTx) Clear() error { - return a.tx.Clear() -} - -func (a feedBelongsToOwnerTx) Count() int64 { - return a.tx.Count() -} - -func (a feedBelongsToOwnerTx) Unscoped() *feedBelongsToOwnerTx { - a.tx = a.tx.Unscoped() - return &a -} - -type feedDo struct{ gen.DO } - -type IFeedDo interface { - gen.SubQuery - Debug() IFeedDo - WithContext(ctx context.Context) IFeedDo - WithResult(fc func(tx gen.Dao)) gen.ResultInfo - ReplaceDB(db *gorm.DB) - ReadDB() IFeedDo - WriteDB() IFeedDo - As(alias string) gen.Dao - Session(config *gorm.Session) IFeedDo - Columns(cols ...field.Expr) gen.Columns - Clauses(conds ...clause.Expression) IFeedDo - Not(conds ...gen.Condition) IFeedDo - Or(conds ...gen.Condition) IFeedDo - Select(conds ...field.Expr) IFeedDo - Where(conds ...gen.Condition) IFeedDo - Order(conds ...field.Expr) IFeedDo - Distinct(cols ...field.Expr) IFeedDo - Omit(cols ...field.Expr) IFeedDo - Join(table schema.Tabler, on ...field.Expr) IFeedDo - LeftJoin(table schema.Tabler, on ...field.Expr) IFeedDo - RightJoin(table schema.Tabler, on ...field.Expr) IFeedDo - Group(cols ...field.Expr) IFeedDo - Having(conds ...gen.Condition) IFeedDo - Limit(limit int) IFeedDo - Offset(offset int) IFeedDo - Count() (count int64, err error) - Scopes(funcs ...func(gen.Dao) gen.Dao) IFeedDo - Unscoped() IFeedDo - Create(values ...*models.Feed) error - CreateInBatches(values []*models.Feed, batchSize int) error - Save(values ...*models.Feed) error - First() (*models.Feed, error) - Take() (*models.Feed, error) - Last() (*models.Feed, error) - Find() ([]*models.Feed, error) - FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Feed, err error) - FindInBatches(result *[]*models.Feed, batchSize int, fc func(tx gen.Dao, batch int) error) error - Pluck(column field.Expr, dest interface{}) error - Delete(...*models.Feed) (info gen.ResultInfo, err error) - Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) - UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) - Updates(value interface{}) (info gen.ResultInfo, err error) - UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) - UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) - UpdateColumns(value interface{}) (info gen.ResultInfo, err error) - UpdateFrom(q gen.SubQuery) gen.Dao - Attrs(attrs ...field.AssignExpr) IFeedDo - Assign(attrs ...field.AssignExpr) IFeedDo - Joins(fields ...field.RelationField) IFeedDo - Preload(fields ...field.RelationField) IFeedDo - FirstOrInit() (*models.Feed, error) - FirstOrCreate() (*models.Feed, error) - FindByPage(offset int, limit int) (result []*models.Feed, count int64, err error) - ScanByPage(result interface{}, offset int, limit int) (count int64, err error) - Rows() (*sql.Rows, error) - Row() *sql.Row - Scan(result interface{}) (err error) - Returning(value interface{}, columns ...string) IFeedDo - UnderlyingDB() *gorm.DB - schema.Tabler -} - -func (f feedDo) Debug() IFeedDo { - return f.withDO(f.DO.Debug()) -} - -func (f feedDo) WithContext(ctx context.Context) IFeedDo { - return f.withDO(f.DO.WithContext(ctx)) -} - -func (f feedDo) ReadDB() IFeedDo { - return f.Clauses(dbresolver.Read) -} - -func (f feedDo) WriteDB() IFeedDo { - return f.Clauses(dbresolver.Write) -} - -func (f feedDo) Session(config *gorm.Session) IFeedDo { - return f.withDO(f.DO.Session(config)) -} - -func (f feedDo) Clauses(conds ...clause.Expression) IFeedDo { - return f.withDO(f.DO.Clauses(conds...)) -} - -func (f feedDo) Returning(value interface{}, columns ...string) IFeedDo { - return f.withDO(f.DO.Returning(value, columns...)) -} - -func (f feedDo) Not(conds ...gen.Condition) IFeedDo { - return f.withDO(f.DO.Not(conds...)) -} - -func (f feedDo) Or(conds ...gen.Condition) IFeedDo { - return f.withDO(f.DO.Or(conds...)) -} - -func (f feedDo) Select(conds ...field.Expr) IFeedDo { - return f.withDO(f.DO.Select(conds...)) -} - -func (f feedDo) Where(conds ...gen.Condition) IFeedDo { - return f.withDO(f.DO.Where(conds...)) -} - -func (f feedDo) Order(conds ...field.Expr) IFeedDo { - return f.withDO(f.DO.Order(conds...)) -} - -func (f feedDo) Distinct(cols ...field.Expr) IFeedDo { - return f.withDO(f.DO.Distinct(cols...)) -} - -func (f feedDo) Omit(cols ...field.Expr) IFeedDo { - return f.withDO(f.DO.Omit(cols...)) -} - -func (f feedDo) Join(table schema.Tabler, on ...field.Expr) IFeedDo { - return f.withDO(f.DO.Join(table, on...)) -} - -func (f feedDo) LeftJoin(table schema.Tabler, on ...field.Expr) IFeedDo { - return f.withDO(f.DO.LeftJoin(table, on...)) -} - -func (f feedDo) RightJoin(table schema.Tabler, on ...field.Expr) IFeedDo { - return f.withDO(f.DO.RightJoin(table, on...)) -} - -func (f feedDo) Group(cols ...field.Expr) IFeedDo { - return f.withDO(f.DO.Group(cols...)) -} - -func (f feedDo) Having(conds ...gen.Condition) IFeedDo { - return f.withDO(f.DO.Having(conds...)) -} - -func (f feedDo) Limit(limit int) IFeedDo { - return f.withDO(f.DO.Limit(limit)) -} - -func (f feedDo) Offset(offset int) IFeedDo { - return f.withDO(f.DO.Offset(offset)) -} - -func (f feedDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IFeedDo { - return f.withDO(f.DO.Scopes(funcs...)) -} - -func (f feedDo) Unscoped() IFeedDo { - return f.withDO(f.DO.Unscoped()) -} - -func (f feedDo) Create(values ...*models.Feed) error { - if len(values) == 0 { - return nil - } - return f.DO.Create(values) -} - -func (f feedDo) CreateInBatches(values []*models.Feed, batchSize int) error { - return f.DO.CreateInBatches(values, batchSize) -} - -// Save : !!! underlying implementation is different with GORM -// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) -func (f feedDo) Save(values ...*models.Feed) error { - if len(values) == 0 { - return nil - } - return f.DO.Save(values) -} - -func (f feedDo) First() (*models.Feed, error) { - if result, err := f.DO.First(); err != nil { - return nil, err - } else { - return result.(*models.Feed), nil - } -} - -func (f feedDo) Take() (*models.Feed, error) { - if result, err := f.DO.Take(); err != nil { - return nil, err - } else { - return result.(*models.Feed), nil - } -} - -func (f feedDo) Last() (*models.Feed, error) { - if result, err := f.DO.Last(); err != nil { - return nil, err - } else { - return result.(*models.Feed), nil - } -} - -func (f feedDo) Find() ([]*models.Feed, error) { - result, err := f.DO.Find() - return result.([]*models.Feed), err -} - -func (f feedDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Feed, err error) { - buf := make([]*models.Feed, 0, batchSize) - err = f.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { - defer func() { results = append(results, buf...) }() - return fc(tx, batch) - }) - return results, err -} - -func (f feedDo) FindInBatches(result *[]*models.Feed, batchSize int, fc func(tx gen.Dao, batch int) error) error { - return f.DO.FindInBatches(result, batchSize, fc) -} - -func (f feedDo) Attrs(attrs ...field.AssignExpr) IFeedDo { - return f.withDO(f.DO.Attrs(attrs...)) -} - -func (f feedDo) Assign(attrs ...field.AssignExpr) IFeedDo { - return f.withDO(f.DO.Assign(attrs...)) -} - -func (f feedDo) Joins(fields ...field.RelationField) IFeedDo { - for _, _f := range fields { - f = *f.withDO(f.DO.Joins(_f)) - } - return &f -} - -func (f feedDo) Preload(fields ...field.RelationField) IFeedDo { - for _, _f := range fields { - f = *f.withDO(f.DO.Preload(_f)) - } - return &f -} - -func (f feedDo) FirstOrInit() (*models.Feed, error) { - if result, err := f.DO.FirstOrInit(); err != nil { - return nil, err - } else { - return result.(*models.Feed), nil - } -} - -func (f feedDo) FirstOrCreate() (*models.Feed, error) { - if result, err := f.DO.FirstOrCreate(); err != nil { - return nil, err - } else { - return result.(*models.Feed), nil - } -} - -func (f feedDo) FindByPage(offset int, limit int) (result []*models.Feed, count int64, err error) { - result, err = f.Offset(offset).Limit(limit).Find() - if err != nil { - return - } - - if size := len(result); 0 < limit && 0 < size && size < limit { - count = int64(size + offset) - return - } - - count, err = f.Offset(-1).Limit(-1).Count() - return -} - -func (f feedDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { - count, err = f.Count() - if err != nil { - return - } - - err = f.Offset(offset).Limit(limit).Scan(result) - return -} - -func (f feedDo) Scan(result interface{}) (err error) { - return f.DO.Scan(result) -} - -func (f feedDo) Delete(models ...*models.Feed) (result gen.ResultInfo, err error) { - return f.DO.Delete(models) -} - -func (f *feedDo) withDO(do gen.Dao) *feedDo { - f.DO = *do.(*gen.DO) - return f -} diff --git a/storage-new/dbgen/gen.go b/storage-new/dbgen/gen.go index 9b00402..422f799 100644 --- a/storage-new/dbgen/gen.go +++ b/storage-new/dbgen/gen.go @@ -22,7 +22,6 @@ var ( Collection *collection Emote *emote FailedOutboundRequest *failedOutboundRequest - Feed *feed LoginProcessToken *loginProcessToken MediaMetadata *mediaMetadata Note *note @@ -58,7 +57,6 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) { Collection = &Q.Collection Emote = &Q.Emote FailedOutboundRequest = &Q.FailedOutboundRequest - Feed = &Q.Feed LoginProcessToken = &Q.LoginProcessToken MediaMetadata = &Q.MediaMetadata Note = &Q.Note @@ -95,7 +93,6 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query { Collection: newCollection(db, opts...), Emote: newEmote(db, opts...), FailedOutboundRequest: newFailedOutboundRequest(db, opts...), - Feed: newFeed(db, opts...), LoginProcessToken: newLoginProcessToken(db, opts...), MediaMetadata: newMediaMetadata(db, opts...), Note: newNote(db, opts...), @@ -133,7 +130,6 @@ type Query struct { Collection collection Emote emote FailedOutboundRequest failedOutboundRequest - Feed feed LoginProcessToken loginProcessToken MediaMetadata mediaMetadata Note note @@ -172,7 +168,6 @@ func (q *Query) clone(db *gorm.DB) *Query { Collection: q.Collection.clone(db), Emote: q.Emote.clone(db), FailedOutboundRequest: q.FailedOutboundRequest.clone(db), - Feed: q.Feed.clone(db), LoginProcessToken: q.LoginProcessToken.clone(db), MediaMetadata: q.MediaMetadata.clone(db), Note: q.Note.clone(db), @@ -218,7 +213,6 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query { Collection: q.Collection.replaceDB(db), Emote: q.Emote.replaceDB(db), FailedOutboundRequest: q.FailedOutboundRequest.replaceDB(db), - Feed: q.Feed.replaceDB(db), LoginProcessToken: q.LoginProcessToken.replaceDB(db), MediaMetadata: q.MediaMetadata.replaceDB(db), Note: q.Note.replaceDB(db), @@ -254,7 +248,6 @@ type queryCtx struct { Collection ICollectionDo Emote IEmoteDo FailedOutboundRequest IFailedOutboundRequestDo - Feed IFeedDo LoginProcessToken ILoginProcessTokenDo MediaMetadata IMediaMetadataDo Note INoteDo @@ -290,7 +283,6 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx { Collection: q.Collection.WithContext(ctx), Emote: q.Emote.WithContext(ctx), FailedOutboundRequest: q.FailedOutboundRequest.WithContext(ctx), - Feed: q.Feed.WithContext(ctx), LoginProcessToken: q.LoginProcessToken.WithContext(ctx), MediaMetadata: q.MediaMetadata.WithContext(ctx), Note: q.Note.WithContext(ctx), diff --git a/storage-new/dbgen/note_to_feeds.gen.go b/storage-new/dbgen/note_to_feeds.gen.go index 3fc9c46..f7a39bc 100644 --- a/storage-new/dbgen/note_to_feeds.gen.go +++ b/storage-new/dbgen/note_to_feeds.gen.go @@ -30,7 +30,7 @@ func newNoteToFeed(db *gorm.DB, opts ...gen.DOOption) noteToFeed { _noteToFeed.ID = field.NewUint64(tableName, "id") _noteToFeed.CreatedAt = field.NewTime(tableName, "created_at") _noteToFeed.NoteId = field.NewString(tableName, "note_id") - _noteToFeed.FeedId = field.NewUint64(tableName, "feed_id") + _noteToFeed.ForUserId = field.NewString(tableName, "for_user_id") _noteToFeed.Reason = field.NewString(tableName, "reason") _noteToFeed.Note = noteToFeedBelongsToNote{ db: db.Session(&gorm.Session{}), @@ -401,15 +401,10 @@ func newNoteToFeed(db *gorm.DB, opts ...gen.DOOption) noteToFeed { }, } - _noteToFeed.Feed = noteToFeedBelongsToFeed{ + _noteToFeed.ForUser = noteToFeedBelongsToForUser{ db: db.Session(&gorm.Session{}), - RelationField: field.NewRelation("Feed", "models.Feed"), - Owner: struct { - field.RelationField - }{ - RelationField: field.NewRelation("Feed.Owner", "models.User"), - }, + RelationField: field.NewRelation("ForUser", "models.User"), } _noteToFeed.fillFieldMap() @@ -424,11 +419,11 @@ type noteToFeed struct { ID field.Uint64 CreatedAt field.Time NoteId field.String - FeedId field.Uint64 + ForUserId field.String Reason field.String Note noteToFeedBelongsToNote - Feed noteToFeedBelongsToFeed + ForUser noteToFeedBelongsToForUser fieldMap map[string]field.Expr } @@ -448,7 +443,7 @@ func (n *noteToFeed) updateTableName(table string) *noteToFeed { n.ID = field.NewUint64(table, "id") n.CreatedAt = field.NewTime(table, "created_at") n.NoteId = field.NewString(table, "note_id") - n.FeedId = field.NewUint64(table, "feed_id") + n.ForUserId = field.NewString(table, "for_user_id") n.Reason = field.NewString(table, "reason") n.fillFieldMap() @@ -470,7 +465,7 @@ func (n *noteToFeed) fillFieldMap() { n.fieldMap["id"] = n.ID n.fieldMap["created_at"] = n.CreatedAt n.fieldMap["note_id"] = n.NoteId - n.fieldMap["feed_id"] = n.FeedId + n.fieldMap["for_user_id"] = n.ForUserId n.fieldMap["reason"] = n.Reason } @@ -479,15 +474,15 @@ func (n noteToFeed) clone(db *gorm.DB) noteToFeed { n.noteToFeedDo.ReplaceConnPool(db.Statement.ConnPool) n.Note.db = db.Session(&gorm.Session{Initialized: true}) n.Note.db.Statement.ConnPool = db.Statement.ConnPool - n.Feed.db = db.Session(&gorm.Session{Initialized: true}) - n.Feed.db.Statement.ConnPool = db.Statement.ConnPool + n.ForUser.db = db.Session(&gorm.Session{Initialized: true}) + n.ForUser.db.Statement.ConnPool = db.Statement.ConnPool return n } func (n noteToFeed) replaceDB(db *gorm.DB) noteToFeed { n.noteToFeedDo.ReplaceDB(db) n.Note.db = db.Session(&gorm.Session{}) - n.Feed.db = db.Session(&gorm.Session{}) + n.ForUser.db = db.Session(&gorm.Session{}) return n } @@ -699,17 +694,13 @@ func (a noteToFeedBelongsToNoteTx) Unscoped() *noteToFeedBelongsToNoteTx { return &a } -type noteToFeedBelongsToFeed struct { +type noteToFeedBelongsToForUser struct { db *gorm.DB field.RelationField - - Owner struct { - field.RelationField - } } -func (a noteToFeedBelongsToFeed) Where(conds ...field.Expr) *noteToFeedBelongsToFeed { +func (a noteToFeedBelongsToForUser) Where(conds ...field.Expr) *noteToFeedBelongsToForUser { if len(conds) == 0 { return &a } @@ -722,32 +713,32 @@ func (a noteToFeedBelongsToFeed) Where(conds ...field.Expr) *noteToFeedBelongsTo return &a } -func (a noteToFeedBelongsToFeed) WithContext(ctx context.Context) *noteToFeedBelongsToFeed { +func (a noteToFeedBelongsToForUser) WithContext(ctx context.Context) *noteToFeedBelongsToForUser { a.db = a.db.WithContext(ctx) return &a } -func (a noteToFeedBelongsToFeed) Session(session *gorm.Session) *noteToFeedBelongsToFeed { +func (a noteToFeedBelongsToForUser) Session(session *gorm.Session) *noteToFeedBelongsToForUser { a.db = a.db.Session(session) return &a } -func (a noteToFeedBelongsToFeed) Model(m *models.NoteToFeed) *noteToFeedBelongsToFeedTx { - return ¬eToFeedBelongsToFeedTx{a.db.Model(m).Association(a.Name())} +func (a noteToFeedBelongsToForUser) Model(m *models.NoteToFeed) *noteToFeedBelongsToForUserTx { + return ¬eToFeedBelongsToForUserTx{a.db.Model(m).Association(a.Name())} } -func (a noteToFeedBelongsToFeed) Unscoped() *noteToFeedBelongsToFeed { +func (a noteToFeedBelongsToForUser) Unscoped() *noteToFeedBelongsToForUser { a.db = a.db.Unscoped() return &a } -type noteToFeedBelongsToFeedTx struct{ tx *gorm.Association } +type noteToFeedBelongsToForUserTx struct{ tx *gorm.Association } -func (a noteToFeedBelongsToFeedTx) Find() (result *models.Feed, err error) { +func (a noteToFeedBelongsToForUserTx) Find() (result *models.User, err error) { return result, a.tx.Find(&result) } -func (a noteToFeedBelongsToFeedTx) Append(values ...*models.Feed) (err error) { +func (a noteToFeedBelongsToForUserTx) Append(values ...*models.User) (err error) { targetValues := make([]interface{}, len(values)) for i, v := range values { targetValues[i] = v @@ -755,7 +746,7 @@ func (a noteToFeedBelongsToFeedTx) Append(values ...*models.Feed) (err error) { return a.tx.Append(targetValues...) } -func (a noteToFeedBelongsToFeedTx) Replace(values ...*models.Feed) (err error) { +func (a noteToFeedBelongsToForUserTx) Replace(values ...*models.User) (err error) { targetValues := make([]interface{}, len(values)) for i, v := range values { targetValues[i] = v @@ -763,7 +754,7 @@ func (a noteToFeedBelongsToFeedTx) Replace(values ...*models.Feed) (err error) { return a.tx.Replace(targetValues...) } -func (a noteToFeedBelongsToFeedTx) Delete(values ...*models.Feed) (err error) { +func (a noteToFeedBelongsToForUserTx) Delete(values ...*models.User) (err error) { targetValues := make([]interface{}, len(values)) for i, v := range values { targetValues[i] = v @@ -771,15 +762,15 @@ func (a noteToFeedBelongsToFeedTx) Delete(values ...*models.Feed) (err error) { return a.tx.Delete(targetValues...) } -func (a noteToFeedBelongsToFeedTx) Clear() error { +func (a noteToFeedBelongsToForUserTx) Clear() error { return a.tx.Clear() } -func (a noteToFeedBelongsToFeedTx) Count() int64 { +func (a noteToFeedBelongsToForUserTx) Count() int64 { return a.tx.Count() } -func (a noteToFeedBelongsToFeedTx) Unscoped() *noteToFeedBelongsToFeedTx { +func (a noteToFeedBelongsToForUserTx) Unscoped() *noteToFeedBelongsToForUserTx { a.tx = a.tx.Unscoped() return &a } diff --git a/storage-new/dbgen/users.gen.go b/storage-new/dbgen/users.gen.go index 91072bd..a06e856 100644 --- a/storage-new/dbgen/users.gen.go +++ b/storage-new/dbgen/users.gen.go @@ -51,6 +51,7 @@ func newUser(db *gorm.DB, opts ...gen.DOOption) user { _user.FinishedRegistration = field.NewBool(tableName, "finished_registration") _user.PrivateKeyRsa = field.NewBytes(tableName, "private_key_rsa") _user.PrivateKeyEd = field.NewBytes(tableName, "private_key_ed") + _user.IsFeed = field.NewBool(tableName, "is_feed") _user.RawData = field.NewBytes(tableName, "raw_data") _user.RemoteInfoId = field.NewField(tableName, "remote_info_id") _user.RemoteInfo = userHasOneRemoteInfo{ @@ -393,6 +394,7 @@ type user struct { FinishedRegistration field.Bool PrivateKeyRsa field.Bytes PrivateKeyEd field.Bytes + IsFeed field.Bool RawData field.Bytes RemoteInfoId field.Field RemoteInfo userHasOneRemoteInfo @@ -457,6 +459,7 @@ func (u *user) updateTableName(table string) *user { u.FinishedRegistration = field.NewBool(table, "finished_registration") u.PrivateKeyRsa = field.NewBytes(table, "private_key_rsa") u.PrivateKeyEd = field.NewBytes(table, "private_key_ed") + u.IsFeed = field.NewBool(table, "is_feed") u.RawData = field.NewBytes(table, "raw_data") u.RemoteInfoId = field.NewField(table, "remote_info_id") @@ -475,7 +478,7 @@ func (u *user) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } func (u *user) fillFieldMap() { - u.fieldMap = make(map[string]field.Expr, 37) + u.fieldMap = make(map[string]field.Expr, 38) u.fieldMap["id"] = u.ID u.fieldMap["username"] = u.Username u.fieldMap["created_at"] = u.CreatedAt @@ -499,6 +502,7 @@ func (u *user) fillFieldMap() { u.fieldMap["finished_registration"] = u.FinishedRegistration u.fieldMap["private_key_rsa"] = u.PrivateKeyRsa u.fieldMap["private_key_ed"] = u.PrivateKeyEd + u.fieldMap["is_feed"] = u.IsFeed u.fieldMap["raw_data"] = u.RawData u.fieldMap["remote_info_id"] = u.RemoteInfoId diff --git a/storage-new/models/0allTypes.go b/storage-new/models/0allTypes.go index 19871d1..7c552f1 100644 --- a/storage-new/models/0allTypes.go +++ b/storage-new/models/0allTypes.go @@ -6,7 +6,6 @@ var AllTypes = []any{ &Collection{}, &Emote{}, &FailedOutboundRequest{}, - &Feed{}, &MediaMetadata{}, &Note{}, &NoteEdit{}, diff --git a/storage-new/models/Feed.go b/storage-new/models/Feed.go deleted file mode 100644 index d727183..0000000 --- a/storage-new/models/Feed.go +++ /dev/null @@ -1,37 +0,0 @@ -package models - -import ( - "database/sql" - - "gorm.io/gorm" -) - -// A feed is the initial entry point for inbound Activitypub events. -// However, its primary and only user-facing use case is to be a collection -// of inbound messages, nothing else. -// -// Feeds are split into two groups, default and non-default. -// Default feeds are feeds automatically created for each user, where their normal -// timeline lives in. Additionally, they also relay inbound non-note events, -// such as likes/reactions, boosts or follow requests, to their owner. -// Default feeds also act using their owner's username (others would ge a follow request from -// `username@host`). -// -// Non-default feeds, in comparison, are explicitly created by users and can be shared -// between them. Thus, they also only accept note events, dropping everything else. -// They also are explicitly labeled as such when issuing follow requests (ex `somename-feed@host`) -type Feed struct { - gorm.Model - // The name of the feed. Will be equal to the owner username if a default feed - Name string - Owner User // The owner of the feed - OwnerId string // Id of the owner - IsDefault bool // Whether the feed is the default one for the user - // If a feed is the default one for a user, use that user's public key. - // Otherwise, use its own key - PublicKey sql.NullString -} - -// Suffix added to feeds created as the default feed for a user -const FeedDefaultSuffix = "-default" -const GlobalFeedName = "global" diff --git a/storage-new/models/NoteToFeed.go b/storage-new/models/NoteToFeed.go index be93365..d73a71d 100644 --- a/storage-new/models/NoteToFeed.go +++ b/storage-new/models/NoteToFeed.go @@ -25,7 +25,7 @@ type NoteToFeed struct { CreatedAt time.Time Note Note // The note being assigned NoteId string - Feed *Feed - FeedId uint64 + ForUser *User + ForUserId string Reason string } diff --git a/storage-new/models/User.go b/storage-new/models/User.go index eee5502..1d65cc7 100644 --- a/storage-new/models/User.go +++ b/storage-new/models/User.go @@ -73,6 +73,12 @@ type User struct { FinishedRegistration bool // Whether this account has completed registration yet PrivateKeyRsa []byte PrivateKeyEd []byte + // Is this user a placeholder for a feed? + // If yes, various settings will be forcefully overwritten + // Description says that it's a feed, displayname will have -feed appended, + // all optional feeds are empty, always verified and registration complete + // not indexable, marked as bot, restricted follows with auto-reject + IsFeed bool RawData []byte diff --git a/storage-new/models/UserToUserRelation.go b/storage-new/models/UserToUserRelation.go index 2b683ee..48be52a 100644 --- a/storage-new/models/UserToUserRelation.go +++ b/storage-new/models/UserToUserRelation.go @@ -13,10 +13,6 @@ type UserToUserRelation struct { } type IUserToUserRelation interface { - // FIXME: Include local users in these queries - // Currently local users don't have an entry in user_remote_links - // causing them to be ignored by these functions as of now - // Get all inbox links for accounts following the user with the specified id // // SELECT u.inbox_link diff --git a/storage-new/self.go b/storage-new/self.go index 375779f..6c2bdab 100644 --- a/storage-new/self.go +++ b/storage-new/self.go @@ -43,9 +43,6 @@ func InsertSelf() error { if err = attachUserToRole(user); err != nil { return other.Error("storage", "failed to save/update self user to full admin role", err) } - if err = insertGlobalFeed(user); err != nil { - return other.Error("storage", "failed to ensure that the global feed exists", err) - } return nil } @@ -218,26 +215,3 @@ func attachUserToRole(user *models.User) error { } return nil } - -func insertGlobalFeed(serverActor *models.User) error { - globalFeed, err := dbgen.Feed.Where(dbgen.Feed.Name.Eq(models.GlobalFeedName)).First() - switch err { - case nil: - return nil - case gorm.ErrRecordNotFound: - globalFeed = &models.Feed{ - Owner: *serverActor, - OwnerId: serverActor.ID, - IsDefault: true, - Name: models.GlobalFeedName, - PublicKey: sql.NullString{Valid: false}, - } - err = dbgen.Feed.Create(globalFeed) - if err != nil { - return err - } - return nil - default: - return err - } -} diff --git a/web/debug/users.go b/web/debug/users.go index d0ed270..c2fea5e 100644 --- a/web/debug/users.go +++ b/web/debug/users.go @@ -183,17 +183,6 @@ func createLocalUser(w http.ResponseWriter, r *http.Request) { log.Error().Err(err).Msg("Failed to add links to new user") _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) } - err = dbgen.Feed.Create(&models.Feed{ - Owner: user, - OwnerId: user.ID, - Name: user.Username + models.FeedDefaultSuffix, - IsDefault: true, - PublicKey: sql.NullString{Valid: false}, - }) - if err != nil { - log.Error().Err(err).Msg("Failed to create default feed for new user") - _ = webutils.ProblemDetailsStatusOnly(w, http.StatusInternalServerError) - } } func deleteUser(w http.ResponseWriter, r *http.Request) { diff --git a/web/public/api/activitypub/inbox.go b/web/public/api/activitypub/inbox.go index e05597c..c0d58ed 100644 --- a/web/public/api/activitypub/inbox.go +++ b/web/public/api/activitypub/inbox.go @@ -25,6 +25,7 @@ import ( "git.mstar.dev/mstar/linstrom/activitypub/translators" "git.mstar.dev/mstar/linstrom/config" "git.mstar.dev/mstar/linstrom/shared" + "git.mstar.dev/mstar/linstrom/storage-new" "git.mstar.dev/mstar/linstrom/storage-new/dbgen" "git.mstar.dev/mstar/linstrom/storage-new/models" webshared "git.mstar.dev/mstar/linstrom/web/shared" @@ -893,7 +894,7 @@ func handleCreate(w http.ResponseWriter, r *http.Request, object map[string]any) // Includes only creator follower list -> Follower only -> only feeds that explicitly follow creator u2u := dbgen.UserToUserRelation - targetFeeds := []models.Feed{} + targetUserIds := []string{} if sliceutils.Contains(totalNoteTargets, "https://www.w3.org/ns/activitystreams#Public") { // Public post, add to global and following feeds dbNote.AccessLevel = models.NOTE_TARGET_PUBLIC @@ -905,27 +906,15 @@ func handleCreate(w http.ResponseWriter, r *http.Request, object map[string]any) Msg("Failed to get ids for followers") return false } - userFeeds, err := dbgen.Feed.Where(dbgen.Feed.OwnerId.In(followerIds...)).Find() - if err != nil { - log.Error(). - Err(err). - Str("follow-target", actingUser.ID). - Strs("follower-ids", followerIds). - Msg("Failed to get feeds for followers") - return false - } - globalFeed, err := dbgen.Feed.Where(dbgen.Feed.Name.Eq(models.GlobalFeedName)).First() - if err != nil { - log.Error(). - Err(err). - Msg("Failed to get global feed") - return false - } - targetFeeds = slices.Concat( - targetFeeds, - sliceutils.Map(userFeeds, func(t *models.Feed) models.Feed { return *t }), - ) - targetFeeds = append(targetFeeds, *globalFeed) + + // globalFeed, err := dbgen.Feed.Where(dbgen.Feed.Name.Eq(models.GlobalFeedName)).First() + // if err != nil { + // log.Error(). + // Err(err). + // Msg("Failed to get global feed") + // return false + // } + targetUserIds = append(followerIds, storage.ServerActorId) } else { if sliceutils.ContainsFunc(totalNoteTargets, func(x string) bool { return strings.HasPrefix(x, actingUser.ID) @@ -940,35 +929,22 @@ func handleCreate(w http.ResponseWriter, r *http.Request, object map[string]any) Msg("Failed to get ids for followers") return false } - userFeeds, err := dbgen.Feed.Where(dbgen.Feed.OwnerId.In(followerIds...)).Find() - if err != nil { - log.Error(). - Err(err). - Str("follow-target", actingUser.ID). - Strs("follower-ids", followerIds). - Msg("Failed to get feeds for followers") - return false - } - targetFeeds = sliceutils.Map(userFeeds, func(t *models.Feed) models.Feed { return *t }) + targetUserIds = followerIds } else { // Neither followers collection url nor public marker, private message dbNote.AccessLevel = models.NOTE_TARGET_DM - userFeeds, err := dbgen.Feed. - LeftJoin(dbgen.User, dbgen.User.ID.EqCol(dbgen.Feed.OwnerId)). - LeftJoin(dbgen.RemoteServer, dbgen.RemoteServer.ID.EqCol(dbgen.User.ServerId)). - LeftJoin(dbgen.UserRemoteLinks, dbgen.UserRemoteLinks.ID.EqCol(dbgen.User.RemoteInfoId)). - Where(dbgen.RemoteServer.IsSelf.Is(true)).Where( - dbgen.User.ID.In(totalNoteTargets...), - ).Or(dbgen.UserRemoteLinks.ApLink.In(totalNoteTargets...)).Find() + urm := dbgen.UserRemoteLinks + remoteLinks, err := urm. + Join(dbgen.User, dbgen.User.ID.EqCol(urm.UserId)). + Join(dbgen.RemoteServer, dbgen.RemoteServer.ID.EqCol(dbgen.User.ServerId)). + Where(urm.ApLink.In(totalNoteTargets...), dbgen.RemoteServer.IsSelf.Is(true)).Find() if err != nil { - log.Error(). - Err(err). - Str("follow-target", actingUser.ID). - Strs("targeted-ids", totalNoteTargets). - Msg("Failed to get feeds for directly messaged users") + log.Error().Err(err).Strs("target-ids", totalNoteTargets).Msg("Failed to get local targets for dm") return false } - targetFeeds = sliceutils.Map(userFeeds, func(t *models.Feed) models.Feed { return *t }) + targetUserIds = sliceutils.Map(remoteLinks, func(t *models.UserRemoteLinks) string { + return t.UserId + }) } } @@ -995,11 +971,11 @@ func handleCreate(w http.ResponseWriter, r *http.Request, object map[string]any) return false } - feedRels := sliceutils.Map(targetFeeds, func(f models.Feed) *models.NoteToFeed { + feedRels := sliceutils.Map(targetUserIds, func(f string) *models.NoteToFeed { return &models.NoteToFeed{ - Reason: string(models.FeedAppearanceReasonFollowUser), - NoteId: dbNote.ID, - FeedId: uint64(f.ID), + Reason: string(models.FeedAppearanceReasonFollowUser), + NoteId: dbNote.ID, + ForUserId: f, } }) err = tx.NoteToFeed.Create(feedRels...)