My Very Own CI-server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
mvoCI/core/models.go

290 lines
11 KiB

package core
import (
"fmt"
"time"
"errors"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/driver/sqlite"
"gorm.io/driver/postgres"
"gorm.io/driver/mysql"
"gorm.io/driver/sqlserver"
)
// structure representing a user
type User struct {
ID uint `gorm:"primary_key"` // database ID
CreatedAt time.Time // time the record was created
UpdatedAt time.Time // time the record was last updated
Name string // the username of the user
Passhash string // a hashed password
Email string // email address of the user
Superuser bool // is the user a superuser or not?
Group []*Group `gorm:"many2many:user_groups"`
AuthProvider string // name of the main auth provider
AuthProviderExtra string // extra information for the main auth provider
AuthExtra string // extra information for the main auth provider
}
// structure for an auth provider for a single user (not shared!)
type AuthProvider struct {
ID uint `gorm:"primary_key"`
Name string // name of the auth provider
Type string // name of the auth provider module
Extra string // information of the auth provider used for verification
UserId uint // reference to the according user
User User // the user object
}
// resets a user structure to a null-value
// TODO: is that used? Maybe replace with u = core.User{} ?
func (u *User) Reset () {
u.ID = 0
u.CreatedAt = time.Unix(0,0)
u.UpdatedAt = time.Unix(0,0)
u.Name = ""
u.Passhash = ""
u.Email = ""
u.Superuser = false
u.Group = []*Group{}
}
// group information, grouping users into groups for easier access control
type Group struct {
ID uint `gorm:"primary_key"` // database ID
CreatedAt time.Time // time the record was created
UpdatedAt time.Time // time the record was last updated
Name string
User []User `gorm:"many2many:user_groups"` // a list of users in this group
}
// structure for LoginTokens, used for authentification after login
type LoginToken struct {
ID uint `gorm:"primary_key"` // database ID
CreatedAt time.Time // date of creation
ExpiresAt time.Time // Expiration Date of the loginToken
Name string // name of that LoginToken, e.g. for API tokens
UserID uint // Link to the user holding the Token
User User
Type string // api or login-token?
Secret string // a secret string
Step string // auth step, at which this loginToken sits
StepExtra string // extra information of the authProvider of the next step, e.g. for storing seeds for the next try
}
// OAuthToken for the gitea release-hook
type OauthToken struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
State string
Name string
Api string
Url string
UserID uint
ClientId string
ClientSecret string
ClientToken string
RedirectUri string
}
type Acl struct {
ID uint `gorm:"primary_key"` // database ID
CreatedAt time.Time // time the record was created
UpdatedAt time.Time // time the record was last updated
Group *Group
GroupID uint
User *User
UserID uint
Repository Repository
RepositoryID uint
AccessLevel AclLevel
}
// structure representing a Repository
type Repository struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
Name string // name of the repository
Secret string // secret of the repository to be used with the webhook feature of gitea, gogs, etc.
CloneUrl string // the clone url is to be used when building the repository for cloning and for finding out which repo needs to be build when receiving a webhook event.
BuildCount uint // number of bulds of this repository. TODO: is that used?
DefaultBranch string // default branch to be build when nothing else is specified (master or main)
BuildScript string // TODO: remove. OBSOLETE! WILL BE REMOVED SOON
BuildScripts []BuildScript // list of buildScripts for more advanced building (release vs. debug,...)
WebHookEnable bool // enable webhook events for this repository
LocalBuildEnable bool // enable local build events from cli. TODO: do I need this feature?
KeepBuilds bool // keep build artifacts?
UserID uint
User User
Acl []Acl
Public bool // is this repository to be shown on the Public Repository page? Only successful builds are shown there. Needs cfg.PublicEnable
}
// structure for build scripts
type BuildScript struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
EventType string // script for which event?
ShellScript string // shell script to be executed
RepositoryID uint
Repository Repository
}
// structure representing a Build of Repositories
type Build struct {
ID uint `gorm:"primary_key"` // database ID
CreatedAt time.Time // starting time of the build
UpdatedAt time.Time // structure last updated
StartedAt time.Time // the point when a build worker started the build
FinishedAt time.Time // time of the moment the build finished
Duration string `gorm:"-"` // duration, will not be created in database, used for calculating the duration of a build
Status string // the status of the Build (started, finished, failed)
Log string // build log
CommitSha string // stores the commit reference
CommitAuthor string // author of a commit
CommitMessage string // message of a commit
CommitUrl string // url to view the commit in the CVS-interface
Event string // event string, why the build was built
Branch string // stores the branch built
Zip string // keeps the name of the zipped Build
Repository Repository // link to the Repository
RepositoryID uint
Api string // build because of which api?
ApiUrl string
BuildScript BuildScript
BuildScriptID uint
}
// log entry for webhook events
type WebHookLog struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
Status string // of the webhook event, successful or not?
API string // which api endpoint was used?
Request string // the request body of the webhook request
ResponseBody string // body of the response sent by mvoCI
ResponseStatus int // status of the response (ideally 200 if successful)
Repository Repository // link to the Repository
RepositoryID uint
Build Build // link to the Build
BuildID uint
}
// parses the database configuration values and sets a configuration string
// for GORM accordingly, so it can set up the database connection.
// used by DBConnect
func connection_settings ( cfg *Config ) string {
var x string
switch cfg.Database.Provider {
case "sqlite3":
x = cfg.Database.Filename
case "mysql":
x = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True",
cfg.Database.Username,
cfg.Database.Password,
cfg.Database.Host,
cfg.Database.Dbname)
case "postgres":
x = fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%d sslmode=%s",
cfg.Database.Username,
cfg.Database.Password,
cfg.Database.Host,
cfg.Database.Dbname,
cfg.Database.Port,
cfg.Database.PostgresSSL)
case "mssql":
x = fmt.Sprintf("sqlserver://%s:%s@%s:%d?database=%s",
cfg.Database.Username,
cfg.Database.Password,
cfg.Database.Host,
cfg.Database.Port,
cfg.Database.Dbname)
}
return x;
}
type gormOpenFunc func(string)gorm.Dialector;
func DBMigrator ( db *gorm.DB ) error {
var root User
var rootCnt int64
db.Where ( "id=1" ).First( &root ).Count ( &rootCnt )
if rootCnt > 1 {
return errors.New("More than one root-user found, please fix users with ID=1")
}
// 2021-12-18 add groups
var publicGroup Group
var publicCount int64
db.Where ( "name=?", "Everyone" ).First( &publicGroup ).Count ( &publicCount );
if publicCount == 0 {
var us []User
db.Model( &User{} ).Find ( &us )
publicGroup.Name = "Everyone"
publicGroup.User = us
db.Save ( &publicGroup )
//db.Model ( &User{} ).Association("Group").Append([]*Group{publicGroup} )
}
return nil
}
// creates the database connection and creates the tables if they don't exist already
// depends on the following settings in the configuration ile:
// - database_provider : sets the type of database server, i.e.
// postgres, sqlite3, mssql, mysql
// - database_username : username for the database connection
// - database_password : the password for the database connection
// - database_host : if mysql, postgres or mssql - host of the database
// - database_filename : only sqlite3 - file (can be :memory)
// - database_port : communication port of the DB
// - database_dbname : the name of the database to use
func DBConnect ( cfg *Config ) (*gorm.DB, error) {
var openFn gormOpenFunc;
switch cfg.Database.Provider {
case "sqlite3":
openFn = sqlite.Open;
case "mysql":
openFn = mysql.Open;
case "postgres":
openFn = postgres.Open;
case "mssql":
openFn = sqlserver.Open;
}
gormcfg := &gorm.Config{}
if cfg.Debug {
gormcfg = &gorm.Config{
Logger: logger.Default.LogMode ( logger.Info ),
}
}
db,err := gorm.Open( openFn(connection_settings(cfg)), gormcfg );
if err == nil {
db.AutoMigrate (
&User{},
&AuthProvider{},
&Group{},
&LoginToken{},
&Repository{},
&Build{},
&WebHookLog{},
&OauthToken{},
&BuildScript{},
&Acl{},
);
err = DBMigrator ( db )
if err != nil {
return nil, err
}
return db, nil;
} else {
return nil, err
}
}