Lots of work
This commit is contained in:
parent
a2a937791d
commit
3086b0e9b4
28 changed files with 1284 additions and 2 deletions
22
storage/mediaFile.go
Normal file
22
storage/mediaFile.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type MediaFile struct {
|
||||
ID string `gorm:"primarykey"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
Remote bool // whether the attachment is a remote one
|
||||
Link string // url if remote attachment, identifier if local
|
||||
// Whether this media has been cached locally
|
||||
// Only really used for user and server icons, not attachments
|
||||
// Reason: Attachments would take way to much space considering that they are often only loaded a few times at most
|
||||
// And caching a file for those few times would be a waste of storage
|
||||
// Caching user and server icons locally however should reduce burden on remote servers by quite a bit though
|
||||
LocallyCached bool
|
||||
}
|
28
storage/noteTargets.go
Normal file
28
storage/noteTargets.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type NoteTarget uint8
|
||||
|
||||
const (
|
||||
NOTE_TARGET_PUBLIC = NoteTarget(0)
|
||||
NOTE_TARGET_HOME = NoteTarget(1 << iota)
|
||||
NOTE_TARGET_FOLLOWERS
|
||||
NOTE_TARGET_DM
|
||||
)
|
||||
|
||||
func (n *NoteTarget) Value() (driver.Value, error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (n *NoteTarget) Scan(value any) error {
|
||||
vBig, ok := value.(int64)
|
||||
if !ok {
|
||||
return errors.New("not an int64")
|
||||
}
|
||||
*n = NoteTarget(vBig)
|
||||
return nil
|
||||
}
|
28
storage/notes.go
Normal file
28
storage/notes.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Note struct {
|
||||
ID string `gorm:"primarykey"` // Make ID a string (uuid) for other implementations
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
Creator string // Full handle of the creator, eg: @max@example.com
|
||||
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
|
||||
ContentWarning *string // Content warnings of the note, if it contains any
|
||||
Attachments []string `gorm:"serializer:json"` // Links to attachments
|
||||
Emotes []string `gorm:"serializer:json"` // Emotes used in that message
|
||||
RepliesTo *string // Url of the message this replies to
|
||||
Quotes *string // url of the message this note quotes
|
||||
Target NoteTarget // Where to send this message to (public, home, followers, dm)
|
||||
Pings []string `gorm:"serializer:json"` // Who is being tagged in this message. Also serves as DM targets
|
||||
OriginServer string // Url of the origin server. Also the primary key for those
|
||||
Tags []string `gorm:"serializer:json"` // Hashtags
|
||||
}
|
18
storage/remoteServerInfo.go
Normal file
18
storage/remoteServerInfo.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type RemoteServer struct {
|
||||
ID string `gorm:"primarykey"` // ID is also server url
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
||||
ServerType RemoteServerType // What software the server is running. Useful for formatting
|
||||
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
|
||||
}
|
33
storage/serverTypes.go
Normal file
33
storage/serverTypes.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Mostly important for rendering
|
||||
type RemoteServerType string
|
||||
|
||||
const (
|
||||
// Includes forks like glitch-soc, etc
|
||||
REMOTE_SERVER_MASTODON = RemoteServerType("Mastodon")
|
||||
// Includes forks like Ice Shrimp, Sharkey, Cutiekey, etc
|
||||
REMOTE_SERVER_MISSKEY = RemoteServerType("Misskey")
|
||||
// Includes Akkoma
|
||||
REMOTE_SERVER_PLEMORA = RemoteServerType("Plemora")
|
||||
// And of course, yours truly
|
||||
REMOTE_SERVER_LINSTROM = RemoteServerType("Linstrom")
|
||||
)
|
||||
|
||||
func (r *RemoteServerType) Value() (driver.Value, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *RemoteServerType) Scan(raw any) error {
|
||||
if v, ok := raw.(string); ok {
|
||||
*r = RemoteServerType(v)
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("value not a string")
|
||||
}
|
||||
}
|
36
storage/storage.go
Normal file
36
storage/storage.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewStorageSqlite(filePath string) (*Storage, error) {
|
||||
db, err := gorm.Open(sqlite.Open(filePath))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Storage{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewStoragePostgres(dbUrl string) (*Storage, error) {
|
||||
db, err := gorm.Open(postgres.Open(dbUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Storage{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: Placeholder. Update to proper implementation later. Including signature
|
||||
func (s *Storage) FindLocalAccount(handle string) (string, error) {
|
||||
return handle, nil
|
||||
}
|
67
storage/user.go
Normal file
67
storage/user.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Database representation of a user account
|
||||
// This can be a bot, remote or not
|
||||
// If remote, this is used for caching the account
|
||||
type User struct {
|
||||
ID string `gorm:"primarykey"` // ID is the full handle, eg @max@example.com
|
||||
CreatedAt time.Time // When this entry was created
|
||||
UpdatedAt time.Time // When this account was last updated. Will also be used for refreshing remote accounts
|
||||
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
|
||||
PublicKeyPem string // The public key of the account
|
||||
// Whether this account restricts following
|
||||
// If true, the owner must approve of a follow request first
|
||||
RestrictedFollow bool
|
||||
// List of things the owner identifies as
|
||||
// Example [cat human robot] means that the owner probably identifies as
|
||||
// a cyborg-catgirl/boy/human
|
||||
IdentifiesAs []Being
|
||||
// List of pronouns the owner identifies with
|
||||
// An unordered list since the owner can freely set it
|
||||
// Examples: [she her], [it they its them]
|
||||
Gender []string
|
||||
|
||||
// --- And internal account stuff ---
|
||||
// Still public fields since they wouldn't be able to be stored in the db otherwise
|
||||
|
||||
PasswordHash []byte // Hash of the user's password
|
||||
TotpToken []byte // Token for totp verification
|
||||
// All the registered passkeys, name of passkey to credentials
|
||||
// Could this be exported to another table? Yes
|
||||
// Would it make sense? Probably not
|
||||
// Will just take the performance hit of json conversion
|
||||
// Access should be rare enough anyway
|
||||
Passkeys map[string]webauthn.Credential `gorm:"serializer:json"`
|
||||
PrivateKeyPem *string // The private key of the account. Nil if remote user
|
||||
}
|
||||
|
||||
func NewEmptyUser() *User {
|
||||
return &User{
|
||||
ID: uuid.NewString(),
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
Remote: false,
|
||||
Server: "placeholder",
|
||||
}
|
||||
}
|
30
storage/userIdentType.go
Normal file
30
storage/userIdentType.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Being string
|
||||
|
||||
const (
|
||||
BEING_HUMAN = Being("human")
|
||||
BEING_CAT = Being("cat")
|
||||
BEING_FOX = Being("fox")
|
||||
BEING_DOG = Being("dog")
|
||||
BEING_ROBOT = Being("robot")
|
||||
BEING_DOLL = Being("doll")
|
||||
)
|
||||
|
||||
func (r *Being) Value() (driver.Value, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *Being) Scan(raw any) error {
|
||||
if v, ok := raw.(string); ok {
|
||||
*r = Being(v)
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("value not a string")
|
||||
}
|
||||
}
|
14
storage/userInfoFields.go
Normal file
14
storage/userInfoFields.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserInfoField struct {
|
||||
gorm.Model // Can actually just embed this as is here as those are not something directly exposed :3
|
||||
Name string
|
||||
Value string
|
||||
LastUrlCheckDate *time.Time // Used if the value is an url to somewhere. Empty if value is not an url
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue