2021-12-12 18:48:20 +03:00
|
|
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
2022-11-27 21:20:29 +03:00
|
|
|
// SPDX-License-Identifier: MIT
|
2021-12-12 18:48:20 +03:00
|
|
|
|
|
|
|
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)
|
2023-09-16 17:39:12 +03:00
|
|
|
func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName string) error {
|
2021-12-12 18:48:20 +03:00
|
|
|
if ownerID == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2023-09-16 17:39:12 +03:00
|
|
|
ctx, committer, err := db.TxContext(ctx)
|
2021-12-12 18:48:20 +03:00
|
|
|
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
|
2023-09-16 17:39:12 +03:00
|
|
|
func UpdateRepositoryUpdatedTime(ctx context.Context, repoID int64, updateTime time.Time) error {
|
|
|
|
_, err := db.GetEngine(ctx).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID)
|
2021-12-12 18:48:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-05-20 17:08:52 +03:00
|
|
|
// UpdateRepositoryCols updates repository's columns
|
|
|
|
func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string) error {
|
2021-12-12 18:48:20 +03:00
|
|
|
_, 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)
|
|
|
|
}
|
|
|
|
|
2022-10-18 08:50:37 +03:00
|
|
|
func (err ErrReachLimitOfRepo) Unwrap() error {
|
|
|
|
return util.ErrPermissionDenied
|
|
|
|
}
|
|
|
|
|
2021-12-12 18:48:20 +03:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2022-10-18 08:50:37 +03:00
|
|
|
func (err ErrRepoAlreadyExist) Unwrap() error {
|
|
|
|
return util.ErrAlreadyExist
|
|
|
|
}
|
|
|
|
|
2021-12-12 18:48:20 +03:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2022-10-18 08:50:37 +03:00
|
|
|
func (err ErrRepoFilesAlreadyExist) Unwrap() error {
|
|
|
|
return util.ErrAlreadyExist
|
|
|
|
}
|
|
|
|
|
2021-12-12 18:48:20 +03:00
|
|
|
// CheckCreateRepository check if could created a repository
|
2023-09-16 17:39:12 +03:00
|
|
|
func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
|
2021-12-12 18:48:20 +03:00
|
|
|
if !doer.CanCreateRepo() {
|
|
|
|
return ErrReachLimitOfRepo{u.MaxRepoCreation}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := IsUsableRepoName(name); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:39:12 +03:00
|
|
|
has, err := IsRepositoryModelOrDirExist(ctx, u, name)
|
2021-12-12 18:48:20 +03:00
|
|
|
if err != nil {
|
2022-10-24 22:29:17 +03:00
|
|
|
return fmt.Errorf("IsRepositoryExist: %w", err)
|
2021-12-12 18:48:20 +03:00
|
|
|
} 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.
|
2023-09-16 17:39:12 +03:00
|
|
|
func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *Repository, newRepoName string) (err error) {
|
2021-12-12 18:48:20 +03:00
|
|
|
oldRepoName := repo.Name
|
|
|
|
newRepoName = strings.ToLower(newRepoName)
|
|
|
|
if err = IsUsableRepoName(newRepoName); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:39:12 +03:00
|
|
|
if err := repo.LoadOwner(ctx); err != nil {
|
2021-12-12 18:48:20 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:39:12 +03:00
|
|
|
has, err := IsRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName)
|
2021-12-12 18:48:20 +03:00
|
|
|
if err != nil {
|
2022-10-24 22:29:17 +03:00
|
|
|
return fmt.Errorf("IsRepositoryExist: %w", err)
|
2021-12-12 18:48:20 +03:00
|
|
|
} else if has {
|
|
|
|
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
|
|
|
|
}
|
|
|
|
|
|
|
|
newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
|
|
|
|
if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil {
|
2022-10-24 22:29:17 +03:00
|
|
|
return fmt.Errorf("rename repository directory: %w", err)
|
2021-12-12 18:48:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2022-10-24 22:29:17 +03:00
|
|
|
return fmt.Errorf("rename repository wiki: %w", err)
|
2021-12-12 18:48:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-16 17:39:12 +03:00
|
|
|
ctx, committer, err := db.TxContext(ctx)
|
2021-12-12 18:48:20 +03:00
|
|
|
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()
|
|
|
|
}
|
2022-06-06 11:01:49 +03:00
|
|
|
|
2023-01-13 21:54:02 +03:00
|
|
|
// UpdateRepoSize updates the repository size, calculating it using getDirectorySize
|
2023-06-29 01:41:02 +03:00
|
|
|
func UpdateRepoSize(ctx context.Context, repoID, gitSize, lfsSize int64) error {
|
|
|
|
_, err := db.GetEngine(ctx).ID(repoID).Cols("size", "git_size", "lfs_size").NoAutoTime().Update(&Repository{
|
|
|
|
Size: gitSize + lfsSize,
|
|
|
|
GitSize: gitSize,
|
|
|
|
LFSSize: lfsSize,
|
2022-06-06 11:01:49 +03:00
|
|
|
})
|
|
|
|
return err
|
|
|
|
}
|