Skip to content

Commit

Permalink
Move some repositories' operations to a standalone service package (#…
Browse files Browse the repository at this point in the history
…8557)

* Move some repositories' operations to a standalone service package

* improve code

* remove unused codes

* add rollback when fork failed

* add repo when return
  • Loading branch information
lunny authored Oct 26, 2019
1 parent d2d5910 commit 9e85358
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 89 deletions.
91 changes: 35 additions & 56 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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) {
Expand All @@ -2065,7 +2064,6 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
}
}

DeleteRepoFromIndexer(repo)
return nil
}

Expand Down Expand Up @@ -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,
Expand All @@ -2553,17 +2551,17 @@ 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
}

if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", oldRepo.ID); err != nil {
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)
Expand All @@ -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)
}
Expand All @@ -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
}
}

Expand Down
1 change: 1 addition & 0 deletions modules/notification/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
64 changes: 64 additions & 0 deletions modules/notification/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
3 changes: 2 additions & 1 deletion routers/admin/repos.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
}
Expand Down
5 changes: 4 additions & 1 deletion routers/api/v1/repo/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
}
30 changes: 11 additions & 19 deletions routers/api/v1/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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,
Expand All @@ -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))
}

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion routers/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 9e85358

Please sign in to comment.