Serverside stuff. Mostly shuffling things around

This commit is contained in:
Melody Becker 2024-10-26 11:42:51 +02:00
parent 90667d96c7
commit be70109c43
20 changed files with 513 additions and 71 deletions

12
storage/emote.go Normal file
View file

@ -0,0 +1,12 @@
package storage
import "gorm.io/gorm"
type Emote struct {
gorm.Model
// Metadata MediaMetadata // `gorm:"foreignKey:MetadataId"`
MetadataId string
Name string
// Server RemoteServer // `gorm:"foreignKey:ServerId;references:ID"`
ServerId string
}

View file

@ -22,8 +22,9 @@ type Note struct {
// Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to
// If not null, this entry is marked as deleted
DeletedAt gorm.DeletedAt `gorm:"index"`
Creator string // Id of the author in the db, not the handle
Remote bool // Whether the note is originally a remote one and just "cached"
// Creator Account // `gorm:"foreignKey:CreatorId;references:ID"` // Account that created the post
CreatorId string
Remote bool // Whether the note is originally a remote one and just "cached"
// Raw content of the note. So without additional formatting applied
// Might already have formatting applied beforehand from the origin server
RawContent string

View file

@ -1,30 +1,21 @@
package storage
import (
"time"
"gorm.io/gorm"
)
type RemoteServer struct {
ID string `gorm:"primarykey"` // ID is also server url
CreatedAt time.Time // When this entry was created
UpdatedAt time.Time // When this entry was last updated
// When this entry was deleted (for soft deletions)
// Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to
// If not null, this entry is marked as deleted
DeletedAt gorm.DeletedAt `gorm:"index"`
gorm.Model
ServerType RemoteServerType // What software the server is running. Useful for formatting
Domain string // `gorm:"primaryKey"` // Domain the server exists under. Additional primary key
Name string // What the server wants to be known as (usually same as url)
Icon string // ID of a media file
IsSelf bool // Whether this server is yours truly
}
func (s *Storage) FindRemoteServer(url string) (*RemoteServer, error) {
server := RemoteServer{
ID: url,
}
err := s.db.First(&server).Error
server := RemoteServer{}
err := s.db.Where("domain = ?").First(&server).Error
switch err {
case nil:
return &server, nil
@ -63,7 +54,7 @@ func (s *Storage) NewRemoteServer(
return nil, err
}
server := RemoteServer{
ID: url,
Domain: url,
Name: displayName,
Icon: icon,
ServerType: serverType,

View file

@ -22,7 +22,7 @@ type Role struct {
gorm.Model
// Name of the role
Name string
Name string `gorm:"primaryKey"`
// Priority of the role
// Lower priority gets applied first and thus overwritten by higher priority ones

View file

@ -6,12 +6,21 @@
package storage
import (
"crypto/ed25519"
"fmt"
"github.com/rs/zerolog/log"
"gitlab.com/mstarongitlab/linstrom/config"
"gitlab.com/mstarongitlab/linstrom/storage/cache"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// Always keep a reference of the server's own RemoteServer entry here
// Removes the need to perform a db request every time a new local anything
// is created
var serverSelf RemoteServer
// Storage is responsible for all database, cache and media related actions
// and serves as the lowest layer of the cake
type Storage struct {
@ -36,10 +45,78 @@ func NewStorage(dbUrl string, cache *cache.Cache) (*Storage, error) {
InboundJob{},
OutboundJob{},
AccessToken{},
Emote{},
)
if err != nil {
return nil, fmt.Errorf("failed to apply migrations: %w", err)
}
s := &Storage{db, cache}
if err = s.insertSelfFromConfig(); err != nil {
return nil, err
}
return &Storage{db, cache}, nil
return s, nil
}
func (s *Storage) insertSelfFromConfig() error {
const ServerActorId = "self"
var err error
// Insert server info
serverData := RemoteServer{}
err = s.db.Where("id = 1").
Attrs(RemoteServer{
Domain: config.GlobalConfig.General.GetFullDomain(),
}).
Assign(RemoteServer{
IsSelf: true,
Name: config.GlobalConfig.Self.ServerDisplayName,
// Icon: "", // TODO: Set to server icon media
}).FirstOrCreate(&serverData).Error
if err != nil {
return err
}
// Set module specific global var
serverSelf = serverData
// Insert server actor
serverActor := Account{}
serverActorPublicKey, serverActorPrivateKey, err := ed25519.GenerateKey(nil)
if err != nil {
return err
}
err = s.db.Where(Account{ID: ServerActorId}).
// Values to always (re)set after launch
Assign(Account{
DisplayName: config.GlobalConfig.Self.ServerActorDisplayName,
// Server: serverData,
ServerId: serverData.ID,
// CustomFields: []uint{},
Description: "Server actor of a Linstrom server",
// Tags: []string{},
IsBot: true,
// Followers: []string{},
// Follows: []string{},
// Icon: "", // TODO: Replace with reference to server icon
// Background: "", // TODO: Replace with reference to background media
// Banner: "", // TODO: Replace with reference to banner media
Indexable: false,
RestrictedFollow: false,
IdentifiesAs: []Being{},
Gender: []string{},
Roles: []string{}, // TODO: Add server actor role once created
}).
// Values that'll only be set on first creation
Attrs(Account{
PublicKey: serverActorPublicKey,
PrivateKey: serverActorPrivateKey,
}).
FirstOrCreate(&serverActor).Error
if err != nil {
return err
}
return nil
}

View file

@ -31,21 +31,21 @@ type Account struct {
// When this entry was deleted (for soft deletions)
// Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to
// If not null, this entry is marked as deleted
DeletedAt gorm.DeletedAt `gorm:"index"`
Remote bool // Whether the account is a local or remote one
Server string // The url of the server this account is from
DisplayName string // The display name of the user. Can be different from the handle
CustomFields []uint `gorm:"serializer:json"` // IDs to the custom fields a user has
Description string // The description of a user account
Tags []string `gorm:"serializer:json"` // Hashtags
IsBot bool // Whether to mark this account as a script controlled one
Follows []string `gorm:"serializer:json"` // List of handles this account follows
Followers []string `gorm:"serializer:json"` // List of handles that follow this account
Icon string // ID of a media file used as icon
Background string // ID of a media file used as background image
Banner string // ID of a media file used as banner
Indexable bool // Whether this account can be found by crawlers
PublicKey []byte // The public key of the account
DeletedAt gorm.DeletedAt `gorm:"index"`
// Server RemoteServer // `gorm:"foreignKey:ServerId;references:ID"` // The server this user is from
ServerId uint // Id of the server this user is from, needed for including RemoteServer
DisplayName string // The display name of the user. Can be different from the handle
CustomFields []uint `gorm:"serializer:json"` // IDs to the custom fields a user has
Description string // The description of a user account
Tags []string `gorm:"serializer:json"` // Hashtags
IsBot bool // Whether to mark this account as a script controlled one
Follows []string `gorm:"serializer:json"` // List of handles this account follows
Followers []string `gorm:"serializer:json"` // List of handles that follow this account
Icon string // ID of a media file used as icon
Background string // ID of a media file used as background image
Banner string // ID of a media file used as banner
Indexable bool // Whether this account can be found by crawlers
PublicKey []byte // The public key of the account
// Whether this account restricts following
// If true, the owner must approve of a follow request first
RestrictedFollow bool
@ -346,8 +346,8 @@ func (s *Storage) NewLocalAccount(handle string) (*Account, error) {
return nil, err
}
acc.Username = handle
acc.Server = config.GlobalConfig.General.GetFullDomain()
acc.Remote = false
// acc.Server = serverSelf
acc.ServerId = serverSelf.ID
acc.DisplayName = handle
publicKey, privateKey, err := ed25519.GenerateKey(nil)
@ -419,7 +419,7 @@ func (s *Storage) GetOrCreateUser(userID string) passkey.User {
Str("account-handle", userID).
Msg("Looking for or creating account for passkey stuff")
acc := &Account{}
res := s.db.Where(Account{Username: userID, Server: config.GlobalConfig.General.GetFullDomain()}).
res := s.db.Where(Account{Username: userID, ServerId: serverSelf.ID}).
First(acc)
if errors.Is(res.Error, gorm.ErrRecordNotFound) {
log.Debug().Str("account-handle", userID)