]> source.dussan.org Git - gitea.git/commitdiff
Move some repositories' operations to a standalone service package (#8557)
authorLunny Xiao <xiaolunwen@gmail.com>
Sat, 26 Oct 2019 06:54:11 +0000 (14:54 +0800)
committerGitHub <noreply@github.com>
Sat, 26 Oct 2019 06:54:11 +0000 (14:54 +0800)
* Move some repositories' operations to a standalone service package

* improve code

* remove unused codes

* add rollback when fork failed

* add repo when return

models/repo.go
modules/notification/indexer/indexer.go
modules/notification/webhook/webhook.go
routers/admin/repos.go
routers/api/v1/repo/fork.go
routers/api/v1/repo/repo.go
routers/repo/pull.go
routers/repo/repo.go
routers/repo/setting.go
services/repository/repository.go [new file with mode: 0644]

index 3b5395ce16409833f881ff9077d3eb0892e14a2d..ac3443f8953b4f252d64f11161564d50bf79745d 100644 (file)
@@ -742,6 +742,28 @@ func (repo *Repository) CanUserFork(user *User) (bool, error) {
        return false, nil
 }
 
+// CanUserDelete returns true if user could delete the repository
+func (repo *Repository) CanUserDelete(user *User) (bool, error) {
+       if user.IsAdmin || user.ID == repo.OwnerID {
+               return true, nil
+       }
+
+       if err := repo.GetOwner(); err != nil {
+               return false, err
+       }
+
+       if repo.Owner.IsOrganization() {
+               isOwner, err := repo.Owner.IsOwnedBy(user.ID)
+               if err != nil {
+                       return false, err
+               } else if isOwner {
+                       return true, nil
+               }
+       }
+
+       return false, nil
+}
+
 // CanEnablePulls returns true if repository meets the requirements of accepting pulls.
 func (repo *Repository) CanEnablePulls() bool {
        return !repo.IsMirror && !repo.IsEmpty
@@ -1430,15 +1452,9 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
                t, err := u.getOwnerTeam(e)
                if err != nil {
                        return fmt.Errorf("getOwnerTeam: %v", err)
-               } else if err = t.addRepository(e, repo); err != nil {
+               }
+               if err = t.addRepository(e, repo); err != nil {
                        return fmt.Errorf("addRepository: %v", err)
-               } else if err = prepareWebhooks(e, repo, HookEventRepository, &api.RepositoryPayload{
-                       Action:       api.HookRepoCreated,
-                       Repository:   repo.innerAPIFormat(e, AccessModeOwner, false),
-                       Organization: u.APIFormat(),
-                       Sender:       doer.APIFormat(),
-               }); err != nil {
-                       return fmt.Errorf("prepareWebhooks: %v", err)
                }
        } else if err = repo.recalculateAccesses(e); err != nil {
                // Organization automatically called this in addRepository method.
@@ -1522,11 +1538,6 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
                return nil, err
        }
 
-       // Add to hook queue for created repo after session commit.
-       if u.IsOrganization() {
-               go HookQueue.Add(repo.ID)
-       }
-
        return repo, err
 }
 
@@ -2044,18 +2055,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
                return fmt.Errorf("Commit: %v", err)
        }
 
-       if org.IsOrganization() {
-               if err = PrepareWebhooks(repo, HookEventRepository, &api.RepositoryPayload{
-                       Action:       api.HookRepoDeleted,
-                       Repository:   repo.APIFormat(AccessModeOwner),
-                       Organization: org.APIFormat(),
-                       Sender:       doer.APIFormat(),
-               }); err != nil {
-                       return err
-               }
-               go HookQueue.Add(repo.ID)
-       }
-
        if len(repo.Avatar) > 0 {
                avatarPath := repo.CustomAvatarPath()
                if com.IsExist(avatarPath) {
@@ -2065,7 +2064,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
                }
        }
 
-       DeleteRepoFromIndexer(repo)
        return nil
 }
 
@@ -2521,22 +2519,22 @@ func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
 }
 
 // ForkRepository forks a repository
-func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
-       forkedRepo, err := oldRepo.GetUserFork(u.ID)
+func ForkRepository(doer, owner *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
+       forkedRepo, err := oldRepo.GetUserFork(owner.ID)
        if err != nil {
                return nil, err
        }
        if forkedRepo != nil {
                return nil, ErrForkAlreadyExist{
-                       Uname:    u.Name,
+                       Uname:    owner.Name,
                        RepoName: oldRepo.FullName(),
                        ForkName: forkedRepo.FullName(),
                }
        }
 
        repo := &Repository{
-               OwnerID:       u.ID,
-               Owner:         u,
+               OwnerID:       owner.ID,
+               Owner:         owner,
                Name:          name,
                LowerName:     strings.ToLower(name),
                Description:   desc,
@@ -2553,7 +2551,7 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
                return nil, err
        }
 
-       if err = createRepository(sess, doer, u, repo); err != nil {
+       if err = createRepository(sess, doer, owner, repo); err != nil {
                return nil, err
        }
 
@@ -2561,9 +2559,9 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
                return nil, err
        }
 
-       repoPath := RepoPath(u.Name, repo.Name)
+       repoPath := RepoPath(owner.Name, repo.Name)
        _, stderr, err := process.GetManager().ExecTimeout(10*time.Minute,
-               fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
+               fmt.Sprintf("ForkRepository(git clone): %s/%s", owner.Name, repo.Name),
                git.GitExecutable, "clone", "--bare", oldRepo.repoPath(sess), repoPath)
        if err != nil {
                return nil, fmt.Errorf("git clone: %v", stderr)
@@ -2586,24 +2584,6 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
                return nil, err
        }
 
-       oldMode, _ := AccessLevel(doer, oldRepo)
-       mode, _ := AccessLevel(doer, repo)
-
-       if err = PrepareWebhooks(oldRepo, HookEventFork, &api.ForkPayload{
-               Forkee: oldRepo.APIFormat(oldMode),
-               Repo:   repo.APIFormat(mode),
-               Sender: doer.APIFormat(),
-       }); err != nil {
-               log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
-       } else {
-               go HookQueue.Add(oldRepo.ID)
-       }
-
-       // Add to hook queue for created repo after session commit.
-       if u.IsOrganization() {
-               go HookQueue.Add(repo.ID)
-       }
-
        if err = repo.UpdateSize(); err != nil {
                log.Error("Failed to update size for repository: %v", err)
        }
@@ -2612,20 +2592,19 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
        sess2 := x.NewSession()
        defer sess2.Close()
        if err = sess2.Begin(); err != nil {
-               return nil, err
+               return repo, err
        }
 
        var lfsObjects []*LFSMetaObject
-
        if err = sess2.Where("repository_id=?", oldRepo.ID).Find(&lfsObjects); err != nil {
-               return nil, err
+               return repo, err
        }
 
        for _, v := range lfsObjects {
                v.ID = 0
                v.RepositoryID = repo.ID
                if _, err = sess2.Insert(v); err != nil {
-                       return nil, err
+                       return repo, err
                }
        }
 
index 66614b2c20c7e3ccb9d304a192bb27da8255f7c7..453eb0c295e0437fd543b20676d23d430d04fcbc 100644 (file)
@@ -98,6 +98,7 @@ func (r *indexerNotifier) NotifyDeleteComment(doer *models.User, comment *models
 
 func (r *indexerNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
        issue_indexer.DeleteRepoIssueIndexer(repo)
+       models.DeleteRepoFromIndexer(repo)
 }
 
 func (r *indexerNotifier) NotifyIssueChangeContent(doer *models.User, issue *models.Issue, oldContent string) {
index 33adfaa739ba78de779ae03cf8d7640b87612e82..13f2f4486a54a5166da9f80fe8a960397606aba2 100644 (file)
@@ -65,3 +65,67 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *models.User, issue *model
                go models.HookQueue.Add(issue.RepoID)
        }
 }
+
+func (m *webhookNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
+       oldMode, _ := models.AccessLevel(doer, oldRepo)
+       mode, _ := models.AccessLevel(doer, repo)
+
+       // forked webhook
+       if err := models.PrepareWebhooks(oldRepo, models.HookEventFork, &api.ForkPayload{
+               Forkee: oldRepo.APIFormat(oldMode),
+               Repo:   repo.APIFormat(mode),
+               Sender: doer.APIFormat(),
+       }); err != nil {
+               log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
+       } else {
+               go models.HookQueue.Add(oldRepo.ID)
+       }
+
+       u := repo.MustOwner()
+
+       // Add to hook queue for created repo after session commit.
+       if u.IsOrganization() {
+               if err := models.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
+                       Action:       api.HookRepoCreated,
+                       Repository:   repo.APIFormat(models.AccessModeOwner),
+                       Organization: u.APIFormat(),
+                       Sender:       doer.APIFormat(),
+               }); err != nil {
+                       log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
+               } else {
+                       go models.HookQueue.Add(repo.ID)
+               }
+       }
+}
+
+func (m *webhookNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) {
+       // Add to hook queue for created repo after session commit.
+       if u.IsOrganization() {
+               if err := models.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
+                       Action:       api.HookRepoCreated,
+                       Repository:   repo.APIFormat(models.AccessModeOwner),
+                       Organization: u.APIFormat(),
+                       Sender:       doer.APIFormat(),
+               }); err != nil {
+                       log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
+               } else {
+                       go models.HookQueue.Add(repo.ID)
+               }
+       }
+}
+
+func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
+       u := repo.MustOwner()
+
+       if u.IsOrganization() {
+               if err := models.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
+                       Action:       api.HookRepoDeleted,
+                       Repository:   repo.APIFormat(models.AccessModeOwner),
+                       Organization: u.APIFormat(),
+                       Sender:       doer.APIFormat(),
+               }); err != nil {
+                       log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
+               }
+               go models.HookQueue.Add(repo.ID)
+       }
+}
index d345c8e76ab03305f07d44c7feed996c725ffaef..73aa66807b315a8543c734b858f9d48488310894 100644 (file)
@@ -11,6 +11,7 @@ import (
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/routers"
+       repo_service "code.gitea.io/gitea/services/repository"
 )
 
 const (
@@ -38,7 +39,7 @@ func DeleteRepo(ctx *context.Context) {
                return
        }
 
-       if err := models.DeleteRepository(ctx.User, repo.MustOwner().ID, repo.ID); err != nil {
+       if err := repo_service.DeleteRepository(ctx.User, repo); err != nil {
                ctx.ServerError("DeleteRepository", err)
                return
        }
index 7231daab292e46e38975b2f3e144e1e65a6f1d07..31f2389478c7679baa43f940fbc389b02fe793f5 100644 (file)
@@ -8,6 +8,7 @@ import (
        "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/modules/context"
        api "code.gitea.io/gitea/modules/structs"
+       repo_service "code.gitea.io/gitea/services/repository"
 )
 
 // ListForks list a repository's forks
@@ -97,10 +98,12 @@ func CreateFork(ctx *context.APIContext, form api.CreateForkOption) {
                }
                forker = org
        }
-       fork, err := models.ForkRepository(ctx.User, forker, repo, repo.Name, repo.Description)
+
+       fork, err := repo_service.ForkRepository(ctx.User, forker, repo, repo.Name, repo.Description)
        if err != nil {
                ctx.Error(500, "ForkRepository", err)
                return
        }
+
        ctx.JSON(202, fork.APIFormat(models.AccessModeOwner))
 }
