2019-10-13 16:23:14 +03:00
// Copyright 2019 Gitea. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"fmt"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2021-07-24 19:03:58 +03:00
"code.gitea.io/gitea/modules/json"
2021-11-16 18:25:33 +03:00
"code.gitea.io/gitea/modules/migration"
2021-05-31 11:25:47 +03:00
"code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
2019-10-13 16:23:14 +03:00
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
2021-05-31 11:25:47 +03:00
"code.gitea.io/gitea/modules/util"
2019-10-13 16:23:14 +03:00
"xorm.io/builder"
)
// Task represents a task
type Task struct {
ID int64
2021-12-10 04:27:50 +03:00
DoerID int64 ` xorm:"index" ` // operator
Doer * user_model . User ` xorm:"-" `
OwnerID int64 ` xorm:"index" ` // repo owner id, when creating, the repoID maybe zero
Owner * user_model . User ` xorm:"-" `
RepoID int64 ` xorm:"index" `
Repo * repo_model . Repository ` xorm:"-" `
2019-10-13 16:23:14 +03:00
Type structs . TaskType
Status structs . TaskStatus ` xorm:"index" `
StartTime timeutil . TimeStamp
EndTime timeutil . TimeStamp
PayloadContent string ` xorm:"TEXT" `
2021-06-17 01:02:24 +03:00
Message string ` xorm:"TEXT" ` // if task failed, saved the error reason
2019-10-13 16:23:14 +03:00
Created timeutil . TimeStamp ` xorm:"created" `
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( Task ) )
}
2021-06-17 01:02:24 +03:00
// TranslatableMessage represents JSON struct that can be translated with a Locale
type TranslatableMessage struct {
Format string
Args [ ] interface { } ` json:"omitempty" `
}
2019-10-13 16:23:14 +03:00
// LoadRepo loads repository of the task
func ( task * Task ) LoadRepo ( ) error {
2021-09-23 18:45:36 +03:00
return task . loadRepo ( db . GetEngine ( db . DefaultContext ) )
2019-10-13 16:23:14 +03:00
}
2021-09-19 14:49:59 +03:00
func ( task * Task ) loadRepo ( e db . Engine ) error {
2019-10-13 16:23:14 +03:00
if task . Repo != nil {
return nil
}
2021-12-10 04:27:50 +03:00
var repo repo_model . Repository
2019-10-13 16:23:14 +03:00
has , err := e . ID ( task . RepoID ) . Get ( & repo )
if err != nil {
return err
} else if ! has {
2021-12-10 04:27:50 +03:00
return repo_model . ErrRepoNotExist {
2019-10-13 16:23:14 +03:00
ID : task . RepoID ,
}
}
task . Repo = & repo
return nil
}
// LoadDoer loads do user
func ( task * Task ) LoadDoer ( ) error {
if task . Doer != nil {
return nil
}
2021-11-24 12:49:20 +03:00
var doer user_model . User
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( db . DefaultContext ) . ID ( task . DoerID ) . Get ( & doer )
2019-10-13 16:23:14 +03:00
if err != nil {
return err
} else if ! has {
2021-11-24 12:49:20 +03:00
return user_model . ErrUserNotExist {
2019-10-13 16:23:14 +03:00
UID : task . DoerID ,
}
}
task . Doer = & doer
return nil
}
// LoadOwner loads owner user
func ( task * Task ) LoadOwner ( ) error {
if task . Owner != nil {
return nil
}
2021-11-24 12:49:20 +03:00
var owner user_model . User
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( db . DefaultContext ) . ID ( task . OwnerID ) . Get ( & owner )
2019-10-13 16:23:14 +03:00
if err != nil {
return err
} else if ! has {
2021-11-24 12:49:20 +03:00
return user_model . ErrUserNotExist {
2019-10-13 16:23:14 +03:00
UID : task . OwnerID ,
}
}
task . Owner = & owner
return nil
}
// UpdateCols updates some columns
func ( task * Task ) UpdateCols ( cols ... string ) error {
2021-09-23 18:45:36 +03:00
_ , err := db . GetEngine ( db . DefaultContext ) . ID ( task . ID ) . Cols ( cols ... ) . Update ( task )
2019-10-13 16:23:14 +03:00
return err
}
// MigrateConfig returns task config when migrate repository
2020-09-11 01:29:19 +03:00
func ( task * Task ) MigrateConfig ( ) ( * migration . MigrateOptions , error ) {
2019-10-13 16:23:14 +03:00
if task . Type == structs . TaskTypeMigrateRepo {
2020-09-11 01:29:19 +03:00
var opts migration . MigrateOptions
2019-10-13 16:23:14 +03:00
err := json . Unmarshal ( [ ] byte ( task . PayloadContent ) , & opts )
if err != nil {
return nil , err
}
2021-05-31 11:25:47 +03:00
// decrypt credentials
if opts . CloneAddrEncrypted != "" {
if opts . CloneAddr , err = secret . DecryptSecret ( setting . SecretKey , opts . CloneAddrEncrypted ) ; err != nil {
return nil , err
}
}
if opts . AuthPasswordEncrypted != "" {
if opts . AuthPassword , err = secret . DecryptSecret ( setting . SecretKey , opts . AuthPasswordEncrypted ) ; err != nil {
return nil , err
}
}
if opts . AuthTokenEncrypted != "" {
if opts . AuthToken , err = secret . DecryptSecret ( setting . SecretKey , opts . AuthTokenEncrypted ) ; err != nil {
return nil , err
}
}
2019-10-13 16:23:14 +03:00
return & opts , nil
}
return nil , fmt . Errorf ( "Task type is %s, not Migrate Repo" , task . Type . Name ( ) )
}
// ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error.
type ErrTaskDoesNotExist struct {
ID int64
RepoID int64
Type structs . TaskType
}
// IsErrTaskDoesNotExist checks if an error is a ErrTaskIsNotExist.
func IsErrTaskDoesNotExist ( err error ) bool {
_ , ok := err . ( ErrTaskDoesNotExist )
return ok
}
func ( err ErrTaskDoesNotExist ) Error ( ) string {
return fmt . Sprintf ( "task is not exist [id: %d, repo_id: %d, type: %d]" ,
err . ID , err . RepoID , err . Type )
}
// GetMigratingTask returns the migrating task by repo's id
func GetMigratingTask ( repoID int64 ) ( * Task , error ) {
2021-03-14 21:52:12 +03:00
task := Task {
2019-10-13 16:23:14 +03:00
RepoID : repoID ,
Type : structs . TaskTypeMigrateRepo ,
}
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( db . DefaultContext ) . Get ( & task )
2019-10-13 16:23:14 +03:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTaskDoesNotExist { 0 , repoID , task . Type }
}
return & task , nil
}
2020-10-24 02:46:35 +03:00
// GetMigratingTaskByID returns the migrating task by repo's id
func GetMigratingTaskByID ( id , doerID int64 ) ( * Task , * migration . MigrateOptions , error ) {
2021-03-14 21:52:12 +03:00
task := Task {
2020-10-24 02:46:35 +03:00
ID : id ,
DoerID : doerID ,
Type : structs . TaskTypeMigrateRepo ,
}
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( db . DefaultContext ) . Get ( & task )
2020-10-24 02:46:35 +03:00
if err != nil {
return nil , nil , err
} else if ! has {
return nil , nil , ErrTaskDoesNotExist { id , 0 , task . Type }
}
var opts migration . MigrateOptions
if err := json . Unmarshal ( [ ] byte ( task . PayloadContent ) , & opts ) ; err != nil {
return nil , nil , err
}
return & task , & opts , nil
}
2019-10-13 16:23:14 +03:00
// FindTaskOptions find all tasks
type FindTaskOptions struct {
Status int
}
// ToConds generates conditions for database operation.
func ( opts FindTaskOptions ) ToConds ( ) builder . Cond {
2021-03-14 21:52:12 +03:00
cond := builder . NewCond ( )
2019-10-13 16:23:14 +03:00
if opts . Status >= 0 {
cond = cond . And ( builder . Eq { "status" : opts . Status } )
}
return cond
}
// FindTasks find all tasks
func FindTasks ( opts FindTaskOptions ) ( [ ] * Task , error ) {
2021-03-14 21:52:12 +03:00
tasks := make ( [ ] * Task , 0 , 10 )
2021-09-23 18:45:36 +03:00
err := db . GetEngine ( db . DefaultContext ) . Where ( opts . ToConds ( ) ) . Find ( & tasks )
2019-10-13 16:23:14 +03:00
return tasks , err
}
2020-01-12 15:11:17 +03:00
// CreateTask creates a task on database
func CreateTask ( task * Task ) error {
2021-09-23 18:45:36 +03:00
return createTask ( db . GetEngine ( db . DefaultContext ) , task )
2020-01-12 15:11:17 +03:00
}
2021-09-19 14:49:59 +03:00
func createTask ( e db . Engine , task * Task ) error {
2019-10-13 16:23:14 +03:00
_ , err := e . Insert ( task )
return err
}
// FinishMigrateTask updates database when migrate task finished
func FinishMigrateTask ( task * Task ) error {
task . Status = structs . TaskStatusFinished
task . EndTime = timeutil . TimeStampNow ( )
2021-05-31 11:25:47 +03:00
// delete credentials when we're done, they're a liability.
conf , err := task . MigrateConfig ( )
if err != nil {
return err
}
conf . AuthPassword = ""
conf . AuthToken = ""
2021-06-14 20:20:43 +03:00
conf . CloneAddr = util . NewStringURLSanitizer ( conf . CloneAddr , true ) . Replace ( conf . CloneAddr )
2021-05-31 11:25:47 +03:00
conf . AuthPasswordEncrypted = ""
conf . AuthTokenEncrypted = ""
conf . CloneAddrEncrypted = ""
confBytes , err := json . Marshal ( conf )
if err != nil {
return err
}
task . PayloadContent = string ( confBytes )
2021-11-21 18:41:00 +03:00
_ , err = db . GetEngine ( db . DefaultContext ) . ID ( task . ID ) . Cols ( "status" , "end_time" , "payload_content" ) . Update ( task )
return err
2019-10-13 16:23:14 +03:00
}