gitea
Зеркало из https://github.com/go-gitea/gitea
1// Copyright 2019 Gitea. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package admin5
6import (7"context"8"fmt"9
10"code.gitea.io/gitea/models/db"11repo_model "code.gitea.io/gitea/models/repo"12user_model "code.gitea.io/gitea/models/user"13"code.gitea.io/gitea/modules/json"14"code.gitea.io/gitea/modules/migration"15"code.gitea.io/gitea/modules/secret"16"code.gitea.io/gitea/modules/setting"17"code.gitea.io/gitea/modules/structs"18"code.gitea.io/gitea/modules/timeutil"19"code.gitea.io/gitea/modules/util"20)
21
22// Task represents a task
23type Task struct {24ID int6425DoerID int64 `xorm:"index"` // operator26Doer *user_model.User `xorm:"-"`27OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero28Owner *user_model.User `xorm:"-"`29RepoID int64 `xorm:"index"`30Repo *repo_model.Repository `xorm:"-"`31Type structs.TaskType32Status structs.TaskStatus `xorm:"index"`33StartTime timeutil.TimeStamp34EndTime timeutil.TimeStamp35PayloadContent string `xorm:"TEXT"`36Message string `xorm:"TEXT"` // if task failed, saved the error reason, it could be a JSON string of TranslatableMessage or a plain message37Created timeutil.TimeStamp `xorm:"created"`38}
39
40func init() {41db.RegisterModel(new(Task))42}
43
44// TranslatableMessage represents JSON struct that can be translated with a Locale
45type TranslatableMessage struct {46Format string47Args []any `json:"omitempty"`48}
49
50// LoadRepo loads repository of the task
51func (task *Task) LoadRepo(ctx context.Context) error {52if task.Repo != nil {53return nil54}55var repo repo_model.Repository56has, err := db.GetEngine(ctx).ID(task.RepoID).Get(&repo)57if err != nil {58return err59} else if !has {60return repo_model.ErrRepoNotExist{61ID: task.RepoID,62}63}64task.Repo = &repo65return nil66}
67
68// LoadDoer loads do user
69func (task *Task) LoadDoer(ctx context.Context) error {70if task.Doer != nil {71return nil72}73
74var doer user_model.User75has, err := db.GetEngine(ctx).ID(task.DoerID).Get(&doer)76if err != nil {77return err78} else if !has {79return user_model.ErrUserNotExist{80UID: task.DoerID,81}82}83task.Doer = &doer84
85return nil86}
87
88// LoadOwner loads owner user
89func (task *Task) LoadOwner(ctx context.Context) error {90if task.Owner != nil {91return nil92}93
94var owner user_model.User95has, err := db.GetEngine(ctx).ID(task.OwnerID).Get(&owner)96if err != nil {97return err98} else if !has {99return user_model.ErrUserNotExist{100UID: task.OwnerID,101}102}103task.Owner = &owner104
105return nil106}
107
108// UpdateCols updates some columns
109func (task *Task) UpdateCols(ctx context.Context, cols ...string) error {110_, err := db.GetEngine(ctx).ID(task.ID).Cols(cols...).Update(task)111return err112}
113
114// MigrateConfig returns task config when migrate repository
115func (task *Task) MigrateConfig() (*migration.MigrateOptions, error) {116if task.Type == structs.TaskTypeMigrateRepo {117var opts migration.MigrateOptions118err := json.Unmarshal([]byte(task.PayloadContent), &opts)119if err != nil {120return nil, err121}122
123// decrypt credentials124if opts.CloneAddrEncrypted != "" {125if opts.CloneAddr, err = secret.DecryptSecret(setting.SecretKey, opts.CloneAddrEncrypted); err != nil {126return nil, err127}128}129if opts.AuthPasswordEncrypted != "" {130if opts.AuthPassword, err = secret.DecryptSecret(setting.SecretKey, opts.AuthPasswordEncrypted); err != nil {131return nil, err132}133}134if opts.AuthTokenEncrypted != "" {135if opts.AuthToken, err = secret.DecryptSecret(setting.SecretKey, opts.AuthTokenEncrypted); err != nil {136return nil, err137}138}139
140return &opts, nil141}142return nil, fmt.Errorf("Task type is %s, not Migrate Repo", task.Type.Name())143}
144
145// ErrTaskDoesNotExist represents a "TaskDoesNotExist" kind of error.
146type ErrTaskDoesNotExist struct {147ID int64148RepoID int64149Type structs.TaskType150}
151
152// IsErrTaskDoesNotExist checks if an error is a ErrTaskDoesNotExist.
153func IsErrTaskDoesNotExist(err error) bool {154_, ok := err.(ErrTaskDoesNotExist)155return ok156}
157
158func (err ErrTaskDoesNotExist) Error() string {159return fmt.Sprintf("task does not exist [id: %d, repo_id: %d, type: %d]",160err.ID, err.RepoID, err.Type)161}
162
163func (err ErrTaskDoesNotExist) Unwrap() error {164return util.ErrNotExist165}
166
167// GetMigratingTask returns the migrating task by repo's id
168func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {169task := Task{170RepoID: repoID,171Type: structs.TaskTypeMigrateRepo,172}173has, err := db.GetEngine(ctx).Get(&task)174if err != nil {175return nil, err176} else if !has {177return nil, ErrTaskDoesNotExist{0, repoID, task.Type}178}179return &task, nil180}
181
182// CreateTask creates a task on database
183func CreateTask(ctx context.Context, task *Task) error {184return db.Insert(ctx, task)185}
186
187// FinishMigrateTask updates database when migrate task finished
188func FinishMigrateTask(ctx context.Context, task *Task) error {189task.Status = structs.TaskStatusFinished190task.EndTime = timeutil.TimeStampNow()191
192// delete credentials when we're done, they're a liability.193conf, err := task.MigrateConfig()194if err != nil {195return err196}197conf.AuthPassword = ""198conf.AuthToken = ""199conf.CloneAddr = util.SanitizeCredentialURLs(conf.CloneAddr)200conf.AuthPasswordEncrypted = ""201conf.AuthTokenEncrypted = ""202conf.CloneAddrEncrypted = ""203confBytes, err := json.Marshal(conf)204if err != nil {205return err206}207task.PayloadContent = string(confBytes)208
209_, err = db.GetEngine(ctx).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task)210return err211}
212