0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-14 19:38:04 +02:00
This commit is contained in:
☙◦ The Tablet ❀ GamerGirlandCo ◦❧ 2025-08-17 19:36:48 -04:00
parent ba0c7caabb
commit d1af473553
No known key found for this signature in database
GPG Key ID: 924A5F6AF051E87C
14 changed files with 252 additions and 105 deletions

View File

@ -228,13 +228,21 @@ func init() {
db.RegisterModel(new(Repository))
}
func RelativePath(ownerName, repoName string) string {
return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".git"
func RelativePathBaseName(ownerName, repoName string, groupID int64) string {
var groupSegment string
if groupID > 0 {
groupSegment = strconv.FormatInt(groupID, 10) + "/"
}
return strings.ToLower(ownerName) + "/" + groupSegment + strings.ToLower(repoName)
}
func RelativePath(ownerName, repoName string, groupID int64) string {
return RelativePathBaseName(ownerName, repoName, groupID) + ".git"
}
// RelativePath should be an unix style path like username/reponame.git
func (repo *Repository) RelativePath() string {
return RelativePath(repo.OwnerName, repo.Name)
return RelativePath(repo.OwnerName, repo.Name, repo.GroupID)
}
type StorageRepo string
@ -582,13 +590,19 @@ func (repo *Repository) IsGenerated() bool {
}
// RepoPath returns repository path by given user and repository name.
func RepoPath(userName, repoName string) string { //revive:disable-line:exported
return filepath.Join(setting.RepoRootPath, filepath.Clean(strings.ToLower(userName)), filepath.Clean(strings.ToLower(repoName)+".git"))
func RepoPath(userName, repoName string, groupID int64) string { //revive:disable-line:exported
var joinArgs []string
joinArgs = append(joinArgs, user_model.UserPath(userName))
if groupID > 0 {
joinArgs = append(joinArgs, strconv.FormatInt(groupID, 10))
}
joinArgs = append(joinArgs, strings.ToLower(repoName)+".git")
return filepath.Join(joinArgs...)
}
// RepoPath returns the repository path
func (repo *Repository) RepoPath() string {
return RepoPath(repo.OwnerName, repo.Name)
return RepoPath(repo.OwnerName, repo.Name, repo.GroupID)
}
// Link returns the repository relative url
@ -658,13 +672,25 @@ type CloneLink struct {
Tea string
}
func getGroupSegment(gid int64) string {
var groupSegment string
if gid > 0 {
groupSegment = fmt.Sprintf("%d", gid)
}
return groupSegment
}
func groupSegmentWithTrailingSlash(gid int64) string {
return getGroupSegment(gid) + "/"
}
// ComposeHTTPSCloneURL returns HTTPS clone URL based on the given owner and repository name.
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string, groupID int64) string {
return fmt.Sprintf("%s%s/%s%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), groupSegmentWithTrailingSlash(groupID), url.PathEscape(repo))
}
// ComposeSSHCloneURL returns SSH clone URL based on the given owner and repository name.
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string, groupID int64) string {
sshUser := setting.SSH.User
sshDomain := setting.SSH.Domain
@ -683,7 +709,7 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
// non-standard port, it must use full URI
if setting.SSH.Port != 22 {
sshHost := net.JoinHostPort(sshDomain, strconv.Itoa(setting.SSH.Port))
return fmt.Sprintf("ssh://%s@%s/%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
return fmt.Sprintf("ssh://%s@%s/%s%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), groupSegmentWithTrailingSlash(groupID), url.PathEscape(repoName))
}
// for standard port, it can use a shorter URI (without the port)
@ -698,25 +724,25 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
}
// ComposeTeaCloneCommand returns Tea CLI clone command based on the given owner and repository name.
func ComposeTeaCloneCommand(ctx context.Context, owner, repo string) string {
return fmt.Sprintf("tea clone %s/%s", url.PathEscape(owner), url.PathEscape(repo))
func ComposeTeaCloneCommand(ctx context.Context, owner, repo string, groupID int64) string {
return fmt.Sprintf("tea clone %s/%s%s", url.PathEscape(owner), url.PathEscape(repo), groupSegmentWithTrailingSlash(groupID))
}
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string, groupID int64) *CloneLink {
return &CloneLink{
SSH: ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName),
HTTPS: ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName),
Tea: ComposeTeaCloneCommand(ctx, repo.OwnerName, repoPathName),
SSH: ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName, groupID),
HTTPS: ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName, groupID),
Tea: ComposeTeaCloneCommand(ctx, repo.OwnerName, repoPathName, groupID),
}
}
// CloneLink returns clone URLs of repository.
func (repo *Repository) CloneLink(ctx context.Context, doer *user_model.User) (cl *CloneLink) {
return repo.cloneLink(ctx, doer, repo.Name)
return repo.cloneLink(ctx, doer, repo.Name, repo.GroupID)
}
func (repo *Repository) CloneLinkGeneral(ctx context.Context) (cl *CloneLink) {
return repo.cloneLink(ctx, nil /* no doer, use a general git user */, repo.Name)
return repo.cloneLink(ctx, nil /* no doer, use a general git user */, repo.Name, repo.GroupID)
}
// GetOriginalURLHostname returns the hostname of a URL or the URL
@ -854,10 +880,11 @@ func GetRepositoriesMapByIDs(ctx context.Context, ids []int64) (map[int64]*Repos
return repos, db.GetEngine(ctx).In("id", ids).Find(&repos)
}
func IsRepositoryModelExist(ctx context.Context, u *user_model.User, repoName string) (bool, error) {
func IsRepositoryModelExist(ctx context.Context, u *user_model.User, repoName string, groupID int64) (bool, error) {
return db.GetEngine(ctx).Get(&Repository{
OwnerID: u.ID,
LowerName: strings.ToLower(repoName),
GroupID: groupID,
})
}

View File

@ -254,7 +254,7 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m
}
// Check if new owner has repository with same name.
if has, err := IsRepositoryModelExist(ctx, newOwner, repo.Name); err != nil {
if has, err := IsRepositoryModelExist(ctx, newOwner, repo.Name, repo.GroupID); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return ErrRepoAlreadyExist{

View File

@ -5,12 +5,10 @@
package repo
import (
"context"
"fmt"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/util"
"context"
"fmt"
)
// ErrWikiAlreadyExist represents a "WikiAlreadyExist" kind of error.
@ -72,15 +70,13 @@ func (err ErrWikiInvalidFileName) Unwrap() error {
// WikiCloneLink returns clone URLs of repository wiki.
func (repo *Repository) WikiCloneLink(ctx context.Context, doer *user_model.User) *CloneLink {
return repo.cloneLink(ctx, doer, repo.Name+".wiki")
return repo.cloneLink(ctx, doer, repo.Name+".wiki", repo.GroupID)
}
func RelativeWikiPath(ownerName, repoName string) string {
return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".wiki.git"
func RelativeWikiPath(ownerName, repoName string, groupID int64) string {
return RelativePathBaseName(ownerName, repoName, groupID) + ".wiki.git"
}
// WikiStorageRepo returns the storage repo for the wiki
// The wiki repository should have the same object format as the code repository
func (repo *Repository) WikiStorageRepo() StorageRepo {
return StorageRepo(RelativeWikiPath(repo.OwnerName, repo.Name))
return StorageRepo(RelativeWikiPath(repo.OwnerName, repo.Name, repo.GroupID))
}

View File

@ -55,6 +55,47 @@ func ListUnadoptedRepositories(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, repoNames)
}
func commonAdoptRepository(ctx *context.APIContext) {
ownerName := ctx.PathParam("username")
repoName := ctx.PathParam("reponame")
groupID := ctx.PathParamInt64("group_id")
ctxUser, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.APIErrorNotFound()
return
}
ctx.APIErrorInternal(err)
return
}
// check not a repo
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName, groupID)
if err != nil {
ctx.APIErrorInternal(err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName, groupID)))
if err != nil {
ctx.APIErrorInternal(err)
return
}
if has || !exist {
ctx.APIErrorNotFound()
return
}
if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
Name: repoName,
IsPrivate: true,
}); err != nil {
ctx.APIErrorInternal(err)
return
}
ctx.Status(http.StatusNoContent)
}
// AdoptRepository will adopt an unadopted repository
func AdoptRepository(ctx *context.APIContext) {
// swagger:operation POST /admin/unadopted/{owner}/{repo} admin adminAdoptRepository
@ -80,8 +121,40 @@ func AdoptRepository(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"
commonAdoptRepository(ctx)
}
func AdoptGroupRepository(ctx *context.APIContext) {
// swagger:operation POST /admin/unadopted/{owner}/{group_id}/{repo} admin adminAdoptRepository
// ---
// summary: Adopt unadopted files as a repository
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
// "403":
// "$ref": "#/responses/forbidden"
commonAdoptRepository(ctx)
}
func commonDeleteUnadoptedRepo(ctx *context.APIContext) {
ownerName := ctx.PathParam("username")
repoName := ctx.PathParam("reponame")
groupID := ctx.PathParamInt64("group_id")
ctxUser, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
@ -94,12 +167,12 @@ func AdoptRepository(ctx *context.APIContext) {
}
// check not a repo
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName)
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName, groupID)
if err != nil {
ctx.APIErrorInternal(err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName)))
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName, groupID)))
if err != nil {
ctx.APIErrorInternal(err)
return
@ -108,10 +181,8 @@ func AdoptRepository(ctx *context.APIContext) {
ctx.APIErrorNotFound()
return
}
if _, err := repo_service.AdoptRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
Name: repoName,
IsPrivate: true,
}); err != nil {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, repoName, groupID); err != nil {
ctx.APIErrorInternal(err)
return
}
@ -142,39 +213,30 @@ func DeleteUnadoptedRepository(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
ownerName := ctx.PathParam("username")
repoName := ctx.PathParam("reponame")
ctxUser, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.APIErrorNotFound()
return
}
ctx.APIErrorInternal(err)
return
}
// check not a repo
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName)
if err != nil {
ctx.APIErrorInternal(err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName)))
if err != nil {
ctx.APIErrorInternal(err)
return
}
if has || !exist {
ctx.APIErrorNotFound()
return
}
if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, repoName); err != nil {
ctx.APIErrorInternal(err)
return
}
ctx.Status(http.StatusNoContent)
commonDeleteUnadoptedRepo(ctx)
}
func DeleteUnadoptedRepositoryInGroup(ctx *context.APIContext) {
// swagger:operation DELETE /admin/unadopted/{owner}/{group_id}/{repo} admin adminDeleteUnadoptedRepository
// ---
// summary: Delete unadopted files
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
commonDeleteUnadoptedRepo(ctx)
}

View File

@ -66,6 +66,7 @@ import (
"errors"
"fmt"
"net/http"
"strconv"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
@ -140,7 +141,16 @@ func repoAssignment() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
userName := ctx.PathParam("username")
repoName := ctx.PathParam("reponame")
var gid int64
group := ctx.PathParam("group_id")
if group != "" {
gid, _ = strconv.ParseInt(group, 10, 64)
if gid == 0 {
ctx.Redirect(strings.Replace(ctx.Req.URL.RequestURI(), "/0/", "/", 1))
return
}
group += "/"
}
var (
owner *user_model.User
err error
@ -186,6 +196,10 @@ func repoAssignment() func(ctx *context.APIContext) {
}
return
}
if repo.GroupID != gid {
ctx.APIErrorNotFound()
return
}
repo.Owner = owner
ctx.Repo.Repository = repo
@ -1771,8 +1785,13 @@ func Routes() *web.Router {
})
m.Group("/unadopted", func() {
m.Get("", admin.ListUnadoptedRepositories)
m.Post("/{username}/{reponame}", admin.AdoptRepository)
m.Delete("/{username}/{reponame}", admin.DeleteUnadoptedRepository)
m.Group("/{username}", func() {
m.Post("/{reponame}", admin.AdoptRepository)
m.Delete("/{reponame}", admin.DeleteUnadoptedRepository)
m.Post("/{group_id}/{reponame}", admin.AdoptGroupRepository)
m.Delete("/{group_id}/{reponame}", admin.DeleteUnadoptedRepositoryInGroup)
})
})
m.Group("/hooks", func() {
m.Combo("").Get(admin.ListHooks).

View File

@ -6,6 +6,7 @@ package admin
import (
"net/http"
"net/url"
"strconv"
"strings"
"code.gitea.io/gitea/models/db"
@ -127,14 +128,18 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
repoName := dirSplit[1]
var groupID int64
if len(dirSplit) >= 3 {
groupID, _ = strconv.ParseInt(dirSplit[2], 10, 64)
}
// check not a repo
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName)
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, repoName, groupID)
if err != nil {
ctx.ServerError("IsRepositoryExist", err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName)))
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, repoName, groupID)))
if err != nil {
ctx.ServerError("IsDir", err)
return
@ -151,7 +156,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
} else if action == "delete" {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, dirSplit[1]); err != nil {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctx.Doer, ctxUser, dirSplit[1], groupID); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}