index a4417107ee3848877bf7dc40f6f3de687dd7e4dc..422bb0ac3a2ef3940133d8da515c9dbc1d7e4033 100644 (file)
@@ -24,6 +24,7 @@ import (
        "code.gitea.io/gitea/modules/validation"
        "code.gitea.io/gitea/routers/api/v1/convert"
        mirror_service "code.gitea.io/gitea/services/mirror"
+       repo_service "code.gitea.io/gitea/services/repository"
 )
 
 var searchOrderByMap = map[string]map[string]models.SearchOrderBy{
@@ -207,7 +208,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
        if opt.AutoInit && opt.Readme == "" {
                opt.Readme = "Default"
        }
-       repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
+       repo, err := repo_service.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
                Name:        opt.Name,
                Description: opt.Description,
                IssueLabels: opt.IssueLabels,
@@ -224,18 +225,11 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
                        models.IsErrNamePatternNotAllowed(err) {
                        ctx.Error(422, "", err)
                } else {
-                       if repo != nil {
-                               if err = models.DeleteRepository(ctx.User, ctx.User.ID, repo.ID); err != nil {
-                                       log.Error("DeleteRepository: %v", err)
-                               }
-                       }
                        ctx.Error(500, "CreateRepository", err)
                }
                return
        }
 
-       notification.NotifyCreateRepository(ctx.User, owner, repo)
-
        ctx.JSON(201, repo.APIFormat(models.AccessModeOwner))
 }
 
