Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move some repositories' operations to a standalone service package #8557

Merged
merged 11 commits into from
Oct 26, 2019
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 @@ -25,6 +25,7 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"

"github.com/unknwon/com"
)
Expand Down Expand Up @@ -208,7 +209,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