View File

@ -9,7 +9,7 @@ import (
)
func addOwnerRepoGitHTTPRouters(m *web.Router, middlewares ...any) {
m.Group("/{username}/{reponame}", func() {
m.Group("/{username}/{group_id}?/{reponame}", func() {
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
m.Methods("POST,OPTIONS", "/git-upload-archive", repo.ServiceUploadArchive)

View File

@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"path"
"strconv"
"strings"
repo_model "code.gitea.io/gitea/models/repo"
@ -22,14 +23,17 @@ func goGet(ctx *context.Context) {
return
}
parts := strings.SplitN(ctx.Req.URL.EscapedPath(), "/", 4)
parts := strings.SplitN(ctx.Req.URL.EscapedPath(), "/", 5)
if len(parts) < 3 {
return
}
var group string
ownerName := parts[1]
repoName := parts[2]
if len(parts) > 3 {
group = parts[3]
}
// Quick responses appropriate go-get meta with status 200
// regardless of if user have access to the repository,
@ -56,7 +60,11 @@ func goGet(ctx *context.Context) {
if err == nil && len(repo.DefaultBranch) > 0 {
branchName = repo.DefaultBranch
}
prefix := setting.AppURL + path.Join(url.PathEscape(ownerName), url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName))
prefix := setting.AppURL + url.PathEscape(ownerName)
if group != "" {
prefix = path.Join(prefix, group)
}
prefix = path.Join(prefix, url.PathEscape(repoName), "src", "branch", util.PathEscapeSegments(branchName))
appURL, _ := url.Parse(setting.AppURL)
@ -68,10 +76,11 @@ func goGet(ctx *context.Context) {
goGetImport := context.ComposeGoGetImport(ctx, ownerName, trimmedRepoName)
var cloneURL string
gid, _ := strconv.ParseInt(group, 10, 64)
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, ownerName, repoName)
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, ownerName, repoName, gid)
} else {
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, ownerName, repoName)
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, ownerName, repoName, gid)
}
goImportContent := fmt.Sprintf("%s git %s", goGetImport, cloneURL /*CloneLink*/)
goSourceContent := fmt.Sprintf("%s _ %s %s", goGetImport, prefix+"{/dir}" /*GoDocDirectory*/, prefix+"{/dir}/{file}#L{line}" /*GoDocFile*/)

View File

@ -4,6 +4,9 @@
package setting
import (
"strconv"
"strings"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/setting"
@ -21,18 +24,24 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
ctx.Data["allowDelete"] = allowDelete
dir := ctx.FormString("id")
var gid int64
if len(strings.Split(dir, "/")) > 1 {
split := strings.Split(dir, "/")
dir = split[0]
gid, _ = strconv.ParseInt(split[1], 10, 64)
}
action := ctx.FormString("action")
ctxUser := ctx.Doer
// check not a repo
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, dir)
has, err := repo_model.IsRepositoryModelExist(ctx, ctxUser, dir, 0)
if err != nil {
ctx.ServerError("IsRepositoryExist", err)
return
}
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, dir)))
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(repo_model.RelativePath(ctxUser.Name, dir, gid)))
if err != nil {
ctx.ServerError("IsDir", err)
return
@ -49,7 +58,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) {
}
ctx.Flash.Success(ctx.Tr("repo.adopt_preexisting_success", dir))
} else if action == "delete" && allowDelete {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctxUser, ctxUser, dir); err != nil {
if err := repo_service.DeleteUnadoptedRepository(ctx, ctxUser, ctxUser, dir, gid); err != nil {
ctx.ServerError("repository.AdoptRepository", err)
return
}

View File

@ -8,6 +8,7 @@ import (
"strings"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/git"

View File

@ -12,6 +12,7 @@ import (
"net/http"
"net/url"
"path"
"strconv"
"strings"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@ -369,6 +370,7 @@ func ComposeGoGetImport(ctx context.Context, owner, repo string) string {
func EarlyResponseForGoGetMeta(ctx *Context) {
username := ctx.PathParam("username")
reponame := strings.TrimSuffix(ctx.PathParam("reponame"), ".git")
groupID := ctx.PathParamInt64("group_id")
if username == "" || reponame == "" {
ctx.PlainText(http.StatusBadRequest, "invalid repository path")
return
@ -376,9 +378,9 @@ func EarlyResponseForGoGetMeta(ctx *Context) {
var cloneURL string
if setting.Repository.GoGetCloneURLProtocol == "ssh" {
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, username, reponame)
cloneURL = repo_model.ComposeSSHCloneURL(ctx.Doer, username, reponame, groupID)
} else {
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, username, reponame)
cloneURL = repo_model.ComposeHTTPSCloneURL(ctx, username, reponame, groupID)
}
goImportContent := fmt.Sprintf("%s git %s", ComposeGoGetImport(ctx, username, reponame), cloneURL)
htmlMeta := fmt.Sprintf(`<meta name="go-import" content="%s">`, html.EscapeString(goImportContent))
@ -468,6 +470,20 @@ func RepoAssignment(ctx *Context) {
var err error
userName := ctx.PathParam("username")
repoName := ctx.PathParam("reponame")
group := ctx.PathParam("group_id")
var gid int64
if group != "" {
gid, _ = strconv.ParseInt(group, 10, 64)
if gid == 0 {
q := ctx.Req.URL.RawQuery
if q != "" {
q = "?" + q
}
ctx.Redirect(strings.Replace(ctx.Link, "/0/", "/", 1) + q)
return
}
group += "/"
}
repoName = strings.TrimSuffix(repoName, ".git")
if setting.Other.EnableFeed {
ctx.Data["EnableFeed"] = true
@ -514,7 +530,7 @@ func RepoAssignment(ctx *Context) {
redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
redirectPath := strings.Replace(
ctx.Req.URL.EscapedPath(),
url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
url.PathEscape(userName)+"/"+group+url.PathEscape(originalRepoName),
url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
1,
)
@ -546,6 +562,9 @@ func RepoAssignment(ctx *Context) {
}
return
}
if repo.GroupID != gid {
ctx.NotFound(nil)
}
repo.Owner = ctx.Repo.Owner
repoAssignment(ctx, repo)

View File

@ -208,12 +208,12 @@ func adoptRepository(ctx context.Context, repo *repo_model.Repository, defaultBr
}
// DeleteUnadoptedRepository deletes unadopted repository files from the filesystem
func DeleteUnadoptedRepository(ctx context.Context, doer, u *user_model.User, repoName string) error {
func DeleteUnadoptedRepository(ctx context.Context, doer, u *user_model.User, repoName string, groupID int64) error {
if err := repo_model.IsUsableRepoName(repoName); err != nil {
return err
}
relativePath := repo_model.RelativePath(u.Name, repoName)
relativePath := repo_model.RelativePath(u.Name, repoName, groupID)
exist, err := gitrepo.IsRepositoryExist(ctx, repo_model.StorageRepo(relativePath))
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", relativePath, err)
@ -226,7 +226,7 @@ func DeleteUnadoptedRepository(ctx context.Context, doer, u *user_model.User, re
}
}
if exist, err := repo_model.IsRepositoryModelExist(ctx, u, repoName); err != nil {
if exist, err := repo_model.IsRepositoryModelExist(ctx, u, repoName, groupID); err != nil {
return err
} else if exist {
return repo_model.ErrRepoAlreadyExist{

View File

@ -366,7 +366,7 @@ func createRepositoryInDB(ctx context.Context, doer, u *user_model.User, repo *r
return err
}
has, err := repo_model.IsRepositoryModelExist(ctx, u, repo.Name)
has, err := repo_model.IsRepositoryModelExist(ctx, u, repo.Name, repo.GroupID)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {

View File

@ -91,12 +91,12 @@ func AcceptTransferOwnership(ctx context.Context, repo *repo_model.Repository, d
}
// isRepositoryModelOrDirExist returns true if the repository with given name under user has already existed.
func isRepositoryModelOrDirExist(ctx context.Context, u *user_model.User, repoName string) (bool, error) {
has, err := repo_model.IsRepositoryModelExist(ctx, u, repoName)
func isRepositoryModelOrDirExist(ctx context.Context, u *user_model.User, repoName string, groupID int64) (bool, error) {
has, err := repo_model.IsRepositoryModelExist(ctx, u, repoName, groupID)
if err != nil {
return false, err
}
repo := repo_model.StorageRepo(repo_model.RelativePath(u.Name, repoName))
repo := repo_model.StorageRepo(repo_model.RelativePath(u.Name, repoName, groupID))
isExist, err := gitrepo.IsRepositoryExist(ctx, repo)
return has || isExist, err
}
@ -118,7 +118,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
}
if repoRenamed {
oldRelativePath, newRelativePath := repo_model.RelativePath(newOwnerName, repo.Name), repo_model.RelativePath(oldOwnerName, repo.Name)
oldRelativePath, newRelativePath := repo_model.RelativePath(newOwnerName, repo.Name, 0), repo_model.RelativePath(oldOwnerName, repo.Name, repo.GroupID)
if err := gitrepo.RenameRepository(ctx, repo_model.StorageRepo(oldRelativePath), repo_model.StorageRepo(newRelativePath)); err != nil {
log.Critical("Unable to move repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name,
oldRelativePath, newRelativePath, err)
@ -126,7 +126,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
}
if wikiRenamed {
oldRelativePath, newRelativePath := repo_model.RelativeWikiPath(newOwnerName, repo.Name), repo_model.RelativeWikiPath(oldOwnerName, repo.Name)
oldRelativePath, newRelativePath := repo_model.RelativeWikiPath(newOwnerName, repo.Name, 0), repo_model.RelativeWikiPath(oldOwnerName, repo.Name, repo.GroupID)
if err := gitrepo.RenameRepository(ctx, repo_model.StorageRepo(oldRelativePath), repo_model.StorageRepo(newRelativePath)); err != nil {
log.Critical("Unable to move wiki for repository %s/%s directory from %s back to correct place %s: %v", oldOwnerName, repo.Name,
oldRelativePath, newRelativePath, err)
@ -154,7 +154,7 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
newOwnerName = newOwner.Name // ensure capitalisation matches
// Check if new owner has repository with same name.
if has, err := isRepositoryModelOrDirExist(ctx, newOwner, repo.Name); err != nil {
if has, err := isRepositoryModelOrDirExist(ctx, newOwner, repo.Name, 0); err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return repo_model.ErrRepoAlreadyExist{
@ -304,19 +304,19 @@ func transferOwnership(ctx context.Context, doer *user_model.User, newOwnerName
}
// Rename remote repository to new path and delete local copy.
oldRelativePath, newRelativePath := repo_model.RelativePath(oldOwner.Name, repo.Name), repo_model.RelativePath(newOwner.Name, repo.Name)
oldRelativePath, newRelativePath := repo_model.RelativePath(oldOwner.Name, repo.Name, repo.GroupID), repo_model.RelativePath(newOwner.Name, repo.Name, repo.GroupID)
if err := gitrepo.RenameRepository(ctx, repo_model.StorageRepo(oldRelativePath), repo_model.StorageRepo(newRelativePath)); err != nil {
return fmt.Errorf("rename repository directory: %w", err)
}
repoRenamed = true
// Rename remote wiki repository to new path and delete local copy.
wikiStorageRepo := repo_model.StorageRepo(repo_model.RelativeWikiPath(oldOwner.Name, repo.Name))
wikiStorageRepo := repo_model.StorageRepo(repo_model.RelativeWikiPath(oldOwner.Name, repo.Name, repo.GroupID))
if isExist, err := gitrepo.IsRepositoryExist(ctx, wikiStorageRepo); err != nil {
log.Error("Unable to check if %s exists. Error: %v", wikiStorageRepo.RelativePath(), err)
return err
} else if isExist {
if err := gitrepo.RenameRepository(ctx, wikiStorageRepo, repo_model.StorageRepo(repo_model.RelativeWikiPath(newOwner.Name, repo.Name))); err != nil {
if err := gitrepo.RenameRepository(ctx, wikiStorageRepo, repo_model.StorageRepo(repo_model.RelativeWikiPath(newOwner.Name, repo.Name, repo.GroupID))); err != nil {
return fmt.Errorf("rename repository wiki: %w", err)
}
wikiRenamed = true
@ -365,7 +365,7 @@ func changeRepositoryName(ctx context.Context, repo *repo_model.Repository, newR
return err
}
has, err := isRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName)
has, err := isRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName, repo.GroupID)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
@ -376,13 +376,13 @@ func changeRepositoryName(ctx context.Context, repo *repo_model.Repository, newR
}
if err = gitrepo.RenameRepository(ctx, repo,
repo_model.StorageRepo(repo_model.RelativePath(repo.OwnerName, newRepoName))); err != nil {
repo_model.StorageRepo(repo_model.RelativePath(repo.OwnerName, newRepoName, 0))); err != nil {
return fmt.Errorf("rename repository directory: %w", err)
}
if HasWiki(ctx, repo) {
if err = gitrepo.RenameRepository(ctx, repo.WikiStorageRepo(), repo_model.StorageRepo(
repo_model.RelativeWikiPath(repo.OwnerName, newRepoName))); err != nil {
repo_model.RelativeWikiPath(repo.OwnerName, newRepoName, repo.GroupID))); err != nil {
return fmt.Errorf("rename repository wiki: %w", err)
}
}