@@ -433,7 +427,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
 
        repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
        if err == nil {
-               notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
+               notification.NotifyMigrateRepository(ctx.User, ctxUser, repo)
 
                log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
                ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
@@ -876,18 +870,16 @@ func Delete(ctx *context.APIContext) {
        owner := ctx.Repo.Owner
        repo := ctx.Repo.Repository
 
-       if owner.IsOrganization() && !ctx.User.IsAdmin {
-               isOwner, err := owner.IsOwnedBy(ctx.User.ID)
-               if err != nil {
-                       ctx.Error(500, "IsOwnedBy", err)
-                       return
-               } else if !isOwner {
-                       ctx.Error(403, "", "Given user is not owner of organization.")
-                       return
-               }
+       canDelete, err := repo.CanUserDelete(ctx.User)
+       if err != nil {
+               ctx.Error(500, "CanUserDelete", err)
+               return
+       } else if !canDelete {
+               ctx.Error(403, "", "Given user is not owner of organization.")
+               return
        }
 
-       if err := models.DeleteRepository(ctx.User, owner.ID, repo.ID); err != nil {
+       if err := repo_service.DeleteRepository(ctx.User, repo); err != nil {
                ctx.Error(500, "DeleteRepository", err)
                return
        }
index 23d97e7b7e200477199fe3a3018dfa817ec3fe0a..f3a9aca2a437e6f899acd8d76f20d056f862a073 100644 (file)
@@ -26,6 +26,7 @@ import (
        "code.gitea.io/gitea/services/gitdiff"
        issue_service "code.gitea.io/gitea/services/issue"
        pull_service "code.gitea.io/gitea/services/pull"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/unknwon/com"
 )
@@ -209,7 +210,7 @@ func ForkPost(ctx *context.Context, form auth.CreateRepoForm) {
                }
        }
 
-       repo, err := models.ForkRepository(ctx.User, ctxUser, forkRepo, form.RepoName, form.Description)
+       repo, err := repo_service.ForkRepository(ctx.User, ctxUser, forkRepo, form.RepoName, form.Description)
        if err != nil {
                ctx.Data["Err_RepoName"] = true
                switch {
index bfd0c771b0585d7991c0d4d06de8de904045fda7..cf1845a727bb4fb2e5c71f0c184069ebf6b61a2d 100644 (file)
@@ -17,10 +17,10 @@ import (
        "code.gitea.io/gitea/modules/git"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/migrations"
-       "code.gitea.io/gitea/modules/notification"
        "code.gitea.io/gitea/modules/setting"
        "code.gitea.io/gitea/modules/task"
        "code.gitea.io/gitea/modules/util"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/unknwon/com"
 )
@@ -170,7 +170,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
                return
        }
 
-       repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
+       repo, err := repo_service.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
                Name:        form.RepoName,
                Description: form.Description,
                Gitignores:  form.Gitignores,
@@ -181,19 +181,11 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
                AutoInit:    form.AutoInit,
        })
        if err == nil {
-               notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
-
                log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
                ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
                return
        }
 
-       if repo != nil {
-               if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
-                       log.Error("DeleteRepository: %v", errDelete)
-               }
-       }
-
        handleCreateError(ctx, ctxUser, err, "CreatePost", tplCreate, &form)
 }
 
index c74b273420de63ab828137b251ea380b6eb1283b..663394fe3db6d7571ea9529cbe1971ce8c31b286 100644 (file)
@@ -26,6 +26,7 @@ import (
        "code.gitea.io/gitea/routers/utils"
        "code.gitea.io/gitea/services/mailer"
        mirror_service "code.gitea.io/gitea/services/mirror"
+       repo_service "code.gitea.io/gitea/services/repository"
 
        "github.com/unknwon/com"
        "mvdan.cc/xurls/v2"
@@ -407,7 +408,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
                        return
                }
 
-               if err := models.DeleteRepository(ctx.User, ctx.Repo.Owner.ID, repo.ID); err != nil {
+               if err := repo_service.DeleteRepository(ctx.User, ctx.Repo.Repository); err != nil {
                        ctx.ServerError("DeleteRepository", err)
                        return
                }
diff --git a/services/repository/repository.go b/services/repository/repository.go
new file mode 100644 (file)
index 0000000..5135435
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repository
+
+import (
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/notification"
+)
+
+// CreateRepository creates a repository for the user/organization.
+func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) (*models.Repository, error) {
+       repo, err := models.CreateRepository(doer, owner, opts)
+       if err != nil {
+               if repo != nil {
+                       if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
+                               log.Error("Rollback deleteRepository: %v", errDelete)
+                       }
+               }
+               return nil, err
+       }
+
+       notification.NotifyCreateRepository(doer, owner, repo)
+
+       return repo, nil
+}
+
+// ForkRepository forks a repository
+func ForkRepository(doer, u *models.User, oldRepo *models.Repository, name, desc string) (*models.Repository, error) {
+       repo, err := models.ForkRepository(doer, u, oldRepo, name, desc)
+       if err != nil {
+               if repo != nil {
+                       if errDelete := models.DeleteRepository(doer, u.ID, repo.ID); errDelete != nil {
+                               log.Error("Rollback deleteRepository: %v", errDelete)
+                       }
+               }
+               return nil, err
+       }
+
+       notification.NotifyForkRepository(doer, oldRepo, repo)
+
+       return repo, nil
+}
+
+// DeleteRepository deletes a repository for a user or organization.
+func DeleteRepository(doer *models.User, repo *models.Repository) error {
+       if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
+               return err
+       }
+
+       notification.NotifyDeleteRepository(doer, repo)
+
+       return nil
+}