mirror of
https://github.com/go-gitea/gitea.git
synced 2025-02-02 15:09:33 -05:00
Merge branch 'main' into agit/update
This commit is contained in:
commit
59f37ce829
@ -22,6 +22,7 @@
|
|||||||
content_type: 1 # json
|
content_type: 1 # json
|
||||||
events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}'
|
events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}'
|
||||||
is_active: true
|
is_active: true
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 4
|
id: 4
|
||||||
repo_id: 2
|
repo_id: 2
|
||||||
@ -29,3 +30,23 @@
|
|||||||
content_type: 1 # json
|
content_type: 1 # json
|
||||||
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
|
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
|
||||||
is_active: true
|
is_active: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 5
|
||||||
|
repo_id: 0
|
||||||
|
owner_id: 0
|
||||||
|
url: www.example.com/url5
|
||||||
|
content_type: 1 # json
|
||||||
|
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
|
||||||
|
is_active: true
|
||||||
|
is_system_webhook: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 6
|
||||||
|
repo_id: 0
|
||||||
|
owner_id: 0
|
||||||
|
url: www.example.com/url6
|
||||||
|
content_type: 1 # json
|
||||||
|
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
|
||||||
|
is_active: true
|
||||||
|
is_system_webhook: false
|
||||||
|
@ -175,10 +175,14 @@ func (p *Permission) LogString() string {
|
|||||||
return fmt.Sprintf(format, args...)
|
return fmt.Sprintf(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) {
|
func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
|
||||||
if user == nil || user.ID <= 0 {
|
if user == nil || user.ID <= 0 {
|
||||||
|
// for anonymous access, it could be:
|
||||||
|
// AccessMode is None or Read, units has repo units, unitModes is nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply everyone access permissions
|
||||||
for _, u := range perm.units {
|
for _, u := range perm.units {
|
||||||
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
|
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
|
||||||
if perm.everyoneAccessMode == nil {
|
if perm.everyoneAccessMode == nil {
|
||||||
@ -187,17 +191,40 @@ func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) {
|
|||||||
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
|
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if perm.unitsMode == nil {
|
||||||
|
// if unitsMode is not set, then it means that the default p.AccessMode applies to all units
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove no permission units
|
||||||
|
origPermUnits := perm.units
|
||||||
|
perm.units = make([]*repo_model.RepoUnit, 0, len(perm.units))
|
||||||
|
for _, u := range origPermUnits {
|
||||||
|
shouldKeep := false
|
||||||
|
for t := range perm.unitsMode {
|
||||||
|
if shouldKeep = u.Type == t; shouldKeep {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for t := range perm.everyoneAccessMode {
|
||||||
|
if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shouldKeep {
|
||||||
|
perm.units = append(perm.units, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserRepoPermission returns the user permissions to the repository
|
// GetUserRepoPermission returns the user permissions to the repository
|
||||||
func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) {
|
func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
applyEveryoneRepoPermission(user, &perm)
|
finalProcessRepoUnitPermission(user, &perm)
|
||||||
}
|
|
||||||
if log.IsTrace() {
|
|
||||||
log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm)
|
|
||||||
}
|
}
|
||||||
|
log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = repo.LoadUnits(ctx); err != nil {
|
if err = repo.LoadUnits(ctx); err != nil {
|
||||||
@ -294,16 +321,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove no permission units
|
|
||||||
perm.units = make([]*repo_model.RepoUnit, 0, len(repo.Units))
|
|
||||||
for t := range perm.unitsMode {
|
|
||||||
for _, u := range repo.Units {
|
|
||||||
if u.Type == t {
|
|
||||||
perm.units = append(perm.units, u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return perm, err
|
return perm, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
|
|||||||
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
applyEveryoneRepoPermission(nil, &perm)
|
finalProcessRepoUnitPermission(nil, &perm)
|
||||||
assert.False(t, perm.CanRead(unit.TypeWiki))
|
assert.False(t, perm.CanRead(unit.TypeWiki))
|
||||||
|
|
||||||
perm = Permission{
|
perm = Permission{
|
||||||
@ -59,7 +59,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
|
|||||||
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm)
|
finalProcessRepoUnitPermission(&user_model.User{ID: 0}, &perm)
|
||||||
assert.False(t, perm.CanRead(unit.TypeWiki))
|
assert.False(t, perm.CanRead(unit.TypeWiki))
|
||||||
|
|
||||||
perm = Permission{
|
perm = Permission{
|
||||||
@ -68,7 +68,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
|
|||||||
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
|
finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
|
||||||
assert.True(t, perm.CanRead(unit.TypeWiki))
|
assert.True(t, perm.CanRead(unit.TypeWiki))
|
||||||
|
|
||||||
perm = Permission{
|
perm = Permission{
|
||||||
@ -77,20 +77,22 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
|
|||||||
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
|
finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
|
||||||
// it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units
|
// it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units
|
||||||
assert.True(t, perm.CanWrite(unit.TypeWiki))
|
assert.True(t, perm.CanWrite(unit.TypeWiki))
|
||||||
|
|
||||||
perm = Permission{
|
perm = Permission{
|
||||||
units: []*repo_model.RepoUnit{
|
units: []*repo_model.RepoUnit{
|
||||||
|
{Type: unit.TypeCode}, // will be removed
|
||||||
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
|
||||||
},
|
},
|
||||||
unitsMode: map[unit.Type]perm_model.AccessMode{
|
unitsMode: map[unit.Type]perm_model.AccessMode{
|
||||||
unit.TypeWiki: perm_model.AccessModeWrite,
|
unit.TypeWiki: perm_model.AccessModeWrite,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
|
finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
|
||||||
assert.True(t, perm.CanWrite(unit.TypeWiki))
|
assert.True(t, perm.CanWrite(unit.TypeWiki))
|
||||||
|
assert.Len(t, perm.units, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnitAccessMode(t *testing.T) {
|
func TestUnitAccessMode(t *testing.T) {
|
||||||
|
@ -54,6 +54,7 @@ func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string,
|
|||||||
for _, o := range oldLicenses {
|
for _, o := range oldLicenses {
|
||||||
// Update already existing license
|
// Update already existing license
|
||||||
if o.License == license {
|
if o.License == license {
|
||||||
|
o.CommitID = commitID
|
||||||
if _, err := db.GetEngine(ctx).ID(o.ID).Cols("`commit_id`").Update(o); err != nil {
|
if _, err := db.GetEngine(ctx).ID(o.ID).Cols("`commit_id`").Update(o); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -11,35 +11,13 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Copy copies file from source to target path.
|
// SyncFile synchronizes the two files. This is skipped if both files
|
||||||
func Copy(src, dest string) error {
|
|
||||||
// Gather file information to set back later.
|
|
||||||
si, err := os.Lstat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle symbolic link.
|
|
||||||
if si.Mode()&os.ModeSymlink != 0 {
|
|
||||||
target, err := os.Readlink(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
|
|
||||||
// which will lead "no such file or directory" error.
|
|
||||||
return os.Symlink(target, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.CopyFile(src, dest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync synchronizes the two files. This is skipped if both files
|
|
||||||
// exist and the size, modtime, and mode match.
|
// exist and the size, modtime, and mode match.
|
||||||
func Sync(srcPath, destPath string) error {
|
func SyncFile(srcPath, destPath string) error {
|
||||||
dest, err := os.Stat(destPath)
|
dest, err := os.Stat(destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return Copy(srcPath, destPath)
|
return util.CopyFile(srcPath, destPath)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -55,7 +33,7 @@ func Sync(srcPath, destPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return Copy(srcPath, destPath)
|
return util.CopyFile(srcPath, destPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncDirs synchronizes files recursively from source to target directory.
|
// SyncDirs synchronizes files recursively from source to target directory.
|
||||||
@ -66,6 +44,10 @@ func SyncDirs(srcPath, destPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the keep file is used to keep the directory in a git repository, it doesn't need to be synced
|
||||||
|
// and go-git doesn't work with the ".keep" file (it would report errors like "ref is empty")
|
||||||
|
const keepFile = ".keep"
|
||||||
|
|
||||||
// find and delete all untracked files
|
// find and delete all untracked files
|
||||||
destFiles, err := util.ListDirRecursively(destPath, &util.ListDirOptions{IncludeDir: true})
|
destFiles, err := util.ListDirRecursively(destPath, &util.ListDirOptions{IncludeDir: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -73,16 +55,20 @@ func SyncDirs(srcPath, destPath string) error {
|
|||||||
}
|
}
|
||||||
for _, destFile := range destFiles {
|
for _, destFile := range destFiles {
|
||||||
destFilePath := filepath.Join(destPath, destFile)
|
destFilePath := filepath.Join(destPath, destFile)
|
||||||
|
shouldRemove := filepath.Base(destFilePath) == keepFile
|
||||||
if _, err = os.Stat(filepath.Join(srcPath, destFile)); err != nil {
|
if _, err = os.Stat(filepath.Join(srcPath, destFile)); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// if src file does not exist, remove dest file
|
shouldRemove = true
|
||||||
if err = os.RemoveAll(destFilePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if src file does not exist, remove dest file
|
||||||
|
if shouldRemove {
|
||||||
|
if err = os.RemoveAll(destFilePath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync src files to dest
|
// sync src files to dest
|
||||||
@ -95,8 +81,8 @@ func SyncDirs(srcPath, destPath string) error {
|
|||||||
// util.ListDirRecursively appends a slash to the directory name
|
// util.ListDirRecursively appends a slash to the directory name
|
||||||
if strings.HasSuffix(srcFile, "/") {
|
if strings.HasSuffix(srcFile, "/") {
|
||||||
err = os.MkdirAll(destFilePath, os.ModePerm)
|
err = os.MkdirAll(destFilePath, os.ModePerm)
|
||||||
} else {
|
} else if filepath.Base(destFilePath) != keepFile {
|
||||||
err = Sync(filepath.Join(srcPath, srcFile), destFilePath)
|
err = SyncFile(filepath.Join(srcPath, srcFile), destFilePath)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -11,6 +11,19 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetSystemOrDefaultWebhooks returns webhooks by given argument or all if argument is missing.
|
||||||
|
func GetSystemOrDefaultWebhooks(ctx context.Context, isSystemWebhook optional.Option[bool]) ([]*Webhook, error) {
|
||||||
|
webhooks := make([]*Webhook, 0, 5)
|
||||||
|
if !isSystemWebhook.Has() {
|
||||||
|
return webhooks, db.GetEngine(ctx).Where("repo_id=? AND owner_id=?", 0, 0).
|
||||||
|
Find(&webhooks)
|
||||||
|
}
|
||||||
|
|
||||||
|
return webhooks, db.GetEngine(ctx).
|
||||||
|
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, isSystemWebhook.Value()).
|
||||||
|
Find(&webhooks)
|
||||||
|
}
|
||||||
|
|
||||||
// GetDefaultWebhooks returns all admin-default webhooks.
|
// GetDefaultWebhooks returns all admin-default webhooks.
|
||||||
func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
|
func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
|
||||||
webhooks := make([]*Webhook, 0, 5)
|
webhooks := make([]*Webhook, 0, 5)
|
||||||
|
37
models/webhook/webhook_system_test.go
Normal file
37
models/webhook/webhook_system_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package webhook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
"code.gitea.io/gitea/modules/optional"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetSystemOrDefaultWebhooks(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
hooks, err := GetSystemOrDefaultWebhooks(db.DefaultContext, optional.None[bool]())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, hooks, 2) {
|
||||||
|
assert.Equal(t, int64(5), hooks[0].ID)
|
||||||
|
assert.Equal(t, int64(6), hooks[1].ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
hooks, err = GetSystemOrDefaultWebhooks(db.DefaultContext, optional.Some(true))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, hooks, 1) {
|
||||||
|
assert.Equal(t, int64(5), hooks[0].ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
hooks, err = GetSystemOrDefaultWebhooks(db.DefaultContext, optional.Some(false))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, hooks, 1) {
|
||||||
|
assert.Equal(t, int64(6), hooks[0].ID)
|
||||||
|
}
|
||||||
|
}
|
@ -1115,9 +1115,6 @@ blame.ignore_revs=Ignorování revizí v <a href="%s">.git-blame-ignorerevs</a>.
|
|||||||
blame.ignore_revs.failed=Nepodařilo se ignorovat revize v <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Nepodařilo se ignorovat revize v <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
user_search_tooltip=Zobrazí maximálně 30 uživatelů
|
user_search_tooltip=Zobrazí maximálně 30 uživatelů
|
||||||
|
|
||||||
tree_path_not_found_commit=Cesta %[1]s v commitu %[2]s neexistuje
|
|
||||||
tree_path_not_found_branch=Cesta %[1]s ve větvi %[2]s neexistuje
|
|
||||||
tree_path_not_found_tag=Cesta %[1]s ve značce %[2]s neexistuje
|
|
||||||
|
|
||||||
transfer.accept=Přijmout převod
|
transfer.accept=Přijmout převod
|
||||||
transfer.accept_desc=Převést do „%s“
|
transfer.accept_desc=Převést do „%s“
|
||||||
|
@ -1111,9 +1111,6 @@ blame.ignore_revs=Revisionen in <a href="%s">.git-blame-ignore-revs</a> werden i
|
|||||||
blame.ignore_revs.failed=Fehler beim Ignorieren der Revisionen in <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Fehler beim Ignorieren der Revisionen in <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
user_search_tooltip=Zeigt maximal 30 Benutzer
|
user_search_tooltip=Zeigt maximal 30 Benutzer
|
||||||
|
|
||||||
tree_path_not_found_commit=Pfad %[1]s existiert nicht in Commit%[2]s
|
|
||||||
tree_path_not_found_branch=Pfad %[1]s existiert nicht in Branch %[2]s
|
|
||||||
tree_path_not_found_tag=Pfad %[1]s existiert nicht in Tag %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Übertragung Akzeptieren
|
transfer.accept=Übertragung Akzeptieren
|
||||||
transfer.accept_desc=`Übertragung nach "%s"`
|
transfer.accept_desc=`Übertragung nach "%s"`
|
||||||
|
@ -992,9 +992,6 @@ blame_prior=Προβολή ευθύνης πριν από αυτή την αλλ
|
|||||||
blame.ignore_revs=Αγνόηση των αναθεωρήσεων στο <a href="%s">.git-blame-ignore-revs</a>. Πατήστε <a href="%s">εδώ</a> για να το παρακάμψετε και να δείτε την κανονική προβολή ευθυνών.
|
blame.ignore_revs=Αγνόηση των αναθεωρήσεων στο <a href="%s">.git-blame-ignore-revs</a>. Πατήστε <a href="%s">εδώ</a> για να το παρακάμψετε και να δείτε την κανονική προβολή ευθυνών.
|
||||||
blame.ignore_revs.failed=Αποτυχία αγνόησης των αναθεωρήσεων στο <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Αποτυχία αγνόησης των αναθεωρήσεων στο <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
|
|
||||||
tree_path_not_found_commit=Η διαδρομή %[1]s δεν υπάρχει στην υποβολή %[2]s
|
|
||||||
tree_path_not_found_branch=Η διαδρομή %[1]s δεν υπάρχει στον κλάδο %[2]s
|
|
||||||
tree_path_not_found_tag=Η διαδρομή %[1]s δεν υπάρχει στην ετικέτα %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Αποδοχή Μεταφοράς
|
transfer.accept=Αποδοχή Μεταφοράς
|
||||||
transfer.reject=Απόρριψη Μεταφοράς
|
transfer.reject=Απόρριψη Μεταφοράς
|
||||||
|
@ -2158,7 +2158,7 @@ settings.advanced_settings = Advanced Settings
|
|||||||
settings.wiki_desc = Enable Repository Wiki
|
settings.wiki_desc = Enable Repository Wiki
|
||||||
settings.use_internal_wiki = Use Built-In Wiki
|
settings.use_internal_wiki = Use Built-In Wiki
|
||||||
settings.default_wiki_branch_name = Default Wiki Branch Name
|
settings.default_wiki_branch_name = Default Wiki Branch Name
|
||||||
settings.default_wiki_everyone_access = Default Access Permission for signed-in users:
|
settings.default_permission_everyone_access = Default access permission for all signed-in users:
|
||||||
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch.
|
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch.
|
||||||
settings.use_external_wiki = Use External Wiki
|
settings.use_external_wiki = Use External Wiki
|
||||||
settings.external_wiki_url = External Wiki URL
|
settings.external_wiki_url = External Wiki URL
|
||||||
|
@ -982,9 +982,6 @@ blame_prior=Ver la culpa antes de este cambio
|
|||||||
blame.ignore_revs=Ignorando revisiones en <a href="%s">.git-blame-ignore-revs</a>. Haga clic <a href="%s">aquí para saltar</a> y para a la vista normal.
|
blame.ignore_revs=Ignorando revisiones en <a href="%s">.git-blame-ignore-revs</a>. Haga clic <a href="%s">aquí para saltar</a> y para a la vista normal.
|
||||||
blame.ignore_revs.failed=No se pudieron ignorar las revisiones en <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=No se pudieron ignorar las revisiones en <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
|
|
||||||
tree_path_not_found_commit=La ruta %[1]s no existe en el commit %[2]s
|
|
||||||
tree_path_not_found_branch=La ruta %[1]s no existe en la rama %[2]s
|
|
||||||
tree_path_not_found_tag=La ruta %[1]s no existe en la etiqueta %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Aceptar transferencia
|
transfer.accept=Aceptar transferencia
|
||||||
transfer.reject=Rechazar transferencia
|
transfer.reject=Rechazar transferencia
|
||||||
|
@ -1115,9 +1115,6 @@ blame.ignore_revs=Les révisions dans <a href="%s">.git-blame-ignore-revs</a> so
|
|||||||
blame.ignore_revs.failed=Impossible d'ignorer les révisions dans <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Impossible d'ignorer les révisions dans <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
user_search_tooltip=Affiche un maximum de 30 utilisateurs
|
user_search_tooltip=Affiche un maximum de 30 utilisateurs
|
||||||
|
|
||||||
tree_path_not_found_commit=Le chemin %[1]s n’existe pas dans la révision %[2]s.
|
|
||||||
tree_path_not_found_branch=Le chemin %[1]s n’existe pas dans la branche %[2]s.
|
|
||||||
tree_path_not_found_tag=Le chemin %[1]s n’existe pas dans l’étiquette %[2]s.
|
|
||||||
|
|
||||||
transfer.accept=Accepter le transfert
|
transfer.accept=Accepter le transfert
|
||||||
transfer.accept_desc=Transférer à « %s »
|
transfer.accept_desc=Transférer à « %s »
|
||||||
|
@ -1115,9 +1115,6 @@ blame.ignore_revs=Ag déanamh neamhairde de leasuithe i <a href="%s">.git-blame-
|
|||||||
blame.ignore_revs.failed=Theip ar neamhaird a dhéanamh ar leasuithe i <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Theip ar neamhaird a dhéanamh ar leasuithe i <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
user_search_tooltip=Taispeáint uasmhéid de 30 úsáideoir
|
user_search_tooltip=Taispeáint uasmhéid de 30 úsáideoir
|
||||||
|
|
||||||
tree_path_not_found_commit=Níl cosán %[1]s ann i dtiomantas %[2]s
|
|
||||||
tree_path_not_found_branch=Níl cosán %[1]s ann i mbrainse %[2]s
|
|
||||||
tree_path_not_found_tag=Níl cosán %[1]s ann i gclib %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Glac le hAistriú
|
transfer.accept=Glac le hAistriú
|
||||||
transfer.accept_desc=Aistriú chuig “%s”
|
transfer.accept_desc=Aistriú chuig “%s”
|
||||||
|
@ -1109,9 +1109,6 @@ blame_prior=この変更より前のBlameを表示
|
|||||||
blame.ignore_revs=<a href="%s">.git-blame-ignore-revs</a> で指定されたリビジョンは除外しています。 これを迂回して通常のBlame表示を見るには <a href="%s">ここ</a>をクリック。
|
blame.ignore_revs=<a href="%s">.git-blame-ignore-revs</a> で指定されたリビジョンは除外しています。 これを迂回して通常のBlame表示を見るには <a href="%s">ここ</a>をクリック。
|
||||||
blame.ignore_revs.failed=<a href="%s">.git-blame-ignore-revs</a> によるリビジョンの無視は失敗しました。
|
blame.ignore_revs.failed=<a href="%s">.git-blame-ignore-revs</a> によるリビジョンの無視は失敗しました。
|
||||||
|
|
||||||
tree_path_not_found_commit=パス %[1]s はコミット %[2]s に存在しません
|
|
||||||
tree_path_not_found_branch=パス %[1]s はブランチ %[2]s に存在しません
|
|
||||||
tree_path_not_found_tag=パス %[1]s はタグ %[2]s に存在しません
|
|
||||||
|
|
||||||
transfer.accept=移転を承認
|
transfer.accept=移転を承認
|
||||||
transfer.accept_desc=`"%s" に移転`
|
transfer.accept_desc=`"%s" に移転`
|
||||||
|
@ -997,9 +997,6 @@ blame_prior=Aplūkot vainīgo par izmaiņām pirms šīs revīzijas
|
|||||||
blame.ignore_revs=Neņem vērā izmaiņas no <a href="%s">.git-blame-ignore-revs</a>. Nospiediet <a href="%s">šeit, lai to apietu</a> un redzētu visu izmaiņu skatu.
|
blame.ignore_revs=Neņem vērā izmaiņas no <a href="%s">.git-blame-ignore-revs</a>. Nospiediet <a href="%s">šeit, lai to apietu</a> un redzētu visu izmaiņu skatu.
|
||||||
blame.ignore_revs.failed=Neizdevās neņemt vērā izmaiņas no <a href="%s">.git-blam-ignore-revs</a>.
|
blame.ignore_revs.failed=Neizdevās neņemt vērā izmaiņas no <a href="%s">.git-blam-ignore-revs</a>.
|
||||||
|
|
||||||
tree_path_not_found_commit=Revīzijā %[2]s neeksistē ceļš %[1]s
|
|
||||||
tree_path_not_found_branch=Atzarā %[2]s nepastāv ceļš %[1]s
|
|
||||||
tree_path_not_found_tag=Tagā %[2]s nepastāv ceļš %[1]s
|
|
||||||
|
|
||||||
transfer.accept=Apstiprināt īpašnieka maiņu
|
transfer.accept=Apstiprināt īpašnieka maiņu
|
||||||
transfer.reject=Noraidīt īpašnieka maiņu
|
transfer.reject=Noraidīt īpašnieka maiņu
|
||||||
|
@ -1115,9 +1115,6 @@ blame.ignore_revs=Ignorando as revisões em <a href="%s">.git-blame-ignore-revs<
|
|||||||
blame.ignore_revs.failed=Falhou ao ignorar as revisões em <a href="%s">.git-blame-ignore-revs</a>.
|
blame.ignore_revs.failed=Falhou ao ignorar as revisões em <a href="%s">.git-blame-ignore-revs</a>.
|
||||||
user_search_tooltip=Mostra um máximo de 30 utilizadores
|
user_search_tooltip=Mostra um máximo de 30 utilizadores
|
||||||
|
|
||||||
tree_path_not_found_commit=A localização %[1]s não existe no cometimento %[2]s
|
|
||||||
tree_path_not_found_branch=A localização %[1]s não existe no ramo %[2]s
|
|
||||||
tree_path_not_found_tag=A localização %[1]s não existe na etiqueta %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Aceitar transferência
|
transfer.accept=Aceitar transferência
|
||||||
transfer.accept_desc=`Transferir para "%s"`
|
transfer.accept_desc=`Transferir para "%s"`
|
||||||
|
@ -978,8 +978,6 @@ delete_preexisting_content=Удалить файлы из %s
|
|||||||
delete_preexisting_success=Удалены непринятые файлы в %s
|
delete_preexisting_success=Удалены непринятые файлы в %s
|
||||||
blame_prior=Показать авторство предшествующих изменений
|
blame_prior=Показать авторство предшествующих изменений
|
||||||
|
|
||||||
tree_path_not_found_commit=Путь %[1]s не существует в коммите %[2]s
|
|
||||||
tree_path_not_found_branch=Путь %[1]s не существует в ветке %[2]s
|
|
||||||
|
|
||||||
transfer.accept=Принять трансфер
|
transfer.accept=Принять трансфер
|
||||||
transfer.reject=Отказаться от перемещения
|
transfer.reject=Отказаться от перемещения
|
||||||
|
@ -1083,9 +1083,6 @@ blame_prior=Bu değişiklikten önceki suçu görüntüle
|
|||||||
blame.ignore_revs=<a href="%s">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılıyor. Bunun yerine normal sorumlu görüntüsü için <a href="%s">buraya tıklayın</a>.
|
blame.ignore_revs=<a href="%s">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılıyor. Bunun yerine normal sorumlu görüntüsü için <a href="%s">buraya tıklayın</a>.
|
||||||
blame.ignore_revs.failed=<a href="%s">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılamadı.
|
blame.ignore_revs.failed=<a href="%s">.git-blame-ignore-revs</a> dosyasındaki sürümler yok sayılamadı.
|
||||||
|
|
||||||
tree_path_not_found_commit=%[1] yolu, %[2]s işlemesinde mevcut değil
|
|
||||||
tree_path_not_found_branch=%[1] yolu, %[2]s dalında mevcut değil
|
|
||||||
tree_path_not_found_tag=%[1] yolu, %[2]s etiketinde mevcut değil
|
|
||||||
|
|
||||||
transfer.accept=Aktarımı Kabul Et
|
transfer.accept=Aktarımı Kabul Et
|
||||||
transfer.reject=Aktarımı Reddet
|
transfer.reject=Aktarımı Reddet
|
||||||
|
@ -1111,9 +1111,6 @@ blame.ignore_revs=忽略 <a href="%s">.git-blame-ignore-revs</a> 的修订。点
|
|||||||
blame.ignore_revs.failed=忽略 <a href="%s">.git-blame-ignore-revs</a> 版本失败。
|
blame.ignore_revs.failed=忽略 <a href="%s">.git-blame-ignore-revs</a> 版本失败。
|
||||||
user_search_tooltip=最多显示30名用户
|
user_search_tooltip=最多显示30名用户
|
||||||
|
|
||||||
tree_path_not_found_commit=路径%[1]s 在提交 %[2]s 中不存在
|
|
||||||
tree_path_not_found_branch=路径 %[1]s 不存在于分支 %[2]s 中。
|
|
||||||
tree_path_not_found_tag=路径 %[1]s 不存在于标签 %[2]s 中
|
|
||||||
|
|
||||||
transfer.accept=接受转移
|
transfer.accept=接受转移
|
||||||
transfer.accept_desc=`转移到 "%s"`
|
transfer.accept_desc=`转移到 "%s"`
|
||||||
|
@ -1108,9 +1108,6 @@ blame.ignore_revs=忽略 <a href="%s">.git-blame-ignore-revs</a> 中的修訂。
|
|||||||
blame.ignore_revs.failed=忽略 <a href="%s">.git-blame-ignore-revs</a> 中的修訂失敗。
|
blame.ignore_revs.failed=忽略 <a href="%s">.git-blame-ignore-revs</a> 中的修訂失敗。
|
||||||
user_search_tooltip=顯示最多 30 個使用者
|
user_search_tooltip=顯示最多 30 個使用者
|
||||||
|
|
||||||
tree_path_not_found_commit=路徑 %[1]s 在提交 %[2]s 中不存在
|
|
||||||
tree_path_not_found_branch=路徑 %[1]s 在分支 %[2]s 中不存在
|
|
||||||
tree_path_not_found_tag=路徑 %[1]s 在標籤 %[2]s 中不存在
|
|
||||||
|
|
||||||
transfer.accept=同意轉移
|
transfer.accept=同意轉移
|
||||||
transfer.accept_desc=轉移到「%s」
|
transfer.accept_desc=轉移到「%s」
|
||||||
|
55
package-lock.json
generated
55
package-lock.json
generated
@ -67,7 +67,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
||||||
"@playwright/test": "1.49.1",
|
"@playwright/test": "1.49.1",
|
||||||
"@silverwind/vue-tsc": "2.1.13",
|
|
||||||
"@stoplight/spectral-cli": "6.14.2",
|
"@stoplight/spectral-cli": "6.14.2",
|
||||||
"@stylistic/eslint-plugin-js": "2.12.1",
|
"@stylistic/eslint-plugin-js": "2.12.1",
|
||||||
"@stylistic/stylelint-plugin": "3.1.1",
|
"@stylistic/stylelint-plugin": "3.1.1",
|
||||||
@ -112,7 +111,8 @@
|
|||||||
"type-fest": "4.30.2",
|
"type-fest": "4.30.2",
|
||||||
"updates": "16.4.1",
|
"updates": "16.4.1",
|
||||||
"vite-string-plugin": "1.3.4",
|
"vite-string-plugin": "1.3.4",
|
||||||
"vitest": "2.1.8"
|
"vitest": "2.1.8",
|
||||||
|
"vue-tsc": "2.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18.0.0"
|
"node": ">= 18.0.0"
|
||||||
@ -3643,24 +3643,6 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@silverwind/vue-tsc": {
|
|
||||||
"version": "2.1.13",
|
|
||||||
"resolved": "https://registry.npmjs.org/@silverwind/vue-tsc/-/vue-tsc-2.1.13.tgz",
|
|
||||||
"integrity": "sha512-ejFxz1KZiUGAESbC+eURnjqt0N95qkU9eZU7W15wgF9zV+v2FEu3ZLduuXTC7D/Sg6lL1R/QjPfUbxbAbBQOsw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@volar/typescript": "~2.4.11",
|
|
||||||
"@vue/language-core": "2.1.10",
|
|
||||||
"semver": "^7.5.4"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"vue-tsc": "bin/vue-tsc.js"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"typescript": ">=5.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@silverwind/vue3-calendar-heatmap": {
|
"node_modules/@silverwind/vue3-calendar-heatmap": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@silverwind/vue3-calendar-heatmap/-/vue3-calendar-heatmap-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@silverwind/vue3-calendar-heatmap/-/vue3-calendar-heatmap-2.0.6.tgz",
|
||||||
@ -5251,17 +5233,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vue/language-core": {
|
"node_modules/@vue/language-core": {
|
||||||
"version": "2.1.10",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz",
|
||||||
"integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==",
|
"integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@volar/language-core": "~2.4.8",
|
"@volar/language-core": "~2.4.11",
|
||||||
"@vue/compiler-dom": "^3.5.0",
|
"@vue/compiler-dom": "^3.5.0",
|
||||||
"@vue/compiler-vue2": "^2.7.16",
|
"@vue/compiler-vue2": "^2.7.16",
|
||||||
"@vue/shared": "^3.5.0",
|
"@vue/shared": "^3.5.0",
|
||||||
"alien-signals": "^0.2.0",
|
"alien-signals": "^0.4.9",
|
||||||
"minimatch": "^9.0.3",
|
"minimatch": "^9.0.3",
|
||||||
"muggle-string": "^0.4.1",
|
"muggle-string": "^0.4.1",
|
||||||
"path-browserify": "^1.0.1"
|
"path-browserify": "^1.0.1"
|
||||||
@ -5664,9 +5646,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/alien-signals": {
|
"node_modules/alien-signals": {
|
||||||
"version": "0.2.2",
|
"version": "0.4.14",
|
||||||
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz",
|
||||||
"integrity": "sha512-cZIRkbERILsBOXTQmMrxc9hgpxglstn69zm+F1ARf4aPAzdAFYd6sBq87ErO0Fj3DV94tglcyHG5kQz9nDC/8A==",
|
"integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@ -14526,6 +14508,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-tsc": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-gtmM1sUuJ8aSb0KoAFmK9yMxb8TxjewmxqTJ1aKphD5Cbu0rULFY6+UQT51zW7SpUcenfPUuflKyVwyx9Qdnxg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@volar/typescript": "~2.4.11",
|
||||||
|
"@vue/language-core": "2.2.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vue-tsc": "bin/vue-tsc.js"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
||||||
"@playwright/test": "1.49.1",
|
"@playwright/test": "1.49.1",
|
||||||
"@silverwind/vue-tsc": "2.1.13",
|
|
||||||
"@stoplight/spectral-cli": "6.14.2",
|
"@stoplight/spectral-cli": "6.14.2",
|
||||||
"@stylistic/eslint-plugin-js": "2.12.1",
|
"@stylistic/eslint-plugin-js": "2.12.1",
|
||||||
"@stylistic/stylelint-plugin": "3.1.1",
|
"@stylistic/stylelint-plugin": "3.1.1",
|
||||||
@ -111,7 +110,8 @@
|
|||||||
"type-fest": "4.30.2",
|
"type-fest": "4.30.2",
|
||||||
"updates": "16.4.1",
|
"updates": "16.4.1",
|
||||||
"vite-string-plugin": "1.3.4",
|
"vite-string-plugin": "1.3.4",
|
||||||
"vitest": "2.1.8"
|
"vitest": "2.1.8",
|
||||||
|
"vue-tsc": "2.2.0"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"defaults"
|
"defaults"
|
||||||
|
@ -34,11 +34,30 @@ func ListHooks(ctx *context.APIContext) {
|
|||||||
// in: query
|
// in: query
|
||||||
// description: page size of results
|
// description: page size of results
|
||||||
// type: integer
|
// type: integer
|
||||||
|
// - type: string
|
||||||
|
// enum:
|
||||||
|
// - system
|
||||||
|
// - default
|
||||||
|
// - all
|
||||||
|
// description: system, default or both kinds of webhooks
|
||||||
|
// name: type
|
||||||
|
// default: system
|
||||||
|
// in: query
|
||||||
|
//
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/HookList"
|
// "$ref": "#/responses/HookList"
|
||||||
|
|
||||||
sysHooks, err := webhook.GetSystemWebhooks(ctx, optional.None[bool]())
|
// for compatibility the default value is true
|
||||||
|
isSystemWebhook := optional.Some(true)
|
||||||
|
typeValue := ctx.FormString("type")
|
||||||
|
if typeValue == "default" {
|
||||||
|
isSystemWebhook = optional.Some(false)
|
||||||
|
} else if typeValue == "all" {
|
||||||
|
isSystemWebhook = optional.None[bool]()
|
||||||
|
}
|
||||||
|
|
||||||
|
sysHooks, err := webhook.GetSystemOrDefaultWebhooks(ctx, isSystemWebhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetSystemWebhooks", err)
|
ctx.Error(http.StatusInternalServerError, "GetSystemWebhooks", err)
|
||||||
return
|
return
|
||||||
|
@ -26,13 +26,9 @@ type userSearchResponse struct {
|
|||||||
Results []*userSearchInfo `json:"results"`
|
Results []*userSearchInfo `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssuePosters get posters for current repo's issues/pull requests
|
func IssuePullPosters(ctx *context.Context) {
|
||||||
func IssuePosters(ctx *context.Context) {
|
isPullList := ctx.PathParam("type") == "pulls"
|
||||||
issuePosters(ctx, false)
|
issuePosters(ctx, isPullList)
|
||||||
}
|
|
||||||
|
|
||||||
func PullPosters(ctx *context.Context) {
|
|
||||||
issuePosters(ctx, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func issuePosters(ctx *context.Context, isPullList bool) {
|
func issuePosters(ctx *context.Context, isPullList bool) {
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -330,34 +329,17 @@ func LatestRelease(ctx *context.Context) {
|
|||||||
ctx.Redirect(release.Link())
|
ctx.Redirect(release.Link())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRelease render creating or edit release page
|
func newReleaseCommon(ctx *context.Context) {
|
||||||
func NewRelease(ctx *context.Context) {
|
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
|
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
|
||||||
ctx.Data["PageIsReleaseList"] = true
|
ctx.Data["PageIsReleaseList"] = true
|
||||||
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
|
|
||||||
if tagName := ctx.FormString("tag"); len(tagName) > 0 {
|
|
||||||
rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName)
|
|
||||||
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
|
||||||
ctx.ServerError("GetRelease", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if rel != nil {
|
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
|
||||||
rel.Repo = ctx.Repo.Repository
|
if err != nil {
|
||||||
if err := rel.LoadAttributes(ctx); err != nil {
|
ctx.ServerError("GetTagNamesByRepoID", err)
|
||||||
ctx.ServerError("LoadAttributes", err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Data["tag_name"] = rel.TagName
|
|
||||||
if rel.Target != "" {
|
|
||||||
ctx.Data["tag_target"] = rel.Target
|
|
||||||
}
|
|
||||||
ctx.Data["title"] = rel.Title
|
|
||||||
ctx.Data["content"] = rel.Note
|
|
||||||
ctx.Data["attachments"] = rel.Attachments
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ctx.Data["Tags"] = tags
|
||||||
|
|
||||||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
||||||
assigneeUsers, err := repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository)
|
assigneeUsers, err := repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -368,35 +350,74 @@ func NewRelease(ctx *context.Context) {
|
|||||||
|
|
||||||
upload.AddUploadContext(ctx, "release")
|
upload.AddUploadContext(ctx, "release")
|
||||||
|
|
||||||
// For New Release page
|
PrepareBranchList(ctx) // for New Release page
|
||||||
PrepareBranchList(ctx)
|
}
|
||||||
|
|
||||||
|
// NewRelease render creating or edit release page
|
||||||
|
func NewRelease(ctx *context.Context) {
|
||||||
|
newReleaseCommon(ctx)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
|
ctx.Data["ShowCreateTagOnlyButton"] = true
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetTagNamesByRepoID", err)
|
// pre-fill the form with the tag name, target branch and the existing release (if exists)
|
||||||
return
|
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
|
||||||
|
if tagName := ctx.FormString("tag"); tagName != "" {
|
||||||
|
rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName)
|
||||||
|
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||||
|
ctx.ServerError("GetRelease", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rel != nil {
|
||||||
|
rel.Repo = ctx.Repo.Repository
|
||||||
|
if err = rel.LoadAttributes(ctx); err != nil {
|
||||||
|
ctx.ServerError("LoadAttributes", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["ShowCreateTagOnlyButton"] = false
|
||||||
|
ctx.Data["tag_name"] = rel.TagName
|
||||||
|
ctx.Data["tag_target"] = rel.Target
|
||||||
|
ctx.Data["title"] = rel.Title
|
||||||
|
ctx.Data["content"] = rel.Note
|
||||||
|
ctx.Data["attachments"] = rel.Attachments
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.Data["Tags"] = tags
|
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplReleaseNew)
|
ctx.HTML(http.StatusOK, tplReleaseNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReleasePost response for creating a release
|
// NewReleasePost response for creating a release
|
||||||
func NewReleasePost(ctx *context.Context) {
|
func NewReleasePost(ctx *context.Context) {
|
||||||
form := web.GetForm(ctx).(*forms.NewReleaseForm)
|
newReleaseCommon(ctx)
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
|
if ctx.Written() {
|
||||||
ctx.Data["PageIsReleaseList"] = true
|
|
||||||
|
|
||||||
tags, err := repo_model.GetTagNamesByRepoID(ctx, ctx.Repo.Repository.ID)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetTagNamesByRepoID", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Tags"] = tags
|
|
||||||
|
|
||||||
|
form := web.GetForm(ctx).(*forms.NewReleaseForm)
|
||||||
|
|
||||||
|
// first, check whether the release exists, and prepare "ShowCreateTagOnlyButton"
|
||||||
|
// the logic should be done before the form error check to make the tmpl has correct variables
|
||||||
|
rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName)
|
||||||
|
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||||
|
ctx.ServerError("GetRelease", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should still show the "tag only" button if the user clicks it, no matter the release exists or not.
|
||||||
|
// Because if error occurs, end users need to have the chance to edit the name and submit the form with "tag-only" again.
|
||||||
|
// It is still not completely right, because there could still be cases like this:
|
||||||
|
// * user visit "new release" page, see the "tag only" button
|
||||||
|
// * input something, click other buttons but not "tag only"
|
||||||
|
// * error occurs, the "new release" page is rendered again, but the "tag only" button is gone
|
||||||
|
// Such cases are not able to be handled by current code, it needs frontend code to toggle the "tag-only" button if the input changes.
|
||||||
|
// Or another choice is "always show the tag-only button" if error occurs.
|
||||||
|
ctx.Data["ShowCreateTagOnlyButton"] = form.TagOnly || rel == nil
|
||||||
|
|
||||||
|
// do some form checks
|
||||||
if ctx.HasError() {
|
if ctx.HasError() {
|
||||||
ctx.HTML(http.StatusOK, tplReleaseNew)
|
ctx.HTML(http.StatusOK, tplReleaseNew)
|
||||||
return
|
return
|
||||||
@ -407,59 +428,49 @@ func NewReleasePost(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title of release cannot be empty
|
if !form.TagOnly && form.Title == "" {
|
||||||
if len(form.TagOnly) == 0 && len(form.Title) == 0 {
|
// if not "tag only", then the title of the release cannot be empty
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.release.title_empty"), tplReleaseNew, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.release.title_empty"), tplReleaseNew, &form)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachmentUUIDs []string
|
handleTagReleaseError := func(err error) {
|
||||||
if setting.Attachment.Enabled {
|
ctx.Data["Err_TagName"] = true
|
||||||
attachmentUUIDs = form.Files
|
switch {
|
||||||
|
case release_service.IsErrTagAlreadyExists(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.branch.tag_collision", form.TagName), tplReleaseNew, &form)
|
||||||
|
case repo_model.IsErrReleaseAlreadyExist(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
|
||||||
|
case release_service.IsErrInvalidTagName(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form)
|
||||||
|
case release_service.IsErrProtectedTagName(err):
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form)
|
||||||
|
default:
|
||||||
|
ctx.ServerError("handleTagReleaseError", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName)
|
// prepare the git message for creating a new tag
|
||||||
if err != nil {
|
newTagMsg := ""
|
||||||
if !repo_model.IsErrReleaseNotExist(err) {
|
if form.Title != "" && form.AddTagMsg {
|
||||||
ctx.ServerError("GetRelease", err)
|
newTagMsg = form.Title + "\n\n" + form.Content
|
||||||
|
}
|
||||||
|
|
||||||
|
// no release, and tag only
|
||||||
|
if rel == nil && form.TagOnly {
|
||||||
|
if err = release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, newTagMsg); err != nil {
|
||||||
|
handleTagReleaseError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx.Flash.Success(ctx.Tr("repo.tag.create_success", form.TagName))
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/src/tag/" + util.PathEscapeSegments(form.TagName))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
msg := ""
|
attachmentUUIDs := util.Iif(setting.Attachment.Enabled, form.Files, nil)
|
||||||
if len(form.Title) > 0 && form.AddTagMsg {
|
|
||||||
msg = form.Title + "\n\n" + form.Content
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(form.TagOnly) > 0 {
|
|
||||||
if err = release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, form.Target, form.TagName, msg); err != nil {
|
|
||||||
if release_service.IsErrTagAlreadyExists(err) {
|
|
||||||
e := err.(release_service.ErrTagAlreadyExists)
|
|
||||||
ctx.Flash.Error(ctx.Tr("repo.branch.tag_collision", e.TagName))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if release_service.IsErrInvalidTagName(err) {
|
|
||||||
ctx.Flash.Error(ctx.Tr("repo.release.tag_name_invalid"))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if release_service.IsErrProtectedTagName(err) {
|
|
||||||
ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected"))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.ServerError("release_service.CreateNewTag", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Flash.Success(ctx.Tr("repo.tag.create_success", form.TagName))
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/tag/" + util.PathEscapeSegments(form.TagName))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// no existing release, create a new release
|
||||||
|
if rel == nil {
|
||||||
rel = &repo_model.Release{
|
rel = &repo_model.Release{
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
Repo: ctx.Repo.Repository,
|
Repo: ctx.Repo.Repository,
|
||||||
@ -469,48 +480,39 @@ func NewReleasePost(ctx *context.Context) {
|
|||||||
TagName: form.TagName,
|
TagName: form.TagName,
|
||||||
Target: form.Target,
|
Target: form.Target,
|
||||||
Note: form.Content,
|
Note: form.Content,
|
||||||
IsDraft: len(form.Draft) > 0,
|
IsDraft: form.Draft,
|
||||||
IsPrerelease: form.Prerelease,
|
IsPrerelease: form.Prerelease,
|
||||||
IsTag: false,
|
IsTag: false,
|
||||||
}
|
}
|
||||||
|
if err = release_service.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs, newTagMsg); err != nil {
|
||||||
if err = release_service.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs, msg); err != nil {
|
handleTagReleaseError(err)
|
||||||
ctx.Data["Err_TagName"] = true
|
|
||||||
switch {
|
|
||||||
case repo_model.IsErrReleaseAlreadyExist(err):
|
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
|
|
||||||
case release_service.IsErrInvalidTagName(err):
|
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form)
|
|
||||||
case release_service.IsErrProtectedTagName(err):
|
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form)
|
|
||||||
default:
|
|
||||||
ctx.ServerError("CreateRelease", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !rel.IsTag {
|
|
||||||
ctx.Data["Err_TagName"] = true
|
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rel.Title = form.Title
|
|
||||||
rel.Note = form.Content
|
|
||||||
rel.Target = form.Target
|
|
||||||
rel.IsDraft = len(form.Draft) > 0
|
|
||||||
rel.IsPrerelease = form.Prerelease
|
|
||||||
rel.PublisherID = ctx.Doer.ID
|
|
||||||
rel.IsTag = false
|
|
||||||
|
|
||||||
if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil {
|
|
||||||
ctx.Data["Err_TagName"] = true
|
|
||||||
ctx.ServerError("UpdateRelease", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Release created: %s/%s:%s", ctx.Doer.LowerName, ctx.Repo.Repository.Name, form.TagName)
|
|
||||||
|
|
||||||
|
// tag exists, try to convert it to a real release
|
||||||
|
// old logic: if the release is not a tag (it is a real release), do not update it on the "new release" page
|
||||||
|
// add new logic: if tag-only, do not convert the tag to a release
|
||||||
|
if form.TagOnly || !rel.IsTag {
|
||||||
|
ctx.Data["Err_TagName"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert a tag to a real release (set is_tag=false)
|
||||||
|
rel.Title = form.Title
|
||||||
|
rel.Note = form.Content
|
||||||
|
rel.Target = form.Target
|
||||||
|
rel.IsDraft = form.Draft
|
||||||
|
rel.IsPrerelease = form.Prerelease
|
||||||
|
rel.PublisherID = ctx.Doer.ID
|
||||||
|
rel.IsTag = false
|
||||||
|
if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil {
|
||||||
|
handleTagReleaseError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
|
ctx.Redirect(ctx.Repo.RepoLink + "/releases")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,60 +11,135 @@ import (
|
|||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/contexttest"
|
"code.gitea.io/gitea/services/contexttest"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewReleasePost(t *testing.T) {
|
func TestNewReleasePost(t *testing.T) {
|
||||||
for _, testCase := range []struct {
|
unittest.PrepareTestEnv(t)
|
||||||
RepoID int64
|
|
||||||
UserID int64
|
|
||||||
TagName string
|
|
||||||
Form forms.NewReleaseForm
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
RepoID: 1,
|
|
||||||
UserID: 2,
|
|
||||||
TagName: "v1.1", // pre-existing tag
|
|
||||||
Form: forms.NewReleaseForm{
|
|
||||||
TagName: "newtag",
|
|
||||||
Target: "master",
|
|
||||||
Title: "title",
|
|
||||||
Content: "content",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RepoID: 1,
|
|
||||||
UserID: 2,
|
|
||||||
TagName: "newtag",
|
|
||||||
Form: forms.NewReleaseForm{
|
|
||||||
TagName: "newtag",
|
|
||||||
Target: "master",
|
|
||||||
Title: "title",
|
|
||||||
Content: "content",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
unittest.PrepareTestEnv(t)
|
|
||||||
|
|
||||||
|
get := func(t *testing.T, tagName string) *context.Context {
|
||||||
|
ctx, _ := contexttest.MockContext(t, "user2/repo1/releases/new?tag="+tagName)
|
||||||
|
contexttest.LoadUser(t, ctx, 2)
|
||||||
|
contexttest.LoadRepo(t, ctx, 1)
|
||||||
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
|
defer ctx.Repo.GitRepo.Close()
|
||||||
|
NewRelease(ctx)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("NewReleasePage", func(t *testing.T) {
|
||||||
|
ctx := get(t, "v1.1")
|
||||||
|
assert.Empty(t, ctx.Data["ShowCreateTagOnlyButton"])
|
||||||
|
ctx = get(t, "new-tag-name")
|
||||||
|
assert.NotEmpty(t, ctx.Data["ShowCreateTagOnlyButton"])
|
||||||
|
})
|
||||||
|
|
||||||
|
post := func(t *testing.T, form forms.NewReleaseForm) *context.Context {
|
||||||
ctx, _ := contexttest.MockContext(t, "user2/repo1/releases/new")
|
ctx, _ := contexttest.MockContext(t, "user2/repo1/releases/new")
|
||||||
contexttest.LoadUser(t, ctx, 2)
|
contexttest.LoadUser(t, ctx, 2)
|
||||||
contexttest.LoadRepo(t, ctx, 1)
|
contexttest.LoadRepo(t, ctx, 1)
|
||||||
contexttest.LoadGitRepo(t, ctx)
|
contexttest.LoadGitRepo(t, ctx)
|
||||||
web.SetForm(ctx, &testCase.Form)
|
defer ctx.Repo.GitRepo.Close()
|
||||||
|
web.SetForm(ctx, &form)
|
||||||
NewReleasePost(ctx)
|
NewReleasePost(ctx)
|
||||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Release{
|
return ctx
|
||||||
RepoID: 1,
|
|
||||||
PublisherID: 2,
|
|
||||||
TagName: testCase.Form.TagName,
|
|
||||||
Target: testCase.Form.Target,
|
|
||||||
Title: testCase.Form.Title,
|
|
||||||
Note: testCase.Form.Content,
|
|
||||||
}, unittest.Cond("is_draft=?", len(testCase.Form.Draft) > 0))
|
|
||||||
ctx.Repo.GitRepo.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadRelease := func(t *testing.T, tagName string) *repo_model.Release {
|
||||||
|
return unittest.GetBean(t, &repo_model.Release{}, unittest.Cond("repo_id=1 AND tag_name=?", tagName))
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("NewTagRelease", func(t *testing.T) {
|
||||||
|
post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "newtag",
|
||||||
|
Target: "master",
|
||||||
|
Title: "title",
|
||||||
|
Content: "content",
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "newtag")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.False(t, rel.IsTag)
|
||||||
|
assert.Equal(t, "master", rel.Target)
|
||||||
|
assert.Equal(t, "title", rel.Title)
|
||||||
|
assert.Equal(t, "content", rel.Note)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ReleaseExistsDoUpdate(non-tag)", func(t *testing.T) {
|
||||||
|
ctx := post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "v1.1",
|
||||||
|
Target: "master",
|
||||||
|
Title: "updated-title",
|
||||||
|
Content: "updated-content",
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "v1.1")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.False(t, rel.IsTag)
|
||||||
|
assert.Equal(t, "testing-release", rel.Title)
|
||||||
|
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ReleaseExistsDoUpdate(tag-only)", func(t *testing.T) {
|
||||||
|
ctx := post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "delete-tag", // a strange name, but it is the only "is_tag=true" fixture
|
||||||
|
Target: "master",
|
||||||
|
Title: "updated-title",
|
||||||
|
Content: "updated-content",
|
||||||
|
TagOnly: true,
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "delete-tag")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.True(t, rel.IsTag) // the record should not be updated because the request is "tag-only". TODO: need to improve the logic?
|
||||||
|
assert.Equal(t, "delete-tag", rel.Title)
|
||||||
|
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||||
|
assert.NotEmpty(t, ctx.Data["ShowCreateTagOnlyButton"]) // still show the "tag-only" button
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ReleaseExistsDoUpdate(tag-release)", func(t *testing.T) {
|
||||||
|
ctx := post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "delete-tag", // a strange name, but it is the only "is_tag=true" fixture
|
||||||
|
Target: "master",
|
||||||
|
Title: "updated-title",
|
||||||
|
Content: "updated-content",
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "delete-tag")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.False(t, rel.IsTag) // the tag has been "updated" to be a real "release"
|
||||||
|
assert.Equal(t, "updated-title", rel.Title)
|
||||||
|
assert.Empty(t, ctx.Flash.ErrorMsg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("TagOnly", func(t *testing.T) {
|
||||||
|
ctx := post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "new-tag-only",
|
||||||
|
Target: "master",
|
||||||
|
Title: "title",
|
||||||
|
Content: "content",
|
||||||
|
TagOnly: true,
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "new-tag-only")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.True(t, rel.IsTag)
|
||||||
|
assert.Empty(t, ctx.Flash.ErrorMsg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("TagOnlyConflict", func(t *testing.T) {
|
||||||
|
ctx := post(t, forms.NewReleaseForm{
|
||||||
|
TagName: "v1.1",
|
||||||
|
Target: "master",
|
||||||
|
Title: "title",
|
||||||
|
Content: "content",
|
||||||
|
TagOnly: true,
|
||||||
|
})
|
||||||
|
rel := loadRelease(t, "v1.1")
|
||||||
|
require.NotNil(t, rel)
|
||||||
|
assert.False(t, rel.IsTag)
|
||||||
|
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalReleaseNumCommitsBehind(t *testing.T) {
|
func TestCalReleaseNumCommitsBehind(t *testing.T) {
|
||||||
|
@ -51,7 +51,7 @@ func MustBeNotEmpty(ctx *context.Context) {
|
|||||||
|
|
||||||
// MustBeEditable check that repo can be edited
|
// MustBeEditable check that repo can be edited
|
||||||
func MustBeEditable(ctx *context.Context) {
|
func MustBeEditable(ctx *context.Context) {
|
||||||
if !ctx.Repo.Repository.CanEnableEditor() || ctx.Repo.IsViewCommit {
|
if !ctx.Repo.Repository.CanEnableEditor() {
|
||||||
ctx.NotFound("", nil)
|
ctx.NotFound("", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,15 @@ const (
|
|||||||
tplDeployKeys templates.TplName = "repo/settings/deploy_keys"
|
tplDeployKeys templates.TplName = "repo/settings/deploy_keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func parseEveryoneAccessMode(permission string, allowed ...perm.AccessMode) perm.AccessMode {
|
||||||
|
// if site admin forces repositories to be private, then do not allow any other access mode,
|
||||||
|
// otherwise the "force private" setting would be bypassed
|
||||||
|
if setting.Repository.ForcePrivate {
|
||||||
|
return perm.AccessModeNone
|
||||||
|
}
|
||||||
|
return perm.ParseAccessMode(permission, allowed...)
|
||||||
|
}
|
||||||
|
|
||||||
// SettingsCtxData is a middleware that sets all the general context data for the
|
// SettingsCtxData is a middleware that sets all the general context data for the
|
||||||
// settings template.
|
// settings template.
|
||||||
func SettingsCtxData(ctx *context.Context) {
|
func SettingsCtxData(ctx *context.Context) {
|
||||||
@ -447,8 +456,9 @@ func SettingsPost(ctx *context.Context) {
|
|||||||
|
|
||||||
if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
|
if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
|
||||||
units = append(units, repo_model.RepoUnit{
|
units = append(units, repo_model.RepoUnit{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Type: unit_model.TypeCode,
|
Type: unit_model.TypeCode,
|
||||||
|
EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultCodeEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
|
||||||
})
|
})
|
||||||
} else if !unit_model.TypeCode.UnitGlobalDisabled() {
|
} else if !unit_model.TypeCode.UnitGlobalDisabled() {
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
|
||||||
@ -474,7 +484,7 @@ func SettingsPost(ctx *context.Context) {
|
|||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
Type: unit_model.TypeWiki,
|
Type: unit_model.TypeWiki,
|
||||||
Config: new(repo_model.UnitConfig),
|
Config: new(repo_model.UnitConfig),
|
||||||
EveryoneAccessMode: perm.ParseAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
|
EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
|
||||||
})
|
})
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
|
||||||
} else {
|
} else {
|
||||||
@ -524,6 +534,7 @@ func SettingsPost(ctx *context.Context) {
|
|||||||
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
|
||||||
EnableDependencies: form.EnableIssueDependencies,
|
EnableDependencies: form.EnableIssueDependencies,
|
||||||
},
|
},
|
||||||
|
EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultIssuesEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
|
||||||
})
|
})
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,7 +249,7 @@ func handleRepoEmptyOrBroken(ctx *context.Context) {
|
|||||||
} else if reallyEmpty {
|
} else if reallyEmpty {
|
||||||
showEmpty = true // the repo is really empty
|
showEmpty = true // the repo is really empty
|
||||||
updateContextRepoEmptyAndStatus(ctx, true, repo_model.RepositoryReady)
|
updateContextRepoEmptyAndStatus(ctx, true, repo_model.RepositoryReady)
|
||||||
} else if ctx.Repo.Commit == nil {
|
} else if branches, _, _ := ctx.Repo.GitRepo.GetBranches(0, 1); len(branches) == 0 {
|
||||||
showEmpty = true // it is not really empty, but there is no branch
|
showEmpty = true // it is not really empty, but there is no branch
|
||||||
// at the moment, other repo units like "actions" are not able to handle such case,
|
// at the moment, other repo units like "actions" are not able to handle such case,
|
||||||
// so we just mark the repo as empty to prevent from displaying these units.
|
// so we just mark the repo as empty to prevent from displaying these units.
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/metrics"
|
"code.gitea.io/gitea/modules/metrics"
|
||||||
"code.gitea.io/gitea/modules/public"
|
"code.gitea.io/gitea/modules/public"
|
||||||
@ -101,7 +102,7 @@ func buildAuthGroup() *auth_service.Group {
|
|||||||
group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers
|
group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers
|
||||||
|
|
||||||
if setting.Service.EnableReverseProxyAuth {
|
if setting.Service.EnableReverseProxyAuth {
|
||||||
group.Add(&auth_service.ReverseProxy{}) // reverseproxy should before Session, otherwise the header will be ignored if user has login
|
group.Add(&auth_service.ReverseProxy{}) // reverse-proxy should before Session, otherwise the header will be ignored if user has login
|
||||||
}
|
}
|
||||||
group.Add(&auth_service.Session{})
|
group.Add(&auth_service.Session{})
|
||||||
|
|
||||||
@ -816,21 +817,23 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action)
|
m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action)
|
||||||
|
|
||||||
reqRepoAdmin := context.RequireRepoAdmin()
|
reqRepoAdmin := context.RequireRepoAdmin()
|
||||||
reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode)
|
reqRepoCodeWriter := context.RequireUnitWriter(unit.TypeCode)
|
||||||
canEnableEditor := context.CanEnableEditor()
|
reqRepoReleaseWriter := context.RequireUnitWriter(unit.TypeReleases)
|
||||||
reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode)
|
reqRepoReleaseReader := context.RequireUnitReader(unit.TypeReleases)
|
||||||
reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases)
|
reqRepoIssuesOrPullsWriter := context.RequireUnitWriter(unit.TypeIssues, unit.TypePullRequests)
|
||||||
reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases)
|
reqRepoIssuesOrPullsReader := context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)
|
||||||
reqRepoWikiReader := context.RequireRepoReader(unit.TypeWiki)
|
reqRepoProjectsReader := context.RequireUnitReader(unit.TypeProjects)
|
||||||
reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki)
|
reqRepoProjectsWriter := context.RequireUnitWriter(unit.TypeProjects)
|
||||||
reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues)
|
reqRepoActionsReader := context.RequireUnitReader(unit.TypeActions)
|
||||||
reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests)
|
reqRepoActionsWriter := context.RequireUnitWriter(unit.TypeActions)
|
||||||
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(unit.TypeIssues, unit.TypePullRequests)
|
|
||||||
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests)
|
// the legacy names "reqRepoXxx" should be renamed to the correct name "reqUnitXxx", these permissions are for units, not repos
|
||||||
reqRepoProjectsReader := context.RequireRepoReader(unit.TypeProjects)
|
reqUnitsWithMarkdown := context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki)
|
||||||
reqRepoProjectsWriter := context.RequireRepoWriter(unit.TypeProjects)
|
reqUnitCodeReader := context.RequireUnitReader(unit.TypeCode)
|
||||||
reqRepoActionsReader := context.RequireRepoReader(unit.TypeActions)
|
reqUnitIssuesReader := context.RequireUnitReader(unit.TypeIssues)
|
||||||
reqRepoActionsWriter := context.RequireRepoWriter(unit.TypeActions)
|
reqUnitPullsReader := context.RequireUnitReader(unit.TypePullRequests)
|
||||||
|
reqUnitWikiReader := context.RequireUnitReader(unit.TypeWiki)
|
||||||
|
reqUnitWikiWriter := context.RequireUnitWriter(unit.TypeWiki)
|
||||||
|
|
||||||
reqPackageAccess := func(accessMode perm.AccessMode) func(ctx *context.Context) {
|
reqPackageAccess := func(accessMode perm.AccessMode) func(ctx *context.Context) {
|
||||||
return func(ctx *context.Context) {
|
return func(ctx *context.Context) {
|
||||||
@ -1053,7 +1056,7 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Group("/migrate", func() {
|
m.Group("/migrate", func() {
|
||||||
m.Get("/status", repo.MigrateStatus)
|
m.Get("/status", repo.MigrateStatus)
|
||||||
})
|
})
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoCodeReader)
|
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
|
||||||
// end "/{username}/{reponame}/-": migrate
|
// end "/{username}/{reponame}/-": migrate
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}/settings", func() {
|
m.Group("/{username}/{reponame}/settings", func() {
|
||||||
@ -1149,56 +1152,54 @@ func registerRoutes(m *web.Router) {
|
|||||||
// end "/{username}/{reponame}/settings"
|
// end "/{username}/{reponame}/settings"
|
||||||
|
|
||||||
// user/org home, including rss feeds
|
// user/org home, including rss feeds
|
||||||
m.Get("/{username}/{reponame}", optSignIn, context.RepoAssignment, context.RepoRef(), repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("/{username}/{reponame}", optSignIn, context.RepoAssignment, context.RepoRefByType(git.RefTypeBranch), repo.SetEditorconfigIfExists, repo.Home)
|
||||||
|
|
||||||
// TODO: maybe it should relax the permission to allow "any access"
|
m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, reqUnitsWithMarkdown, web.Bind(structs.MarkupOption{}), misc.Markup)
|
||||||
m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki), web.Bind(structs.MarkupOption{}), misc.Markup)
|
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Get("/find/*", repo.FindFiles)
|
m.Get("/find/*", repo.FindFiles)
|
||||||
m.Group("/tree-list", func() {
|
m.Group("/tree-list", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.TreeList)
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.TreeList)
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.TreeList)
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList)
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.TreeList)
|
||||||
})
|
})
|
||||||
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
|
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
|
||||||
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
|
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
|
||||||
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
|
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
|
||||||
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
|
Post(reqSignIn, context.RepoMustNotBeArchived(), reqUnitPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoCodeReader)
|
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
|
||||||
// end "/{username}/{reponame}": repo code: find, compare, list
|
// end "/{username}/{reponame}": repo code: find, compare, list
|
||||||
|
|
||||||
|
addIssuesPullsViewRoutes := func() {
|
||||||
|
// for /{username}/{reponame}/issues" or "/{username}/{reponame}/pulls"
|
||||||
|
m.Get("/posters", repo.IssuePullPosters)
|
||||||
|
m.Group("/{index}", func() {
|
||||||
|
m.Get("/info", repo.GetIssueInfo)
|
||||||
|
m.Get("/attachments", repo.GetIssueAttachments)
|
||||||
|
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
||||||
|
m.Group("/content-history", func() {
|
||||||
|
m.Get("/overview", repo.GetContentHistoryOverview)
|
||||||
|
m.Get("/list", repo.GetContentHistoryList)
|
||||||
|
m.Get("/detail", repo.GetContentHistoryDetail)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because it would conflict with other routes like "/pulls/{index}"
|
|
||||||
m.Get("/pulls/posters", repo.PullPosters)
|
|
||||||
m.Get("/comments/{id}/attachments", repo.GetCommentAttachments)
|
m.Get("/comments/{id}/attachments", repo.GetCommentAttachments)
|
||||||
m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels)
|
m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels)
|
||||||
m.Get("/milestones", repo.Milestones)
|
m.Get("/milestones", repo.Milestones)
|
||||||
m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls)
|
m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls)
|
||||||
m.Group("/{type:issues|pulls}", func() {
|
|
||||||
m.Group("/{index}", func() {
|
|
||||||
m.Get("/info", repo.GetIssueInfo)
|
|
||||||
m.Get("/attachments", repo.GetIssueAttachments)
|
|
||||||
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
|
||||||
m.Group("/content-history", func() {
|
|
||||||
m.Get("/overview", repo.GetContentHistoryOverview)
|
|
||||||
m.Get("/list", repo.GetContentHistoryList)
|
|
||||||
m.Get("/detail", repo.GetContentHistoryDetail)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, context.RepoRef())
|
|
||||||
m.Get("/issues/suggestions", repo.IssueSuggestions)
|
m.Get("/issues/suggestions", repo.IssueSuggestions)
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
|
}, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones
|
||||||
|
|
||||||
|
m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitIssuesReader)
|
||||||
|
m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader)
|
||||||
// end "/{username}/{reponame}": view milestone, label, issue, pull, etc
|
// end "/{username}/{reponame}": view milestone, label, issue, pull, etc
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}/{type:issues}", func() {
|
||||||
m.Group("/{type:issues|pulls}", func() {
|
m.Get("", repo.Issues)
|
||||||
m.Get("", repo.Issues)
|
m.Get("/{index}", repo.ViewIssue)
|
||||||
m.Group("/{index}", func() {
|
}, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypeExternalTracker))
|
||||||
m.Get("", repo.ViewIssue)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests, unit.TypeExternalTracker))
|
|
||||||
// end "/{username}/{reponame}": issue/pull list, issue/pull view, external tracker
|
// end "/{username}/{reponame}": issue/pull list, issue/pull view, external tracker
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() { // edit issues, pulls, labels, milestones, etc
|
m.Group("/{username}/{reponame}", func() { // edit issues, pulls, labels, milestones, etc
|
||||||
@ -1209,11 +1210,10 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
|
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
|
||||||
})
|
})
|
||||||
m.Get("/search", repo.SearchRepoIssuesJSON)
|
m.Get("/search", repo.SearchRepoIssuesJSON)
|
||||||
}, context.RepoMustNotBeArchived(), reqRepoIssueReader)
|
}, reqUnitIssuesReader)
|
||||||
|
|
||||||
// FIXME: should use different URLs but mostly same logic for comments of issue and pull request.
|
addIssuesPullsRoutes := func() {
|
||||||
// So they can apply their own enable/disable logic on routers.
|
// for "/{username}/{reponame}/issues" or "/{username}/{reponame}/pulls"
|
||||||
m.Group("/{type:issues|pulls}", func() {
|
|
||||||
m.Group("/{index}", func() {
|
m.Group("/{index}", func() {
|
||||||
m.Post("/title", repo.UpdateIssueTitle)
|
m.Post("/title", repo.UpdateIssueTitle)
|
||||||
m.Post("/content", repo.UpdateIssueContent)
|
m.Post("/content", repo.UpdateIssueContent)
|
||||||
@ -1240,39 +1240,37 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
|
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
|
||||||
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
|
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
|
||||||
m.Post("/delete", reqRepoAdmin, repo.DeleteIssue)
|
m.Post("/delete", reqRepoAdmin, repo.DeleteIssue)
|
||||||
}, context.RepoMustNotBeArchived())
|
|
||||||
|
|
||||||
m.Group("/{index}", func() {
|
|
||||||
m.Post("/content-history/soft-delete", repo.SoftDeleteContentHistory)
|
m.Post("/content-history/soft-delete", repo.SoftDeleteContentHistory)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
|
|
||||||
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
|
|
||||||
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
|
|
||||||
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
|
|
||||||
m.Post("/request_review", repo.UpdatePullReviewRequest)
|
|
||||||
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
|
|
||||||
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
|
|
||||||
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
|
|
||||||
m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
|
|
||||||
m.Post("/attachments", repo.UploadIssueAttachment)
|
m.Post("/attachments", repo.UploadIssueAttachment)
|
||||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||||
|
|
||||||
|
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
|
||||||
|
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
|
||||||
|
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
|
||||||
|
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
|
||||||
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
|
||||||
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
|
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
|
||||||
}, context.RepoMustNotBeArchived())
|
}
|
||||||
|
m.Group("/{type:issues}", addIssuesPullsRoutes, reqUnitIssuesReader, context.RepoMustNotBeArchived())
|
||||||
|
m.Group("/{type:pulls}", addIssuesPullsRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived())
|
||||||
|
|
||||||
m.Group("/comments/{id}", func() {
|
m.Group("/comments/{id}", func() {
|
||||||
m.Post("", repo.UpdateCommentContent)
|
m.Post("", repo.UpdateCommentContent)
|
||||||
m.Post("/delete", repo.DeleteComment)
|
m.Post("/delete", repo.DeleteComment)
|
||||||
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction)
|
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction)
|
||||||
}, context.RepoMustNotBeArchived())
|
}, reqRepoIssuesOrPullsReader) // edit issue/pull comment
|
||||||
|
|
||||||
|
m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel)
|
m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel)
|
||||||
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel)
|
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel)
|
||||||
m.Post("/delete", repo.DeleteLabel)
|
m.Post("/delete", repo.DeleteLabel)
|
||||||
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), repo.InitializeLabels)
|
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), repo.InitializeLabels)
|
||||||
}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
|
}, reqRepoIssuesOrPullsWriter, context.RepoRef())
|
||||||
|
|
||||||
|
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
|
||||||
m.Group("/milestones", func() {
|
m.Group("/milestones", func() {
|
||||||
m.Combo("/new").Get(repo.NewMilestone).
|
m.Combo("/new").Get(repo.NewMilestone).
|
||||||
Post(web.Bind(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
|
Post(web.Bind(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
|
||||||
@ -1280,11 +1278,15 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Post("/{id}/edit", web.Bind(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
|
m.Post("/{id}/edit", web.Bind(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
|
||||||
m.Post("/{id}/{action}", repo.ChangeMilestoneStatus)
|
m.Post("/{id}/{action}", repo.ChangeMilestoneStatus)
|
||||||
m.Post("/delete", repo.DeleteMilestone)
|
m.Post("/delete", repo.DeleteMilestone)
|
||||||
}, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
|
}, reqRepoIssuesOrPullsWriter, context.RepoRef())
|
||||||
m.Group("/pull", func() {
|
|
||||||
m.Post("/{index}/target_branch", repo.UpdatePullRequestTarget)
|
m.Group("", func() {
|
||||||
}, context.RepoMustNotBeArchived())
|
m.Post("/request_review", repo.UpdatePullReviewRequest)
|
||||||
}, reqSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
|
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
|
||||||
|
m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
|
||||||
|
m.Post("/pull/{index}/target_branch", repo.UpdatePullRequestTarget)
|
||||||
|
}, reqUnitPullsReader)
|
||||||
|
}, reqSignIn, context.RepoAssignment, context.RepoMustNotBeArchived())
|
||||||
// end "/{username}/{reponame}": create or edit issues, pulls, labels, milestones
|
// end "/{username}/{reponame}": create or edit issues, pulls, labels, milestones
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() { // repo code
|
m.Group("/{username}/{reponame}", func() { // repo code
|
||||||
@ -1304,18 +1306,18 @@ func registerRoutes(m *web.Router) {
|
|||||||
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost)
|
||||||
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick).
|
m.Combo("/_cherrypick/{sha:([a-f0-9]{7,64})}/*").Get(repo.CherryPick).
|
||||||
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost)
|
||||||
}, repo.MustBeEditable)
|
}, context.RepoRefByType(git.RefTypeBranch), context.CanWriteToBranch())
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Post("/upload-file", repo.UploadFileToServer)
|
m.Post("/upload-file", repo.UploadFileToServer)
|
||||||
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
|
||||||
}, repo.MustBeEditable, repo.MustBeAbleToUpload)
|
}, repo.MustBeAbleToUpload, reqRepoCodeWriter)
|
||||||
}, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived())
|
}, repo.MustBeEditable, context.RepoMustNotBeArchived())
|
||||||
|
|
||||||
m.Group("/branches", func() {
|
m.Group("/branches", func() {
|
||||||
m.Group("/_new", func() {
|
m.Group("/_new", func() {
|
||||||
m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch)
|
m.Post("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.CreateBranch)
|
||||||
m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch)
|
m.Post("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.CreateBranch)
|
||||||
m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch)
|
m.Post("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.CreateBranch)
|
||||||
}, web.Bind(forms.NewBranchForm{}))
|
}, web.Bind(forms.NewBranchForm{}))
|
||||||
m.Post("/delete", repo.DeleteBranchPost)
|
m.Post("/delete", repo.DeleteBranchPost)
|
||||||
m.Post("/restore", repo.RestoreBranchPost)
|
m.Post("/restore", repo.RestoreBranchPost)
|
||||||
@ -1324,45 +1326,42 @@ func registerRoutes(m *web.Router) {
|
|||||||
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
|
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
|
m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
|
||||||
}, reqSignIn, context.RepoAssignment, reqRepoCodeReader)
|
}, reqSignIn, context.RepoAssignment, reqUnitCodeReader)
|
||||||
// end "/{username}/{reponame}": repo code
|
// end "/{username}/{reponame}": repo code
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() { // repo tags
|
m.Group("/{username}/{reponame}", func() { // repo tags
|
||||||
m.Group("/tags", func() {
|
m.Group("/tags", func() {
|
||||||
m.Get("", repo.TagsList)
|
m.Get("", repo.TagsList)
|
||||||
m.Get("/list", repo.GetTagList)
|
|
||||||
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
|
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
|
||||||
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
|
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
|
||||||
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed),
|
m.Get("/list", repo.GetTagList)
|
||||||
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true}))
|
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed))
|
||||||
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
|
m.Post("/tags/delete", reqSignIn, reqRepoCodeWriter, context.RepoMustNotBeArchived(), repo.DeleteTag)
|
||||||
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
|
}, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqUnitCodeReader)
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoCodeReader)
|
|
||||||
// end "/{username}/{reponame}": repo tags
|
// end "/{username}/{reponame}": repo tags
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() { // repo releases
|
m.Group("/{username}/{reponame}", func() { // repo releases
|
||||||
m.Group("/releases", func() {
|
m.Group("/releases", func() {
|
||||||
m.Get("", repo.Releases)
|
m.Get("", repo.Releases)
|
||||||
m.Get("/tag/*", repo.SingleRelease)
|
|
||||||
m.Get("/latest", repo.LatestRelease)
|
|
||||||
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
|
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
|
||||||
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom)
|
m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom)
|
||||||
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed),
|
m.Get("/tag/*", repo.SingleRelease)
|
||||||
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true}))
|
m.Get("/latest", repo.LatestRelease)
|
||||||
m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, repo.GetAttachment)
|
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed))
|
||||||
m.Get("/releases/download/{vTag}/{fileName}", repo.MustBeNotEmpty, repo.RedirectDownload)
|
m.Get("/releases/attachments/{uuid}", repo.GetAttachment)
|
||||||
|
m.Get("/releases/download/{vTag}/{fileName}", repo.RedirectDownload)
|
||||||
m.Group("/releases", func() {
|
m.Group("/releases", func() {
|
||||||
m.Get("/new", repo.NewRelease)
|
m.Get("/new", repo.NewRelease)
|
||||||
m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
|
m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost)
|
||||||
m.Post("/delete", repo.DeleteRelease)
|
m.Post("/delete", repo.DeleteRelease)
|
||||||
m.Post("/attachments", repo.UploadReleaseAttachment)
|
m.Post("/attachments", repo.UploadReleaseAttachment)
|
||||||
m.Post("/attachments/remove", repo.DeleteAttachment)
|
m.Post("/attachments/remove", repo.DeleteAttachment)
|
||||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef())
|
}, reqSignIn, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, context.RepoRef())
|
||||||
m.Group("/releases", func() {
|
m.Group("/releases", func() {
|
||||||
m.Get("/edit/*", repo.EditRelease)
|
m.Get("/edit/*", repo.EditRelease)
|
||||||
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
|
||||||
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache)
|
}, reqSignIn, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache)
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoReleaseReader)
|
}, optSignIn, context.RepoAssignment, repo.MustBeNotEmpty, reqRepoReleaseReader)
|
||||||
// end "/{username}/{reponame}": repo releases
|
// end "/{username}/{reponame}": repo releases
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() { // to maintain compatibility with old attachments
|
m.Group("/{username}/{reponame}", func() { // to maintain compatibility with old attachments
|
||||||
@ -1440,43 +1439,48 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Group("/{username}/{reponame}/wiki", func() {
|
m.Group("/{username}/{reponame}/wiki", func() {
|
||||||
m.Combo("").
|
m.Combo("").
|
||||||
Get(repo.Wiki).
|
Get(repo.Wiki).
|
||||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
Post(context.RepoMustNotBeArchived(), reqSignIn, reqUnitWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||||
m.Combo("/*").
|
m.Combo("/*").
|
||||||
Get(repo.Wiki).
|
Get(repo.Wiki).
|
||||||
Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
Post(context.RepoMustNotBeArchived(), reqSignIn, reqUnitWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
|
||||||
m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
|
m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
|
||||||
m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
|
||||||
m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
|
m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
|
||||||
m.Get("/raw/*", repo.WikiRaw)
|
m.Get("/raw/*", repo.WikiRaw)
|
||||||
}, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqRepoWikiReader, func(ctx *context.Context) {
|
}, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) {
|
||||||
ctx.Data["PageIsWiki"] = true
|
ctx.Data["PageIsWiki"] = true
|
||||||
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink(ctx, ctx.Doer)
|
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink(ctx, ctx.Doer)
|
||||||
})
|
})
|
||||||
// end "/{username}/{reponame}/wiki"
|
// end "/{username}/{reponame}/wiki"
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}/activity", func() {
|
m.Group("/{username}/{reponame}/activity", func() {
|
||||||
|
// activity has its own permission checks
|
||||||
m.Get("", repo.Activity)
|
m.Get("", repo.Activity)
|
||||||
m.Get("/{period}", repo.Activity)
|
m.Get("/{period}", repo.Activity)
|
||||||
m.Group("/contributors", func() {
|
|
||||||
m.Get("", repo.Contributors)
|
m.Group("", func() {
|
||||||
m.Get("/data", repo.ContributorsData)
|
m.Group("/contributors", func() {
|
||||||
})
|
m.Get("", repo.Contributors)
|
||||||
m.Group("/code-frequency", func() {
|
m.Get("/data", repo.ContributorsData)
|
||||||
m.Get("", repo.CodeFrequency)
|
})
|
||||||
m.Get("/data", repo.CodeFrequencyData)
|
m.Group("/code-frequency", func() {
|
||||||
})
|
m.Get("", repo.CodeFrequency)
|
||||||
m.Group("/recent-commits", func() {
|
m.Get("/data", repo.CodeFrequencyData)
|
||||||
m.Get("", repo.RecentCommits)
|
})
|
||||||
m.Get("/data", repo.RecentCommitsData)
|
m.Group("/recent-commits", func() {
|
||||||
})
|
m.Get("", repo.RecentCommits)
|
||||||
|
m.Get("/data", repo.RecentCommitsData)
|
||||||
|
})
|
||||||
|
}, reqUnitCodeReader)
|
||||||
},
|
},
|
||||||
optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases),
|
optSignIn, context.RepoAssignment, repo.MustBeNotEmpty,
|
||||||
context.RepoRef(), repo.MustBeNotEmpty,
|
context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases),
|
||||||
)
|
)
|
||||||
// end "/{username}/{reponame}/activity"
|
// end "/{username}/{reponame}/activity"
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Group("/pulls/{index}", func() {
|
m.Get("/{type:pulls}", repo.Issues)
|
||||||
|
m.Group("/{type:pulls}/{index}", func() {
|
||||||
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
|
||||||
m.Get(".diff", repo.DownloadPullDiff)
|
m.Get(".diff", repo.DownloadPullDiff)
|
||||||
m.Get(".patch", repo.DownloadPullPatch)
|
m.Get(".patch", repo.DownloadPullPatch)
|
||||||
@ -1501,7 +1505,7 @@ func registerRoutes(m *web.Router) {
|
|||||||
}, context.RepoMustNotBeArchived())
|
}, context.RepoMustNotBeArchived())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqRepoPullsReader)
|
}, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader)
|
||||||
// end "/{username}/{reponame}/pulls/{index}": repo pull request
|
// end "/{username}/{reponame}/pulls/{index}": repo pull request
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
@ -1521,42 +1525,39 @@ func registerRoutes(m *web.Router) {
|
|||||||
}, repo.MustBeNotEmpty, context.RepoRef())
|
}, repo.MustBeNotEmpty, context.RepoRef())
|
||||||
|
|
||||||
m.Group("/media", func() {
|
m.Group("/media", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownloadOrLFS)
|
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownloadOrLFS)
|
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownloadOrLFS)
|
|
||||||
m.Get("/blob/{sha}", repo.DownloadByIDOrLFS)
|
m.Get("/blob/{sha}", repo.DownloadByIDOrLFS)
|
||||||
// "/*" route is deprecated, and kept for backward compatibility
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.SingleDownloadOrLFS)
|
||||||
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownloadOrLFS)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownloadOrLFS)
|
||||||
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownloadOrLFS)
|
||||||
|
m.Get("/*", context.RepoRefByType(""), repo.SingleDownloadOrLFS) // "/*" route is deprecated, and kept for backward compatibility
|
||||||
}, repo.MustBeNotEmpty)
|
}, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Group("/raw", func() {
|
m.Group("/raw", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload)
|
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownload)
|
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.SingleDownload)
|
|
||||||
m.Get("/blob/{sha}", repo.DownloadByID)
|
m.Get("/blob/{sha}", repo.DownloadByID)
|
||||||
// "/*" route is deprecated, and kept for backward compatibility
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.SingleDownload)
|
||||||
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.SingleDownload)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.SingleDownload)
|
||||||
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.SingleDownload)
|
||||||
|
m.Get("/*", context.RepoRefByType(""), repo.SingleDownload) // "/*" route is deprecated, and kept for backward compatibility
|
||||||
}, repo.MustBeNotEmpty)
|
}, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Group("/render", func() {
|
m.Group("/render", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile)
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RenderFile)
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RenderFile)
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile)
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RenderFile)
|
||||||
m.Get("/blob/{sha}", repo.RenderFile)
|
m.Get("/blob/{sha}", repo.RenderFile)
|
||||||
}, repo.MustBeNotEmpty)
|
}, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Group("/commits", func() {
|
m.Group("/commits", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RefCommits)
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RefCommits)
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits)
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RefCommits)
|
||||||
// "/*" route is deprecated, and kept for backward compatibility
|
m.Get("/*", context.RepoRefByType(""), repo.RefCommits) // "/*" route is deprecated, and kept for backward compatibility
|
||||||
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.RefCommits)
|
|
||||||
}, repo.MustBeNotEmpty)
|
}, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Group("/blame", func() {
|
m.Group("/blame", func() {
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefBlame)
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.RefBlame)
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefBlame)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.RefBlame)
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefBlame)
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.RefBlame)
|
||||||
}, repo.MustBeNotEmpty)
|
}, repo.MustBeNotEmpty)
|
||||||
|
|
||||||
m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
|
m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
|
||||||
@ -1568,27 +1569,27 @@ func registerRoutes(m *web.Router) {
|
|||||||
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
|
||||||
}, repo.MustBeNotEmpty, context.RepoRef())
|
}, repo.MustBeNotEmpty, context.RepoRef())
|
||||||
|
|
||||||
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
m.Get("/rss/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeed)
|
||||||
m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
|
m.Get("/atom/branch/*", context.RepoRefByType(git.RefTypeBranch), feedEnabled, feed.RenderBranchFeed)
|
||||||
|
|
||||||
m.Group("/src", func() {
|
m.Group("/src", func() {
|
||||||
m.Get("", func(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink) }) // there is no "{owner}/{repo}/src" page, so redirect to "{owner}/{repo}" to avoid 404
|
m.Get("", func(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink) }) // there is no "{owner}/{repo}/src" page, so redirect to "{owner}/{repo}" to avoid 404
|
||||||
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
|
m.Get("/branch/*", context.RepoRefByType(git.RefTypeBranch), repo.Home)
|
||||||
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home)
|
m.Get("/tag/*", context.RepoRefByType(git.RefTypeTag), repo.Home)
|
||||||
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home)
|
m.Get("/commit/*", context.RepoRefByType(git.RefTypeCommit), repo.Home)
|
||||||
m.Get("/*", context.RepoRefByType(context.RepoRefUnknown), repo.Home) // "/*" route is deprecated, and kept for backward compatibility
|
m.Get("/*", context.RepoRefByType(""), repo.Home) // "/*" route is deprecated, and kept for backward compatibility
|
||||||
}, repo.SetEditorconfigIfExists)
|
}, repo.SetEditorconfigIfExists)
|
||||||
|
|
||||||
m.Get("/forks", context.RepoRef(), repo.Forks)
|
m.Get("/forks", context.RepoRef(), repo.Forks)
|
||||||
m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff)
|
m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff)
|
||||||
m.Post("/lastcommit/*", context.RepoRefByType(context.RepoRefCommit), repo.LastCommit)
|
m.Post("/lastcommit/*", context.RepoRefByType(git.RefTypeCommit), repo.LastCommit)
|
||||||
}, optSignIn, context.RepoAssignment, reqRepoCodeReader)
|
}, optSignIn, context.RepoAssignment, reqUnitCodeReader)
|
||||||
// end "/{username}/{reponame}": repo code
|
// end "/{username}/{reponame}": repo code
|
||||||
|
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Get("/stars", repo.Stars)
|
m.Get("/stars", repo.Stars)
|
||||||
m.Get("/watchers", repo.Watchers)
|
m.Get("/watchers", repo.Watchers)
|
||||||
m.Get("/search", reqRepoCodeReader, repo.Search)
|
m.Get("/search", reqUnitCodeReader, repo.Search)
|
||||||
m.Post("/action/{action}", reqSignIn, repo.Action)
|
m.Post("/action/{action}", reqSignIn, repo.Action)
|
||||||
}, optSignIn, context.RepoAssignment, context.RepoRef())
|
}, optSignIn, context.RepoAssignment, context.RepoRef())
|
||||||
|
|
||||||
|
@ -9,31 +9,20 @@ import (
|
|||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequireRepoAdmin returns a middleware for requiring repository admin permission
|
// RequireRepoAdmin returns a middleware for requiring repository admin permission
|
||||||
func RequireRepoAdmin() func(ctx *Context) {
|
func RequireRepoAdmin() func(ctx *Context) {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
|
if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
|
||||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
ctx.NotFound("RequireRepoAdmin denies the request", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
|
// CanWriteToBranch checks if the user is allowed to write to the branch of the repo
|
||||||
func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
|
func CanWriteToBranch() func(ctx *Context) {
|
||||||
return func(ctx *Context) {
|
|
||||||
if !ctx.Repo.CanWrite(unitType) {
|
|
||||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanEnableEditor checks if the user is allowed to write to the branch of the repo
|
|
||||||
func CanEnableEditor() func(ctx *Context) {
|
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
|
if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
|
||||||
ctx.NotFound("CanWriteToBranch denies permission", nil)
|
ctx.NotFound("CanWriteToBranch denies permission", nil)
|
||||||
@ -42,75 +31,30 @@ func CanEnableEditor() func(ctx *Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
|
// RequireUnitWriter returns a middleware for requiring repository write to one of the unit permission
|
||||||
func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
|
func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
for _, unitType := range unitTypes {
|
for _, unitType := range unitTypes {
|
||||||
if ctx.Repo.CanWrite(unitType) {
|
if ctx.Repo.CanWrite(unitType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
ctx.NotFound("RequireUnitWriter denies the request", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequireRepoReader returns a middleware for requiring repository read to the specify unitType
|
// RequireUnitReader returns a middleware for requiring repository write to one of the unit permission
|
||||||
func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
|
func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) {
|
||||||
return func(ctx *Context) {
|
|
||||||
if !ctx.Repo.CanRead(unitType) {
|
|
||||||
if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if log.IsTrace() {
|
|
||||||
if ctx.IsSigned {
|
|
||||||
log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
|
|
||||||
"User in Repo has Permissions: %-+v",
|
|
||||||
ctx.Doer,
|
|
||||||
unitType,
|
|
||||||
ctx.Repo.Repository,
|
|
||||||
ctx.Repo.Permission)
|
|
||||||
} else {
|
|
||||||
log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
|
|
||||||
"Anonymous user in Repo has Permissions: %-+v",
|
|
||||||
unitType,
|
|
||||||
ctx.Repo.Repository,
|
|
||||||
ctx.Repo.Permission)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
|
|
||||||
func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
|
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
for _, unitType := range unitTypes {
|
for _, unitType := range unitTypes {
|
||||||
if ctx.Repo.CanRead(unitType) {
|
if ctx.Repo.CanRead(unitType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) {
|
||||||
if log.IsTrace() {
|
return
|
||||||
var format string
|
|
||||||
var args []any
|
|
||||||
if ctx.IsSigned {
|
|
||||||
format = "Permission Denied: User %-v cannot read ["
|
|
||||||
args = append(args, ctx.Doer)
|
|
||||||
} else {
|
|
||||||
format = "Permission Denied: Anonymous user cannot read ["
|
|
||||||
}
|
}
|
||||||
for _, unit := range unitTypes {
|
|
||||||
format += "%-v, "
|
|
||||||
args = append(args, unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
format = format[:len(format)-2] + "] in Repo %-v\n" +
|
|
||||||
"User in Repo has Permissions: %-+v"
|
|
||||||
args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
|
|
||||||
log.Trace(format, args...)
|
|
||||||
}
|
}
|
||||||
ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
|
ctx.NotFound("RequireUnitReader denies the request", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,24 +677,12 @@ func RepoAssignment(ctx *Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoRefType type of repo reference
|
|
||||||
type RepoRefType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RepoRefUnknown is for legacy support, makes the code to "guess" the ref type
|
|
||||||
RepoRefUnknown RepoRefType = iota
|
|
||||||
RepoRefBranch
|
|
||||||
RepoRefTag
|
|
||||||
RepoRefCommit
|
|
||||||
)
|
|
||||||
|
|
||||||
const headRefName = "HEAD"
|
const headRefName = "HEAD"
|
||||||
|
|
||||||
// RepoRef handles repository reference names when the ref name is not
|
|
||||||
// explicitly given
|
|
||||||
func RepoRef() func(*Context) {
|
func RepoRef() func(*Context) {
|
||||||
// since no ref name is explicitly specified, ok to just use branch
|
// old code does: return RepoRefByType(git.RefTypeBranch)
|
||||||
return RepoRefByType(RepoRefBranch)
|
// in most cases, it is an abuse, so we just disable it completely and fix the abuses one by one (if there is anything wrong)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string {
|
func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string {
|
||||||
@ -710,29 +698,29 @@ func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRefNameLegacy(ctx *Base, repo *Repository, reqPath, extraRef string) (string, RepoRefType) {
|
func getRefNameLegacy(ctx *Base, repo *Repository, reqPath, extraRef string) (string, git.RefType) {
|
||||||
reqRefPath := path.Join(extraRef, reqPath)
|
reqRefPath := path.Join(extraRef, reqPath)
|
||||||
reqRefPathParts := strings.Split(reqRefPath, "/")
|
reqRefPathParts := strings.Split(reqRefPath, "/")
|
||||||
if refName := getRefName(ctx, repo, reqRefPath, RepoRefBranch); refName != "" {
|
if refName := getRefName(ctx, repo, reqRefPath, git.RefTypeBranch); refName != "" {
|
||||||
return refName, RepoRefBranch
|
return refName, git.RefTypeBranch
|
||||||
}
|
}
|
||||||
if refName := getRefName(ctx, repo, reqRefPath, RepoRefTag); refName != "" {
|
if refName := getRefName(ctx, repo, reqRefPath, git.RefTypeTag); refName != "" {
|
||||||
return refName, RepoRefTag
|
return refName, git.RefTypeTag
|
||||||
}
|
}
|
||||||
if git.IsStringLikelyCommitID(git.ObjectFormatFromName(repo.Repository.ObjectFormatName), reqRefPathParts[0]) {
|
if git.IsStringLikelyCommitID(git.ObjectFormatFromName(repo.Repository.ObjectFormatName), reqRefPathParts[0]) {
|
||||||
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
|
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
|
||||||
repo.TreePath = strings.Join(reqRefPathParts[1:], "/")
|
repo.TreePath = strings.Join(reqRefPathParts[1:], "/")
|
||||||
return reqRefPathParts[0], RepoRefCommit
|
return reqRefPathParts[0], git.RefTypeCommit
|
||||||
}
|
}
|
||||||
// FIXME: the old code falls back to default branch if "ref" doesn't exist, there could be an edge case:
|
// FIXME: the old code falls back to default branch if "ref" doesn't exist, there could be an edge case:
|
||||||
// "README?ref=no-such" would read the README file from the default branch, but the user might expect a 404
|
// "README?ref=no-such" would read the README file from the default branch, but the user might expect a 404
|
||||||
repo.TreePath = reqPath
|
repo.TreePath = reqPath
|
||||||
return repo.Repository.DefaultBranch, RepoRefBranch
|
return repo.Repository.DefaultBranch, git.RefTypeBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType) string {
|
func getRefName(ctx *Base, repo *Repository, path string, refType git.RefType) string {
|
||||||
switch pathType {
|
switch refType {
|
||||||
case RepoRefBranch:
|
case git.RefTypeBranch:
|
||||||
ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist)
|
ref := getRefNameFromPath(repo, path, repo.GitRepo.IsBranchExist)
|
||||||
if len(ref) == 0 {
|
if len(ref) == 0 {
|
||||||
// check if ref is HEAD
|
// check if ref is HEAD
|
||||||
@ -762,9 +750,9 @@ func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ref
|
return ref
|
||||||
case RepoRefTag:
|
case git.RefTypeTag:
|
||||||
return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist)
|
return getRefNameFromPath(repo, path, repo.GitRepo.IsTagExist)
|
||||||
case RepoRefCommit:
|
case git.RefTypeCommit:
|
||||||
parts := strings.Split(path, "/")
|
parts := strings.Split(path, "/")
|
||||||
if git.IsStringLikelyCommitID(repo.GetObjectFormat(), parts[0], 7) {
|
if git.IsStringLikelyCommitID(repo.GetObjectFormat(), parts[0], 7) {
|
||||||
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
|
// FIXME: this logic is different from other types. Ideally, it should also try to GetCommit to check if it exists
|
||||||
@ -782,22 +770,18 @@ func getRefName(ctx *Base, repo *Repository, path string, pathType RepoRefType)
|
|||||||
return commit.ID.String()
|
return commit.ID.String()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unrecognized path type: %v", pathType))
|
panic(fmt.Sprintf("Unrecognized ref type: %v", refType))
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepoRefByTypeOptions struct {
|
func repoRefFullName(typ git.RefType, shortName string) git.RefName {
|
||||||
IgnoreNotExistErr bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func repoRefFullName(shortName string, typ RepoRefType) git.RefName {
|
|
||||||
switch typ {
|
switch typ {
|
||||||
case RepoRefBranch:
|
case git.RefTypeBranch:
|
||||||
return git.RefNameFromBranch(shortName)
|
return git.RefNameFromBranch(shortName)
|
||||||
case RepoRefTag:
|
case git.RefTypeTag:
|
||||||
return git.RefNameFromTag(shortName)
|
return git.RefNameFromTag(shortName)
|
||||||
case RepoRefCommit:
|
case git.RefTypeCommit:
|
||||||
return git.RefNameFromCommit(shortName)
|
return git.RefNameFromCommit(shortName)
|
||||||
default:
|
default:
|
||||||
setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ)
|
setting.PanicInDevOrTesting("Unknown RepoRefType: %v", typ)
|
||||||
@ -807,8 +791,7 @@ func repoRefFullName(shortName string, typ RepoRefType) git.RefName {
|
|||||||
|
|
||||||
// RepoRefByType handles repository reference name for a specific type
|
// RepoRefByType handles repository reference name for a specific type
|
||||||
// of repository reference
|
// of repository reference
|
||||||
func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func(*Context) {
|
func RepoRefByType(detectRefType git.RefType) func(*Context) {
|
||||||
opt := util.OptionalArg(opts)
|
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
var err error
|
var err error
|
||||||
refType := detectRefType
|
refType := detectRefType
|
||||||
@ -824,14 +807,6 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Repo.GitRepo == nil {
|
|
||||||
ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, ctx.Repo.Repository)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError(fmt.Sprintf("Open Repository %v failed", ctx.Repo.Repository.FullName()), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get default branch.
|
// Get default branch.
|
||||||
var refShortName string
|
var refShortName string
|
||||||
reqPath := ctx.PathParam("*")
|
reqPath := ctx.PathParam("*")
|
||||||
@ -861,13 +836,13 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
|||||||
}
|
}
|
||||||
ctx.Repo.IsViewBranch = true
|
ctx.Repo.IsViewBranch = true
|
||||||
} else { // there is a path in request
|
} else { // there is a path in request
|
||||||
guessLegacyPath := refType == RepoRefUnknown
|
guessLegacyPath := refType == ""
|
||||||
if guessLegacyPath {
|
if guessLegacyPath {
|
||||||
refShortName, refType = getRefNameLegacy(ctx.Base, ctx.Repo, reqPath, "")
|
refShortName, refType = getRefNameLegacy(ctx.Base, ctx.Repo, reqPath, "")
|
||||||
} else {
|
} else {
|
||||||
refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType)
|
refShortName = getRefName(ctx.Base, ctx.Repo, reqPath, refType)
|
||||||
}
|
}
|
||||||
ctx.Repo.RefFullName = repoRefFullName(refShortName, refType)
|
ctx.Repo.RefFullName = repoRefFullName(refType, refShortName)
|
||||||
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
|
isRenamedBranch, has := ctx.Data["IsRenamedBranch"].(bool)
|
||||||
if isRenamedBranch && has {
|
if isRenamedBranch && has {
|
||||||
renamedBranchName := ctx.Data["RenamedBranchName"].(string)
|
renamedBranchName := ctx.Data["RenamedBranchName"].(string)
|
||||||
@ -877,7 +852,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if refType == RepoRefBranch && ctx.Repo.GitRepo.IsBranchExist(refShortName) {
|
if refType == git.RefTypeBranch && ctx.Repo.GitRepo.IsBranchExist(refShortName) {
|
||||||
ctx.Repo.IsViewBranch = true
|
ctx.Repo.IsViewBranch = true
|
||||||
ctx.Repo.BranchName = refShortName
|
ctx.Repo.BranchName = refShortName
|
||||||
ctx.Repo.RefFullName = git.RefNameFromBranch(refShortName)
|
ctx.Repo.RefFullName = git.RefNameFromBranch(refShortName)
|
||||||
@ -888,7 +863,7 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||||
} else if refType == RepoRefTag && ctx.Repo.GitRepo.IsTagExist(refShortName) {
|
} else if refType == git.RefTypeTag && ctx.Repo.GitRepo.IsTagExist(refShortName) {
|
||||||
ctx.Repo.IsViewTag = true
|
ctx.Repo.IsViewTag = true
|
||||||
ctx.Repo.RefFullName = git.RefNameFromTag(refShortName)
|
ctx.Repo.RefFullName = git.RefNameFromTag(refShortName)
|
||||||
ctx.Repo.TagName = refShortName
|
ctx.Repo.TagName = refShortName
|
||||||
@ -919,9 +894,6 @@ func RepoRefByType(detectRefType RepoRefType, opts ...RepoRefByTypeOptions) func
|
|||||||
ctx.RespHeader().Set("Link", fmt.Sprintf(`<%s>; rel="canonical"`, canonicalURL))
|
ctx.RespHeader().Set("Link", fmt.Sprintf(`<%s>; rel="canonical"`, canonicalURL))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if opt.IgnoreNotExistErr {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refShortName))
|
ctx.NotFound("RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refShortName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -110,41 +110,51 @@ type RepoSettingForm struct {
|
|||||||
EnablePrune bool
|
EnablePrune bool
|
||||||
|
|
||||||
// Advanced settings
|
// Advanced settings
|
||||||
EnableCode bool
|
EnableCode bool
|
||||||
EnableWiki bool
|
DefaultCodeEveryoneAccess string
|
||||||
EnableExternalWiki bool
|
|
||||||
DefaultWikiBranch string
|
EnableWiki bool
|
||||||
DefaultWikiEveryoneAccess string
|
EnableExternalWiki bool
|
||||||
ExternalWikiURL string
|
DefaultWikiBranch string
|
||||||
|
DefaultWikiEveryoneAccess string
|
||||||
|
ExternalWikiURL string
|
||||||
|
|
||||||
EnableIssues bool
|
EnableIssues bool
|
||||||
|
DefaultIssuesEveryoneAccess string
|
||||||
EnableExternalTracker bool
|
EnableExternalTracker bool
|
||||||
ExternalTrackerURL string
|
ExternalTrackerURL string
|
||||||
TrackerURLFormat string
|
TrackerURLFormat string
|
||||||
TrackerIssueStyle string
|
TrackerIssueStyle string
|
||||||
ExternalTrackerRegexpPattern string
|
ExternalTrackerRegexpPattern string
|
||||||
EnableCloseIssuesViaCommitInAnyBranch bool
|
EnableCloseIssuesViaCommitInAnyBranch bool
|
||||||
EnableProjects bool
|
|
||||||
ProjectsMode string
|
EnableProjects bool
|
||||||
EnableReleases bool
|
ProjectsMode string
|
||||||
EnablePackages bool
|
|
||||||
EnablePulls bool
|
EnableReleases bool
|
||||||
EnableActions bool
|
|
||||||
PullsIgnoreWhitespace bool
|
EnablePackages bool
|
||||||
PullsAllowMerge bool
|
|
||||||
PullsAllowRebase bool
|
EnablePulls bool
|
||||||
PullsAllowRebaseMerge bool
|
PullsIgnoreWhitespace bool
|
||||||
PullsAllowSquash bool
|
PullsAllowMerge bool
|
||||||
PullsAllowFastForwardOnly bool
|
PullsAllowRebase bool
|
||||||
PullsAllowManualMerge bool
|
PullsAllowRebaseMerge bool
|
||||||
PullsDefaultMergeStyle string
|
PullsAllowSquash bool
|
||||||
EnableAutodetectManualMerge bool
|
PullsAllowFastForwardOnly bool
|
||||||
PullsAllowRebaseUpdate bool
|
PullsAllowManualMerge bool
|
||||||
DefaultDeleteBranchAfterMerge bool
|
PullsDefaultMergeStyle string
|
||||||
DefaultAllowMaintainerEdit bool
|
EnableAutodetectManualMerge bool
|
||||||
EnableTimetracker bool
|
PullsAllowRebaseUpdate bool
|
||||||
AllowOnlyContributorsToTrackTime bool
|
DefaultDeleteBranchAfterMerge bool
|
||||||
EnableIssueDependencies bool
|
DefaultAllowMaintainerEdit bool
|
||||||
IsArchived bool
|
EnableTimetracker bool
|
||||||
|
AllowOnlyContributorsToTrackTime bool
|
||||||
|
EnableIssueDependencies bool
|
||||||
|
|
||||||
|
EnableActions bool
|
||||||
|
|
||||||
|
IsArchived bool
|
||||||
|
|
||||||
// Signing Settings
|
// Signing Settings
|
||||||
TrustModel string
|
TrustModel string
|
||||||
@ -651,8 +661,8 @@ type NewReleaseForm struct {
|
|||||||
Target string `form:"tag_target" binding:"Required;MaxSize(255)"`
|
Target string `form:"tag_target" binding:"Required;MaxSize(255)"`
|
||||||
Title string `binding:"MaxSize(255)"`
|
Title string `binding:"MaxSize(255)"`
|
||||||
Content string
|
Content string
|
||||||
Draft string
|
Draft bool
|
||||||
TagOnly string
|
TagOnly bool
|
||||||
Prerelease bool
|
Prerelease bool
|
||||||
AddTagMsg bool
|
AddTagMsg bool
|
||||||
Files []string
|
Files []string
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{template "base/disable_form_autofill"}}
|
{{template "base/disable_form_autofill"}}
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{template "base/disable_form_autofill"}}
|
{{template "base/disable_form_autofill"}}
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{template "base/disable_form_autofill"}}
|
{{template "base/disable_form_autofill"}}
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{template "base/disable_form_autofill"}}
|
{{template "base/disable_form_autofill"}}
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -3,13 +3,15 @@
|
|||||||
<div class="ui container medium-width">
|
<div class="ui container medium-width">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
{{ctx.Locale.Tr "repo.migrate.migrate" .service.Title}}
|
||||||
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
{{template "base/alert" .}}
|
{{template "base/alert" .}}
|
||||||
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
<form class="ui form left-right-form" action="{{.Link}}" method="post">
|
||||||
{{template "base/disable_form_autofill"}}
|
{{template "base/disable_form_autofill"}}
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
|
|
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}">
|
||||||
|
|
||||||
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}">
|
||||||
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
<label for="clone_addr">{{ctx.Locale.Tr "repo.migrate.clone_address"}}</label>
|
||||||
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required>
|
||||||
|
@ -109,23 +109,17 @@
|
|||||||
{{ctx.Locale.Tr "repo.release.delete_release"}}
|
{{ctx.Locale.Tr "repo.release.delete_release"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .IsDraft}}
|
{{if .IsDraft}}
|
||||||
<button class="ui small button" type="submit" name="draft" value="{{ctx.Locale.Tr "repo.release.save_draft"}}">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
|
<button class="ui small button" type="submit" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
|
||||||
<button class="ui small primary button">
|
<button class="ui small primary button">{{ctx.Locale.Tr "repo.release.publish"}}</button>
|
||||||
{{ctx.Locale.Tr "repo.release.publish"}}
|
|
||||||
</button>
|
|
||||||
{{else}}
|
{{else}}
|
||||||
<button class="ui small primary button">
|
<button class="ui small primary button">{{ctx.Locale.Tr "repo.release.edit_release"}}</button>
|
||||||
{{ctx.Locale.Tr "repo.release.edit_release"}}
|
|
||||||
</button>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if not .tag_name}}
|
{{if .ShowCreateTagOnlyButton}}
|
||||||
<button class="ui small button" name="tag_only" value="1">{{ctx.Locale.Tr "repo.release.add_tag"}}</button>
|
<button class="ui small button" name="tag_only" value="1">{{ctx.Locale.Tr "repo.release.add_tag"}}</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
<button class="ui small button" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
|
<button class="ui small button" name="draft" value="1">{{ctx.Locale.Tr "repo.release.save_draft"}}</button>
|
||||||
<button class="ui small primary button">
|
<button class="ui small primary button">{{ctx.Locale.Tr "repo.release.publish"}}</button>
|
||||||
{{ctx.Locale.Tr "repo.release.publish"}}
|
|
||||||
</button>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -302,6 +302,15 @@
|
|||||||
<input class="enable-system" name="enable_code" type="checkbox"{{if $isCodeEnabled}} checked{{end}}>
|
<input class="enable-system" name="enable_code" type="checkbox"{{if $isCodeEnabled}} checked{{end}}>
|
||||||
<label>{{ctx.Locale.Tr "repo.code.desc"}}</label>
|
<label>{{ctx.Locale.Tr "repo.code.desc"}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline field tw-pl-4">
|
||||||
|
{{$unitCode := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeCode}}
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
|
||||||
|
<select name="default_code_everyone_access" class="ui selection dropdown">
|
||||||
|
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
|
||||||
|
<option value="none" {{Iif (eq $unitCode.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
|
||||||
|
<option value="read" {{Iif (eq $unitCode.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{$isInternalWikiEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}}
|
{{$isInternalWikiEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}}
|
||||||
@ -331,7 +340,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
{{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}}
|
{{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}}
|
||||||
<label>{{ctx.Locale.Tr "repo.settings.default_wiki_everyone_access"}}</label>
|
<label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
|
||||||
<select name="default_wiki_everyone_access" class="ui selection dropdown">
|
<select name="default_wiki_everyone_access" class="ui selection dropdown">
|
||||||
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
|
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
|
||||||
<option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
|
<option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
|
||||||
@ -374,6 +383,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field tw-pl-4 {{if (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
|
<div class="field tw-pl-4 {{if (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
|
||||||
|
<div class="inline field">
|
||||||
|
{{$unitIssue := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeIssues}}
|
||||||
|
<label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
|
||||||
|
<select name="default_issues_everyone_access" class="ui selection dropdown">
|
||||||
|
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
|
||||||
|
<option value="none" {{Iif (eq $unitIssue.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
|
||||||
|
<option value="read" {{Iif (eq $unitIssue.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
{{if .Repository.CanEnableTimetracker}}
|
{{if .Repository.CanEnableTimetracker}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
|
12
templates/swagger/v1_json.tmpl
generated
12
templates/swagger/v1_json.tmpl
generated
@ -234,6 +234,18 @@
|
|||||||
"description": "page size of results",
|
"description": "page size of results",
|
||||||
"name": "limit",
|
"name": "limit",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"system",
|
||||||
|
"default",
|
||||||
|
"all"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"default": "system",
|
||||||
|
"description": "system, default or both kinds of webhooks",
|
||||||
|
"name": "type",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -24,6 +25,7 @@ import (
|
|||||||
"code.gitea.io/gitea/tests"
|
"code.gitea.io/gitea/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder {
|
func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder {
|
||||||
@ -82,6 +84,29 @@ func TestEmptyRepoAddFile(t *testing.T) {
|
|||||||
req = NewRequest(t, "GET", redirect)
|
req = NewRequest(t, "GET", redirect)
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
assert.Contains(t, resp.Body.String(), "newly-added-test-file")
|
assert.Contains(t, resp.Body.String(), "newly-added-test-file")
|
||||||
|
|
||||||
|
// the repo is not empty anymore
|
||||||
|
req = NewRequest(t, "GET", "/user30/empty")
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
assert.Contains(t, resp.Body.String(), "test-file.md")
|
||||||
|
|
||||||
|
// if the repo is in incorrect state, it should be able to self-heal (recover to correct state)
|
||||||
|
user30EmptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 30, Name: "empty"})
|
||||||
|
user30EmptyRepo.IsEmpty = true
|
||||||
|
user30EmptyRepo.DefaultBranch = "no-such"
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).ID(user30EmptyRepo.ID).Cols("is_empty", "default_branch").Update(user30EmptyRepo)
|
||||||
|
require.NoError(t, err)
|
||||||
|
user30EmptyRepo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 30, Name: "empty"})
|
||||||
|
assert.True(t, user30EmptyRepo.IsEmpty)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/user30/empty")
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
redirect = test.RedirectURL(resp)
|
||||||
|
assert.Equal(t, "/user30/empty", redirect)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/user30/empty")
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
assert.Contains(t, resp.Body.String(), "test-file.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyRepoUploadFile(t *testing.T) {
|
func TestEmptyRepoUploadFile(t *testing.T) {
|
||||||
|
@ -79,8 +79,12 @@ func TestMigrateGiteaForm(t *testing.T) {
|
|||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
// Step 2: load the form
|
// Step 2: load the form
|
||||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||||
link, exists := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`).Attr("action")
|
form := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`)
|
||||||
|
link, exists := form.Attr("action")
|
||||||
assert.True(t, exists, "The template has changed")
|
assert.True(t, exists, "The template has changed")
|
||||||
|
serviceInput, exists := form.Find(`input[name="service"]`).Attr("value")
|
||||||
|
assert.True(t, exists)
|
||||||
|
assert.EqualValues(t, fmt.Sprintf("%d", structs.GiteaService), serviceInput)
|
||||||
// Step 4: submit the migration to only migrate issues
|
// Step 4: submit the migration to only migrate issues
|
||||||
migratedRepoName := "otherrepo"
|
migratedRepoName := "otherrepo"
|
||||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||||
|
@ -39,7 +39,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st
|
|||||||
postData["prerelease"] = "on"
|
postData["prerelease"] = "on"
|
||||||
}
|
}
|
||||||
if draft {
|
if draft {
|
||||||
postData["draft"] = "Save Draft"
|
postData["draft"] = "1"
|
||||||
}
|
}
|
||||||
req = NewRequestWithValues(t, "POST", link, postData)
|
req = NewRequestWithValues(t, "POST", link, postData)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user