aboutsummaryrefslogtreecommitdiffstats
path: root/models/admin
diff options
context:
space:
mode:
Diffstat (limited to 'models/admin')
-rw-r--r--models/admin/main_test.go7
-rw-r--r--models/admin/notice_test.go73
-rw-r--r--models/admin/task.go264
3 files changed, 306 insertions, 38 deletions
diff --git a/models/admin/main_test.go b/models/admin/main_test.go
index 693b70fbf7..23277fe37c 100644
--- a/models/admin/main_test.go
+++ b/models/admin/main_test.go
@@ -2,18 +2,21 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package admin
+package admin_test
import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models/unittest"
+
+ _ "code.gitea.io/gitea/models"
+ _ "code.gitea.io/gitea/models/activities"
+ _ "code.gitea.io/gitea/models/perm/access"
)
func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."),
- FixtureFiles: []string{"notice.yml"},
})
}
diff --git a/models/admin/notice_test.go b/models/admin/notice_test.go
index b4613db8e7..f3767392d1 100644
--- a/models/admin/notice_test.go
+++ b/models/admin/notice_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package admin
+package admin_test
import (
"testing"
+ "code.gitea.io/gitea/models/admin"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
@@ -14,8 +15,8 @@ import (
)
func TestNotice_TrStr(t *testing.T) {
- notice := &Notice{
- Type: NoticeRepository,
+ notice := &admin.Notice{
+ Type: admin.NoticeRepository,
Description: "test description",
}
assert.Equal(t, "admin.notices.type_1", notice.TrStr())
@@ -24,24 +25,24 @@ func TestNotice_TrStr(t *testing.T) {
func TestCreateNotice(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- noticeBean := &Notice{
- Type: NoticeRepository,
+ noticeBean := &admin.Notice{
+ Type: admin.NoticeRepository,
Description: "test description",
}
unittest.AssertNotExistsBean(t, noticeBean)
- assert.NoError(t, CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
+ assert.NoError(t, admin.CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
unittest.AssertExistsAndLoadBean(t, noticeBean)
}
func TestCreateRepositoryNotice(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- noticeBean := &Notice{
- Type: NoticeRepository,
+ noticeBean := &admin.Notice{
+ Type: admin.NoticeRepository,
Description: "test description",
}
unittest.AssertNotExistsBean(t, noticeBean)
- assert.NoError(t, CreateRepositoryNotice(noticeBean.Description))
+ assert.NoError(t, admin.CreateRepositoryNotice(noticeBean.Description))
unittest.AssertExistsAndLoadBean(t, noticeBean)
}
@@ -49,20 +50,20 @@ func TestCreateRepositoryNotice(t *testing.T) {
func TestCountNotices(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- assert.Equal(t, int64(3), CountNotices())
+ assert.Equal(t, int64(3), admin.CountNotices())
}
func TestNotices(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- notices, err := Notices(1, 2)
+ notices, err := admin.Notices(1, 2)
assert.NoError(t, err)
if assert.Len(t, notices, 2) {
assert.Equal(t, int64(3), notices[0].ID)
assert.Equal(t, int64(2), notices[1].ID)
}
- notices, err = Notices(2, 2)
+ notices, err = admin.Notices(2, 2)
assert.NoError(t, err)
if assert.Len(t, notices, 1) {
assert.Equal(t, int64(1), notices[0].ID)
@@ -72,45 +73,45 @@ func TestNotices(t *testing.T) {
func TestDeleteNotice(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
- assert.NoError(t, DeleteNotice(3))
- unittest.AssertNotExistsBean(t, &Notice{ID: 3})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
+ assert.NoError(t, admin.DeleteNotice(3))
+ unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
}
func TestDeleteNotices(t *testing.T) {
// delete a non-empty range
assert.NoError(t, unittest.PrepareTestDatabase())
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
- assert.NoError(t, DeleteNotices(1, 2))
- unittest.AssertNotExistsBean(t, &Notice{ID: 1})
- unittest.AssertNotExistsBean(t, &Notice{ID: 2})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
+ assert.NoError(t, admin.DeleteNotices(1, 2))
+ unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
+ unittest.AssertNotExistsBean(t, &admin.Notice{ID: 2})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
}
func TestDeleteNotices2(t *testing.T) {
// delete an empty range
assert.NoError(t, unittest.PrepareTestDatabase())
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
- assert.NoError(t, DeleteNotices(3, 2))
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
+ assert.NoError(t, admin.DeleteNotices(3, 2))
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
}
func TestDeleteNoticesByIDs(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
- assert.NoError(t, DeleteNoticesByIDs([]int64{1, 3}))
- unittest.AssertNotExistsBean(t, &Notice{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
- unittest.AssertNotExistsBean(t, &Notice{ID: 3})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
+ assert.NoError(t, admin.DeleteNoticesByIDs([]int64{1, 3}))
+ unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
+ unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
+ unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
}
diff --git a/models/admin/task.go b/models/admin/task.go
new file mode 100644
index 0000000000..07eb61decc
--- /dev/null
+++ b/models/admin/task.go
@@ -0,0 +1,264 @@
+// 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 admin
+
+import (
+ "context"
+ "fmt"
+
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/migration"
+ "code.gitea.io/gitea/modules/secret"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
+
+ "xorm.io/builder"
+)
+
+// Task represents a task
+type Task struct {
+ ID int64
+ 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:"-"`
+ Type structs.TaskType
+ Status structs.TaskStatus `xorm:"index"`
+ StartTime timeutil.TimeStamp
+ EndTime timeutil.TimeStamp
+ PayloadContent string `xorm:"TEXT"`
+ Message string `xorm:"TEXT"` // if task failed, saved the error reason
+ Created timeutil.TimeStamp `xorm:"created"`
+}
+
+func init() {
+ db.RegisterModel(new(Task))
+}
+
+// TranslatableMessage represents JSON struct that can be translated with a Locale
+type TranslatableMessage struct {
+ Format string
+ Args []interface{} `json:"omitempty"`
+}
+
+// LoadRepo loads repository of the task
+func (task *Task) LoadRepo() error {
+ return task.loadRepo(db.DefaultContext)
+}
+
+func (task *Task) loadRepo(ctx context.Context) error {
+ if task.Repo != nil {
+ return nil
+ }
+ var repo repo_model.Repository
+ has, err := db.GetEngine(ctx).ID(task.RepoID).Get(&repo)
+ if err != nil {
+ return err
+ } else if !has {
+ return repo_model.ErrRepoNotExist{
+ ID: task.RepoID,
+ }
+ }
+ task.Repo = &repo
+ return nil
+}
+
+// LoadDoer loads do user
+func (task *Task) LoadDoer() error {
+ if task.Doer != nil {
+ return nil
+ }
+
+ var doer user_model.User
+ has, err := db.GetEngine(db.DefaultContext).ID(task.DoerID).Get(&doer)
+ if err != nil {
+ return err
+ } else if !has {
+ return user_model.ErrUserNotExist{
+ UID: task.DoerID,
+ }
+ }
+ task.Doer = &doer
+
+ return nil
+}
+
+// LoadOwner loads owner user
+func (task *Task) LoadOwner() error {
+ if task.Owner != nil {
+ return nil
+ }
+
+ var owner user_model.User
+ has, err := db.GetEngine(db.DefaultContext).ID(task.OwnerID).Get(&owner)
+ if err != nil {
+ return err
+ } else if !has {
+ return user_model.ErrUserNotExist{
+ UID: task.OwnerID,
+ }
+ }
+ task.Owner = &owner
+
+ return nil
+}
+
+// UpdateCols updates some columns
+func (task *Task) UpdateCols(cols ...string) error {
+ _, err := db.GetEngine(db.DefaultContext).ID(task.ID).Cols(cols...).Update(task)
+ return err
+}
+
+// MigrateConfig returns task config when migrate repository
+func (task *Task) MigrateConfig() (*migration.MigrateOptions, error) {
+ if task.Type == structs.TaskTypeMigrateRepo {
+ var opts migration.MigrateOptions
+ err := json.Unmarshal([]byte(task.PayloadContent), &opts)
+ if err != nil {
+ return nil, err
+ }
+
+ // 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
+ }
+ }
+
+ 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 ErrTaskDoesNotExist.
+func IsErrTaskDoesNotExist(err error) bool {
+ _, ok := err.(ErrTaskDoesNotExist)
+ return ok
+}
+
+func (err ErrTaskDoesNotExist) Error() string {
+ return fmt.Sprintf("task does 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) {
+ task := Task{
+ RepoID: repoID,
+ Type: structs.TaskTypeMigrateRepo,
+ }
+ has, err := db.GetEngine(db.DefaultContext).Get(&task)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, ErrTaskDoesNotExist{0, repoID, task.Type}
+ }
+ return &task, nil
+}
+
+// HasFinishedMigratingTask returns if a finished migration task exists for the repo.
+func HasFinishedMigratingTask(repoID int64) (bool, error) {
+ return db.GetEngine(db.DefaultContext).
+ Where("repo_id=? AND type=? AND status=?", repoID, structs.TaskTypeMigrateRepo, structs.TaskStatusFinished).
+ Table("task").
+ Exist()
+}
+
+// GetMigratingTaskByID returns the migrating task by repo's id
+func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, error) {
+ task := Task{
+ ID: id,
+ DoerID: doerID,
+ Type: structs.TaskTypeMigrateRepo,
+ }
+ has, err := db.GetEngine(db.DefaultContext).Get(&task)
+ 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
+}
+
+// FindTaskOptions find all tasks
+type FindTaskOptions struct {
+ Status int
+}
+
+// ToConds generates conditions for database operation.
+func (opts FindTaskOptions) ToConds() builder.Cond {
+ cond := builder.NewCond()
+ if opts.Status >= 0 {
+ cond = cond.And(builder.Eq{"status": opts.Status})
+ }
+ return cond
+}
+
+// FindTasks find all tasks
+func FindTasks(opts FindTaskOptions) ([]*Task, error) {
+ tasks := make([]*Task, 0, 10)
+ err := db.GetEngine(db.DefaultContext).Where(opts.ToConds()).Find(&tasks)
+ return tasks, err
+}
+
+// CreateTask creates a task on database
+func CreateTask(task *Task) error {
+ return db.Insert(db.DefaultContext, task)
+}
+
+// FinishMigrateTask updates database when migrate task finished
+func FinishMigrateTask(task *Task) error {
+ task.Status = structs.TaskStatusFinished
+ task.EndTime = timeutil.TimeStampNow()
+
+ // delete credentials when we're done, they're a liability.
+ conf, err := task.MigrateConfig()
+ if err != nil {
+ return err
+ }
+ conf.AuthPassword = ""
+ conf.AuthToken = ""
+ conf.CloneAddr = util.SanitizeCredentialURLs(conf.CloneAddr)
+ conf.AuthPasswordEncrypted = ""
+ conf.AuthTokenEncrypted = ""
+ conf.CloneAddrEncrypted = ""
+ confBytes, err := json.Marshal(conf)
+ if err != nil {
+ return err
+ }
+ task.PayloadContent = string(confBytes)
+
+ _, err = db.GetEngine(db.DefaultContext).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task)
+ return err
+}