mirror of
https://codeberg.org/forgejo/forgejo
synced 2024-11-24 18:56:11 +01:00
34283a74e8
Fix #19513 This PR introduce a new db method `InTransaction(context.Context)`, and also builtin check on `db.TxContext` and `db.WithTx`. There is also a new method `db.AutoTx` has been introduced but could be used by other PRs. `WithTx` will always open a new transaction, if a transaction exist in context, return an error. `AutoTx` will try to open a new transaction if no transaction exist in context. That means it will always enter a transaction if there is no error. Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: 6543 <6543@obermui.de>
195 lines
5.4 KiB
Go
195 lines
5.4 KiB
Go
// Copyright 2021 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 repo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/util"
|
|
)
|
|
|
|
// UpdateRepositoryOwnerNames updates repository owner_names (this should only be used when the ownerName has changed case)
|
|
func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error {
|
|
if ownerID == 0 {
|
|
return nil
|
|
}
|
|
ctx, committer, err := db.TxContext(db.DefaultContext)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer committer.Close()
|
|
|
|
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&Repository{
|
|
OwnerName: ownerName,
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return committer.Commit()
|
|
}
|
|
|
|
// UpdateRepositoryUpdatedTime updates a repository's updated time
|
|
func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error {
|
|
_, err := db.GetEngine(db.DefaultContext).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID)
|
|
return err
|
|
}
|
|
|
|
// UpdateRepositoryCols updates repository's columns
|
|
func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string) error {
|
|
_, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).Update(repo)
|
|
return err
|
|
}
|
|
|
|
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
|
type ErrReachLimitOfRepo struct {
|
|
Limit int
|
|
}
|
|
|
|
// IsErrReachLimitOfRepo checks if an error is a ErrReachLimitOfRepo.
|
|
func IsErrReachLimitOfRepo(err error) bool {
|
|
_, ok := err.(ErrReachLimitOfRepo)
|
|
return ok
|
|
}
|
|
|
|
func (err ErrReachLimitOfRepo) Error() string {
|
|
return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit)
|
|
}
|
|
|
|
func (err ErrReachLimitOfRepo) Unwrap() error {
|
|
return util.ErrPermissionDenied
|
|
}
|
|
|
|
// ErrRepoAlreadyExist represents a "RepoAlreadyExist" kind of error.
|
|
type ErrRepoAlreadyExist struct {
|
|
Uname string
|
|
Name string
|
|
}
|
|
|
|
// IsErrRepoAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
|
func IsErrRepoAlreadyExist(err error) bool {
|
|
_, ok := err.(ErrRepoAlreadyExist)
|
|
return ok
|
|
}
|
|
|
|
func (err ErrRepoAlreadyExist) Error() string {
|
|
return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name)
|
|
}
|
|
|
|
func (err ErrRepoAlreadyExist) Unwrap() error {
|
|
return util.ErrAlreadyExist
|
|
}
|
|
|
|
// ErrRepoFilesAlreadyExist represents a "RepoFilesAlreadyExist" kind of error.
|
|
type ErrRepoFilesAlreadyExist struct {
|
|
Uname string
|
|
Name string
|
|
}
|
|
|
|
// IsErrRepoFilesAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
|
func IsErrRepoFilesAlreadyExist(err error) bool {
|
|
_, ok := err.(ErrRepoFilesAlreadyExist)
|
|
return ok
|
|
}
|
|
|
|
func (err ErrRepoFilesAlreadyExist) Error() string {
|
|
return fmt.Sprintf("repository files already exist [uname: %s, name: %s]", err.Uname, err.Name)
|
|
}
|
|
|
|
func (err ErrRepoFilesAlreadyExist) Unwrap() error {
|
|
return util.ErrAlreadyExist
|
|
}
|
|
|
|
// CheckCreateRepository check if could created a repository
|
|
func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
|
|
if !doer.CanCreateRepo() {
|
|
return ErrReachLimitOfRepo{u.MaxRepoCreation}
|
|
}
|
|
|
|
if err := IsUsableRepoName(name); err != nil {
|
|
return err
|
|
}
|
|
|
|
has, err := IsRepositoryExist(db.DefaultContext, u, name)
|
|
if err != nil {
|
|
return fmt.Errorf("IsRepositoryExist: %w", err)
|
|
} else if has {
|
|
return ErrRepoAlreadyExist{u.Name, name}
|
|
}
|
|
|
|
repoPath := RepoPath(u.Name, name)
|
|
isExist, err := util.IsExist(repoPath)
|
|
if err != nil {
|
|
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
|
|
return err
|
|
}
|
|
if !overwriteOrAdopt && isExist {
|
|
return ErrRepoFilesAlreadyExist{u.Name, name}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
|
|
func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName string) (err error) {
|
|
oldRepoName := repo.Name
|
|
newRepoName = strings.ToLower(newRepoName)
|
|
if err = IsUsableRepoName(newRepoName); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := repo.GetOwner(db.DefaultContext); err != nil {
|
|
return err
|
|
}
|
|
|
|
has, err := IsRepositoryExist(db.DefaultContext, repo.Owner, newRepoName)
|
|
if err != nil {
|
|
return fmt.Errorf("IsRepositoryExist: %w", err)
|
|
} else if has {
|
|
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
|
|
}
|
|
|
|
newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
|
|
if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil {
|
|
return fmt.Errorf("rename repository directory: %w", err)
|
|
}
|
|
|
|
wikiPath := repo.WikiPath()
|
|
isExist, err := util.IsExist(wikiPath)
|
|
if err != nil {
|
|
log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
|
|
return err
|
|
}
|
|
if isExist {
|
|
if err = util.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil {
|
|
return fmt.Errorf("rename repository wiki: %w", err)
|
|
}
|
|
}
|
|
|
|
ctx, committer, err := db.TxContext(db.DefaultContext)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer committer.Close()
|
|
|
|
if err := NewRedirect(ctx, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
|
|
return err
|
|
}
|
|
|
|
return committer.Commit()
|
|
}
|
|
|
|
// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize
|
|
func UpdateRepoSize(ctx context.Context, repoID, size int64) error {
|
|
_, err := db.GetEngine(ctx).ID(repoID).Cols("size").NoAutoTime().Update(&Repository{
|
|
Size: size,
|
|
})
|
|
return err
|
|
}
|