2019-10-13 16:23:14 +03:00
// Copyright 2019 Gitea. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2019-10-13 16:23:14 +03:00
2022-08-25 05:31:57 +03:00
package admin
2019-10-13 16:23:14 +03:00
import (
2022-05-20 17:08:52 +03:00
"context"
2019-10-13 16:23:14 +03:00
"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
)
// 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" `
2023-05-11 11:25:46 +03:00
Message string ` xorm:"TEXT" ` // if task failed, saved the error reason, it could be a JSON string of TranslatableMessage or a plain message
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
2023-07-04 21:36:08 +03:00
Args [ ] any ` json:"omitempty" `
2021-06-17 01:02:24 +03:00
}
2019-10-13 16:23:14 +03:00
// LoadRepo loads repository of the task
2023-09-16 17:39:12 +03:00
func ( task * Task ) LoadRepo ( ctx context . Context ) 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
2022-05-20 17:08:52 +03:00
has , err := db . GetEngine ( ctx ) . ID ( task . RepoID ) . Get ( & repo )
2019-10-13 16:23:14 +03:00
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
2023-09-16 17:39:12 +03:00
func ( task * Task ) LoadDoer ( ctx context . Context ) error {
2019-10-13 16:23:14 +03:00
if task . Doer != nil {
return nil
}
2021-11-24 12:49:20 +03:00
var doer user_model . User
2023-09-16 17:39:12 +03:00
has , err := db . GetEngine ( ctx ) . 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
2023-09-16 17:39:12 +03:00
func ( task * Task ) LoadOwner ( ctx context . Context ) error {
2019-10-13 16:23:14 +03:00
if task . Owner != nil {
return nil
}
2021-11-24 12:49:20 +03:00
var owner user_model . User
2023-09-16 17:39:12 +03:00
has , err := db . GetEngine ( ctx ) . 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
2023-09-16 17:39:12 +03:00
func ( task * Task ) UpdateCols ( ctx context . Context , cols ... string ) error {
_ , err := db . GetEngine ( ctx ) . 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
}
2022-06-24 16:51:37 +03:00
// IsErrTaskDoesNotExist checks if an error is a ErrTaskDoesNotExist.
2019-10-13 16:23:14 +03:00
func IsErrTaskDoesNotExist ( err error ) bool {
_ , ok := err . ( ErrTaskDoesNotExist )
return ok
}
func ( err ErrTaskDoesNotExist ) Error ( ) string {
2022-06-24 16:51:37 +03:00
return fmt . Sprintf ( "task does not exist [id: %d, repo_id: %d, type: %d]" ,
2019-10-13 16:23:14 +03:00
err . ID , err . RepoID , err . Type )
}
2022-10-18 08:50:37 +03:00
func ( err ErrTaskDoesNotExist ) Unwrap ( ) error {
return util . ErrNotExist
}
2019-10-13 16:23:14 +03:00
// GetMigratingTask returns the migrating task by repo's id
2023-09-16 17:39:12 +03:00
func GetMigratingTask ( ctx context . Context , 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 ,
}
2023-09-16 17:39:12 +03:00
has , err := db . GetEngine ( ctx ) . 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
2023-09-16 17:39:12 +03:00
func GetMigratingTaskByID ( ctx context . Context , 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 ,
}
2023-09-16 17:39:12 +03:00
has , err := db . GetEngine ( ctx ) . 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
}
2020-01-12 15:11:17 +03:00
// CreateTask creates a task on database
2023-09-16 17:39:12 +03:00
func CreateTask ( ctx context . Context , task * Task ) error {
return db . Insert ( ctx , task )
2019-10-13 16:23:14 +03:00
}
// FinishMigrateTask updates database when migrate task finished
2023-09-16 17:39:12 +03:00
func FinishMigrateTask ( ctx context . Context , task * Task ) error {
2019-10-13 16:23:14 +03:00
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 = ""
2022-03-31 05:25:40 +03:00
conf . CloneAddr = util . SanitizeCredentialURLs ( 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 )
2023-09-16 17:39:12 +03:00
_ , err = db . GetEngine ( ctx ) . ID ( task . ID ) . Cols ( "status" , "end_time" , "payload_content" ) . Update ( task )
2021-11-21 18:41:00 +03:00
return err
2019-10-13 16:23:14 +03:00
}