Files
simplegit/state/models.go
T
2026-07-29 06:51:43 -04:00

116 lines
3.3 KiB
Go

package state
import (
"fmt"
"time"
"xorm.io/xorm"
"xorm.io/xorm/names"
)
type BaseModel struct {
ID int64 `xorm:"pk autoincr" json:"id"`
CreatedAt time.Time `xorm:"created" json:"created_at"`
UpdatedAt time.Time `xorm:"updated" json:"updated_at"`
// DeletedAt *time.Time `xorm:"deleted" json:"deleted_at,omitempty"`
}
type Namespace struct {
BaseModel `xorm:"extends"`
Name string `xorm:"varchar(255) unique notnull" json:"name"`
PasswordHash string `xorm:"varchar(255)" json:"-"`
}
type Repo struct {
BaseModel `xorm:"extends"`
NamespaceID int64 `xorm:"notnull unique(cred)" json:"namespace_id"`
Name string `xorm:"varchar(255) notnull" json:"reponame"`
IsPrivate bool `xorm:"default false" json:"is_private"`
}
type SSHKey struct {
BaseModel `xorm:"extends"`
PublicKey string `xorm:"text notnull" json:"-"`
Fingerprint string `xorm:"varchar(255) unique notnull" json:"fingerprint"`
KeyType string `xorm:"varchar(50) notnull" json:"key_type"`
Comment string `xorm:"varchar(255)" json:"comment,omitempty"`
LastUsedAt *time.Time `xorm:"" json:"last_used_at,omitempty"`
}
type PAT struct {
BaseModel `xorm:"extends"`
TokenHash string `xorm:"varchar(64) unique notnull" json:"-"`
Prefix string `xorm:"varchar(20)" json:"prefix"`
Name string `xorm:"varchar(255)" json:"name"`
ExpiresAt *time.Time `xorm:"" json:"expires_at,omitempty"`
LastUsedAt *time.Time `xorm:"" json:"last_used_at,omitempty"`
}
type ACL struct {
BaseModel `xorm:"extends"`
CredType int `xorm:"notnull unique(cred) index" json:"cred_type"`
CredID int64 `xorm:"notnull unique(cred)" json:"cred_id"`
TargetType int `xorm:"notnull unique(cred) index" json:"target_type"`
TargetID int64 `xorm:"notnull unique(cred)" json:"target_id"`
Perm string `xorm:"varchar(20) default 'read'" json:"perm"`
}
type CredType int
const (
CredTypePAT CredType = 0
CredTypeSSH CredType = 1
CredTypeUserPswd CredType = 2
)
type TargetType int
const (
TargetTypeRepo TargetType = 0
TargetTypeNS TargetType = 1
)
func InitEngine(driverName, dataSourceName string) (*xorm.Engine, error) {
engine, err := xorm.NewEngine(driverName, dataSourceName)
if err != nil {
return nil, err
}
engine.SetTableMapper(names.GonicMapper{})
engine.SetColumnMapper(names.GonicMapper{})
if driverName == sqliteDriver {
if err := migrateLegacySQLite(engine); err != nil {
_ = engine.Close()
return nil, err
}
}
if err := engine.Sync2(
new(Namespace),
new(Repo),
new(SSHKey),
new(PAT),
new(ACL),
); err != nil {
return nil, err
}
return engine, nil
}
// migrateLegacySQLite handles model field renames that Sync2 otherwise treats
// as new NOT NULL columns. The migration is idempotent and preserves old repos.
func migrateLegacySQLite(engine *xorm.Engine) error {
rows, err := engine.QueryString("PRAGMA table_info(repo)")
if err != nil {
return fmt.Errorf("inspect legacy repo schema: %w", err)
}
columns := make(map[string]bool, len(rows))
for _, row := range rows {
columns[row["name"]] = true
}
if columns["repo_name"] && !columns["name"] {
if _, err := engine.Exec("ALTER TABLE repo RENAME COLUMN repo_name TO name"); err != nil {
return fmt.Errorf("migrate repo column repo_name to name: %w", err)
}
}
return nil
}