mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-18 08:20:31 +02:00
Compare commits
23 Commits
v1.8.1
...
release/v1
Author | SHA1 | Date | |
---|---|---|---|
|
11f6ed4f83 | ||
|
e94a84248d | ||
|
cf7a5b3d91 | ||
|
5d1a8d23b0 | ||
|
dbd0a2e6dc | ||
|
7697a282d6 | ||
|
76e8eec3d9 | ||
|
10effb396a | ||
|
5e97b2d00e | ||
|
873acd884d | ||
|
dc73b2748d | ||
|
31ad8b7026 | ||
|
d07edc5336 | ||
|
63cb160cb1 | ||
|
8d5c3d3d0b | ||
|
706d85b87d | ||
|
75e491c03e | ||
|
608f46e59c | ||
|
895764e7f5 | ||
|
21983965d0 | ||
|
e069a75817 | ||
|
ebb8fa610c | ||
|
c8fc7fce4a |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -4,6 +4,31 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17
|
||||
* BUGFIXES
|
||||
* Always set userID on LFS authentication (#7224) (Part of #6993)
|
||||
* Fix LFS Locks over SSH (#6999) (#7223)
|
||||
* Fix duplicated file on pull request conflicted files (#7211) (#7214)
|
||||
* Detect noreply email address as user (#7133) (#7195)
|
||||
* Don't get milestone from DB if ID is zero (#7169) (#7174)
|
||||
* Allow archived repos to be (un)starred and (un)watched (#7163) (#7168)
|
||||
* Fix GCArgs load from ini (#7156) (#7157)
|
||||
|
||||
## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29
|
||||
* BUGFIXES
|
||||
* Fix possbile mysql invalid connnection error (#7051) (#7071)
|
||||
* Handle invalid administrator username on install page (#7060) (#7063)
|
||||
* Disable arm7 builds (#7037) (#7042)
|
||||
* Fix default for allowing new organization creation for new users (#7017) (#7034)
|
||||
* SearchRepositoryByName improvements and unification (#6897) (#7002)
|
||||
* Fix u2f registrationlist ToRegistrations() method (#6980) (#6982)
|
||||
* Allow collaborators to view repo owned by private org (#6965) (#6968)
|
||||
* Use AppURL for Oauth user link (#6894) (#6925)
|
||||
* Escape the commit message on issues update (#6901) (#6902)
|
||||
* Fix regression for API users search (#6882) (#6885)
|
||||
* Handle early git version's lack of get-url (#7065) (#7076)
|
||||
* Fix wrong init dependency on markup extensions (#7038) (#7074)
|
||||
|
||||
## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08
|
||||
* BUGFIXES
|
||||
* Fix 404 when sending pull requests in some situations (#6871) (#6873)
|
||||
|
2
Makefile
2
Makefile
@@ -336,7 +336,7 @@ release-linux:
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u src.techknowlogick.com/xgo; \
|
||||
fi
|
||||
xgo -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out gitea-$(VERSION) .
|
||||
xgo -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
|
130
cmd/serv.go
130
cmd/serv.go
@@ -217,75 +217,77 @@ func runServ(c *cli.Context) error {
|
||||
|
||||
// Allow anonymous clone for public repositories.
|
||||
var (
|
||||
keyID int64
|
||||
user *models.User
|
||||
keyID int64
|
||||
user *models.User
|
||||
userID int64
|
||||
)
|
||||
if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
|
||||
keys := strings.Split(c.Args()[0], "-")
|
||||
if len(keys) != 2 {
|
||||
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
||||
}
|
||||
|
||||
key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
|
||||
keys := strings.Split(c.Args()[0], "-")
|
||||
if len(keys) != 2 {
|
||||
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
|
||||
}
|
||||
|
||||
key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
|
||||
if err != nil {
|
||||
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
|
||||
}
|
||||
keyID = key.ID
|
||||
userID = key.OwnerID
|
||||
|
||||
if key.Type == models.KeyTypeDeploy {
|
||||
// Now we have to get the deploy key for this repo
|
||||
deployKey, err := private.GetDeployKey(key.ID, repo.ID)
|
||||
if err != nil {
|
||||
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
|
||||
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
keyID = key.ID
|
||||
|
||||
if deployKey == nil {
|
||||
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
if deployKey.Mode < requestedMode {
|
||||
fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
// Update deploy key activity.
|
||||
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
|
||||
fail("Internal error", "UpdateDeployKey: %v", err)
|
||||
}
|
||||
|
||||
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
|
||||
// however we don't have good way of representing deploy keys in hook.go
|
||||
// so for now use the owner
|
||||
os.Setenv(models.EnvPusherName, username)
|
||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
|
||||
userID = repo.OwnerID
|
||||
} else if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
|
||||
// Check deploy key or user key.
|
||||
if key.Type == models.KeyTypeDeploy {
|
||||
// Now we have to get the deploy key for this repo
|
||||
deployKey, err := private.GetDeployKey(key.ID, repo.ID)
|
||||
if err != nil {
|
||||
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
if deployKey == nil {
|
||||
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
if deployKey.Mode < requestedMode {
|
||||
fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID)
|
||||
}
|
||||
|
||||
// Update deploy key activity.
|
||||
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
|
||||
fail("Internal error", "UpdateDeployKey: %v", err)
|
||||
}
|
||||
|
||||
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
|
||||
// however we don't have good way of representing deploy keys in hook.go
|
||||
// so for now use the owner
|
||||
os.Setenv(models.EnvPusherName, username)
|
||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
|
||||
} else {
|
||||
user, err = private.GetUserByKeyID(key.ID)
|
||||
if err != nil {
|
||||
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
|
||||
}
|
||||
|
||||
if !user.IsActive || user.ProhibitLogin {
|
||||
fail("Your account is not active or has been disabled by Administrator",
|
||||
"User %s is disabled and have no access to repository %s",
|
||||
user.Name, repoPath)
|
||||
}
|
||||
|
||||
mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType)
|
||||
if err != nil {
|
||||
fail("Internal error", "Failed to check access: %v", err)
|
||||
} else if *mode < requestedMode {
|
||||
clientMessage := accessDenied
|
||||
if *mode >= models.AccessModeRead {
|
||||
clientMessage = "You do not have sufficient authorization for this action"
|
||||
}
|
||||
fail(clientMessage,
|
||||
"User %s does not have level %v access to repository %s's "+unitName,
|
||||
user.Name, requestedMode, repoPath)
|
||||
}
|
||||
|
||||
os.Setenv(models.EnvPusherName, user.Name)
|
||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
|
||||
user, err = private.GetUserByKeyID(key.ID)
|
||||
if err != nil {
|
||||
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
|
||||
}
|
||||
|
||||
if !user.IsActive || user.ProhibitLogin {
|
||||
fail("Your account is not active or has been disabled by Administrator",
|
||||
"User %s is disabled and have no access to repository %s",
|
||||
user.Name, repoPath)
|
||||
}
|
||||
|
||||
mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType)
|
||||
if err != nil {
|
||||
fail("Internal error", "Failed to check access: %v", err)
|
||||
} else if *mode < requestedMode {
|
||||
clientMessage := accessDenied
|
||||
if *mode >= models.AccessModeRead {
|
||||
clientMessage = "You do not have sufficient authorization for this action"
|
||||
}
|
||||
fail(clientMessage,
|
||||
"User %s does not have level %v access to repository %s's "+unitName,
|
||||
user.Name, requestedMode, repoPath)
|
||||
}
|
||||
|
||||
os.Setenv(models.EnvPusherName, user.Name)
|
||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
|
||||
}
|
||||
|
||||
//LFS token authentication
|
||||
@@ -299,8 +301,8 @@ func runServ(c *cli.Context) error {
|
||||
"exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
|
||||
"nbf": now.Unix(),
|
||||
}
|
||||
if user != nil {
|
||||
claims["user"] = user.ID
|
||||
if userID > 0 {
|
||||
claims["user"] = userID
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
|
@@ -15,7 +15,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup/external"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/routers/routes"
|
||||
@@ -120,8 +119,6 @@ func runWeb(ctx *cli.Context) error {
|
||||
|
||||
routers.GlobalInit()
|
||||
|
||||
external.RegisterParsers()
|
||||
|
||||
m := routes.NewMacaron()
|
||||
routes.RegisterRoutes(m)
|
||||
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/external"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/routers/routes"
|
||||
@@ -113,6 +114,7 @@ func runPR() {
|
||||
log.Printf("[PR] Setting up router\n")
|
||||
//routers.GlobalInit()
|
||||
external.RegisterParsers()
|
||||
markup.Init()
|
||||
m := routes.NewMacaron()
|
||||
routes.RegisterRoutes(m)
|
||||
|
||||
|
@@ -129,3 +129,18 @@ func TestAPIListUsers(t *testing.T) {
|
||||
numberOfUsers := models.GetCount(t, &models.User{}, "type = 0")
|
||||
assert.Equal(t, numberOfUsers, len(users))
|
||||
}
|
||||
|
||||
func TestAPIListUsersNotLoggedIn(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
req := NewRequest(t, "GET", "/api/v1/admin/users")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
func TestAPIListUsersNonAdmin(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
nonAdminUsername := "user2"
|
||||
session := loginUser(t, nonAdminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/admin/users?token=%s", token)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
@@ -69,40 +69,41 @@ func TestAPISearchRepo(t *testing.T) {
|
||||
name, requestURL string
|
||||
expectedResults
|
||||
}{
|
||||
{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
|
||||
{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 19},
|
||||
user: {count: 19},
|
||||
user2: {count: 19}},
|
||||
},
|
||||
{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
|
||||
{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
},
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default&private=false", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
},
|
||||
{name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s", "big_test_"), expectedResults: expectedResults{
|
||||
{name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "big_test_"), expectedResults: expectedResults{
|
||||
nil: {count: 7, repoName: "big_test_"},
|
||||
user: {count: 7, repoName: "big_test_"},
|
||||
user2: {count: 7, repoName: "big_test_"}},
|
||||
},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{
|
||||
nil: {count: 4},
|
||||
user: {count: 8, includesPrivate: true},
|
||||
user2: {count: 4}},
|
||||
nil: {count: 5},
|
||||
user: {count: 9, includesPrivate: true},
|
||||
user2: {count: 5, includesPrivate: true}},
|
||||
},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
user2: {count: 2, includesPrivate: true}},
|
||||
user: {count: 2, includesPrivate: true},
|
||||
user2: {count: 2, includesPrivate: true},
|
||||
user4: {count: 1}},
|
||||
},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
user2: {count: 1},
|
||||
user: {count: 4, includesPrivate: true},
|
||||
user2: {count: 2, includesPrivate: true},
|
||||
user3: {count: 4, includesPrivate: true}},
|
||||
},
|
||||
{name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{
|
||||
@@ -112,12 +113,12 @@ func TestAPISearchRepo(t *testing.T) {
|
||||
},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{
|
||||
nil: {count: 3},
|
||||
user: {count: 3},
|
||||
user4: {count: 6, includesPrivate: true}}},
|
||||
user: {count: 4, includesPrivate: true},
|
||||
user4: {count: 7, includesPrivate: true}}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{
|
||||
nil: {count: 0},
|
||||
user: {count: 0},
|
||||
user4: {count: 0, includesPrivate: true}}},
|
||||
user: {count: 1, includesPrivate: true},
|
||||
user4: {count: 1, includesPrivate: true}}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{
|
||||
nil: {count: 1},
|
||||
user: {count: 1},
|
||||
@@ -136,8 +137,8 @@ func TestAPISearchRepo(t *testing.T) {
|
||||
user4: {count: 2, includesPrivate: true}}},
|
||||
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{
|
||||
nil: {count: 0},
|
||||
user: {count: 0},
|
||||
user4: {count: 0, includesPrivate: true}}},
|
||||
user: {count: 1, includesPrivate: true},
|
||||
user4: {count: 1, includesPrivate: true}}},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
@@ -164,14 +165,19 @@ func TestAPISearchRepo(t *testing.T) {
|
||||
var body api.SearchResults
|
||||
DecodeJSON(t, response, &body)
|
||||
|
||||
assert.Len(t, body.Data, expected.count)
|
||||
repoNames := make([]string, 0, len(body.Data))
|
||||
for _, repo := range body.Data {
|
||||
repoNames = append(repoNames, fmt.Sprintf("%d:%s:%t", repo.ID, repo.FullName, repo.Private))
|
||||
}
|
||||
assert.Len(t, repoNames, expected.count)
|
||||
for _, repo := range body.Data {
|
||||
r := getRepo(t, repo.ID)
|
||||
hasAccess, err := models.HasAccess(userID, r)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, hasAccess)
|
||||
assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err)
|
||||
assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName)
|
||||
|
||||
assert.NotEmpty(t, repo.Name)
|
||||
assert.Equal(t, repo.Name, r.Name)
|
||||
|
||||
if len(expected.repoName) > 0 {
|
||||
assert.Contains(t, repo.Name, expected.repoName)
|
||||
@@ -182,7 +188,7 @@ func TestAPISearchRepo(t *testing.T) {
|
||||
}
|
||||
|
||||
if !expected.includesPrivate {
|
||||
assert.False(t, repo.Private)
|
||||
assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
52
integrations/api_user_search_test.go
Normal file
52
integrations/api_user_search_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.package models
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type SearchResults struct {
|
||||
OK bool `json:"ok"`
|
||||
Data []*api.User `json:"data"`
|
||||
}
|
||||
|
||||
func TestAPIUserSearchLoggedIn(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
adminUsername := "user1"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
query := "user2"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?token=%s&q=%s", token, query)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
assert.NotEmpty(t, user.Email)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIUserSearchNotLoggedIn(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
query := "user2"
|
||||
req := NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
assert.Empty(t, user.Email)
|
||||
}
|
||||
}
|
@@ -61,6 +61,10 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
little = commitAndPush(t, littleSize, dstPath)
|
||||
})
|
||||
t.Run("Big", func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
return
|
||||
}
|
||||
big = commitAndPush(t, bigSize, dstPath)
|
||||
})
|
||||
})
|
||||
@@ -77,9 +81,15 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
|
||||
t.Run("Little", func(t *testing.T) {
|
||||
littleLFS = commitAndPush(t, littleSize, dstPath)
|
||||
lockFileTest(t, littleLFS, dstPath)
|
||||
})
|
||||
t.Run("Big", func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
return
|
||||
}
|
||||
bigLFS = commitAndPush(t, bigSize, dstPath)
|
||||
lockFileTest(t, bigLFS, dstPath)
|
||||
})
|
||||
})
|
||||
t.Run("Locks", func(t *testing.T) {
|
||||
@@ -94,19 +104,21 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", big))
|
||||
nilResp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, nilResp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", littleLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, littleSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", big))
|
||||
nilResp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, nilResp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
}
|
||||
|
||||
})
|
||||
t.Run("Media", func(t *testing.T) {
|
||||
@@ -117,17 +129,19 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", big))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", littleLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", big))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Length)
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
@@ -160,6 +174,10 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
little = commitAndPush(t, littleSize, dstPath)
|
||||
})
|
||||
t.Run("Big", func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
return
|
||||
}
|
||||
big = commitAndPush(t, bigSize, dstPath)
|
||||
})
|
||||
})
|
||||
@@ -176,9 +194,16 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
|
||||
t.Run("Little", func(t *testing.T) {
|
||||
littleLFS = commitAndPush(t, littleSize, dstPath)
|
||||
lockFileTest(t, littleLFS, dstPath)
|
||||
|
||||
})
|
||||
t.Run("Big", func(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
bigLFS = commitAndPush(t, bigSize, dstPath)
|
||||
lockFileTest(t, bigLFS, dstPath)
|
||||
|
||||
})
|
||||
})
|
||||
t.Run("Locks", func(t *testing.T) {
|
||||
@@ -193,20 +218,21 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", big))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", littleLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, littleSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", big))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.NotEqual(t, bigSize, resp.Body.Len())
|
||||
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
|
||||
}
|
||||
})
|
||||
t.Run("Media", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
@@ -216,17 +242,19 @@ func testGit(t *testing.T, u *url.URL) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", big))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", littleLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, littleSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
if !testing.Short() {
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", big))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
|
||||
req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
assert.Equal(t, bigSize, resp.Body.Len())
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
@@ -243,15 +271,17 @@ func ensureAnonymousClone(t *testing.T, u *url.URL) {
|
||||
}
|
||||
|
||||
func lockTest(t *testing.T, remote, repoPath string) {
|
||||
_, err := git.NewCommand("remote").AddArguments("set-url", "origin", remote).RunInDir(repoPath) //TODO add test ssh git-lfs-creds
|
||||
lockFileTest(t, "README.md", repoPath)
|
||||
}
|
||||
|
||||
func lockFileTest(t *testing.T, filename, repoPath string) {
|
||||
_, err := git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
_, err = git.NewCommand("lfs").AddArguments("lock", filename).RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
_, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
_, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
_, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
_, err = git.NewCommand("lfs").AddArguments("unlock", "README.md").RunInDir(repoPath)
|
||||
_, err = git.NewCommand("lfs").AddArguments("unlock", filename).RunInDir(repoPath)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
|
@@ -92,6 +92,15 @@ func TestPrivateOrg(t *testing.T) {
|
||||
req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// non-org member who is collaborator on repo in private org
|
||||
session = loginUser(t, "user4")
|
||||
req = NewRequest(t, "GET", "/privated_org")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
req = NewRequest(t, "GET", "/privated_org/public_repo_on_private_org") // colab of this repo
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org")
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
|
||||
// site admin
|
||||
session = loginUser(t, "user1")
|
||||
req = NewRequest(t, "GET", "/privated_org")
|
||||
|
@@ -7,6 +7,7 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -532,7 +533,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
|
||||
}
|
||||
refMarked[issue.ID] = true
|
||||
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, c.Message)
|
||||
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, html.EscapeString(c.Message))
|
||||
if err = CreateRefComment(doer, repo, issue, message, c.Sha1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -9,3 +9,9 @@
|
||||
repo_id: 4
|
||||
user_id: 4
|
||||
mode: 2 # write
|
||||
|
||||
-
|
||||
id: 3
|
||||
repo_id: 38
|
||||
user_id: 4
|
||||
mode: 2 # write
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -277,6 +278,11 @@ func SetEngine() (err error) {
|
||||
// so use log file to instead print to stdout.
|
||||
x.SetLogger(log.XORMLogger)
|
||||
x.ShowSQL(setting.LogSQL)
|
||||
if DbCfg.Type == "mysql" {
|
||||
x.SetMaxIdleConns(0)
|
||||
x.SetConnMaxLifetime(3 * time.Second)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -861,7 +861,17 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
|
||||
line := scanner.Text()
|
||||
|
||||
if strings.HasPrefix(line, prefix) {
|
||||
pr.ConflictedFiles = append(pr.ConflictedFiles, strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0]))
|
||||
var found bool
|
||||
var filepath = strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0])
|
||||
for _, f := range pr.ConflictedFiles {
|
||||
if f == filepath {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
pr.ConflictedFiles = append(pr.ConflictedFiles, filepath)
|
||||
}
|
||||
}
|
||||
// only list 10 conflicted files
|
||||
if len(pr.ConflictedFiles) >= 10 {
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/go-xorm/builder"
|
||||
"github.com/go-xorm/core"
|
||||
)
|
||||
|
||||
// RepositoryListDefaultPageSize is the default number of repositories
|
||||
@@ -112,15 +111,17 @@ func (repos MirrorRepositoryList) LoadAttributes() error {
|
||||
|
||||
// SearchRepoOptions holds the search options
|
||||
type SearchRepoOptions struct {
|
||||
Keyword string
|
||||
OwnerID int64
|
||||
OrderBy SearchOrderBy
|
||||
Private bool // Include private repositories in results
|
||||
Starred bool
|
||||
Page int
|
||||
IsProfile bool
|
||||
AllPublic bool // Include also all public repositories
|
||||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
||||
UserID int64
|
||||
UserIsAdmin bool
|
||||
Keyword string
|
||||
OwnerID int64
|
||||
OrderBy SearchOrderBy
|
||||
Private bool // Include private repositories in results
|
||||
StarredByID int64
|
||||
Page int
|
||||
IsProfile bool
|
||||
AllPublic bool // Include also all public repositories
|
||||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
||||
// None -> include collaborative AND non-collaborative
|
||||
// True -> include just collaborative
|
||||
// False -> incude just non-collaborative
|
||||
@@ -168,72 +169,79 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
|
||||
var cond = builder.NewCond()
|
||||
|
||||
if !opts.Private {
|
||||
if opts.Private {
|
||||
if !opts.UserIsAdmin && opts.UserID != 0 && opts.UserID != opts.OwnerID {
|
||||
// OK we're in the context of a User
|
||||
// We should be Either
|
||||
cond = cond.And(builder.Or(
|
||||
// 1. Be able to see all non-private repositories that either:
|
||||
cond.And(
|
||||
builder.Eq{"is_private": false},
|
||||
builder.Or(
|
||||
// A. Aren't in organisations __OR__
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
|
||||
// B. Isn't a private organisation. (Limited is OK because we're logged in)
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePrivate}))),
|
||||
),
|
||||
// 2. Be able to see all repositories that we have access to
|
||||
builder.In("id", builder.Select("repo_id").
|
||||
From("`access`").
|
||||
Where(builder.And(
|
||||
builder.Eq{"user_id": opts.UserID},
|
||||
builder.Gt{"mode": int(AccessModeNone)}))),
|
||||
// 3. Be able to see all repositories that we are in a team
|
||||
builder.In("id", builder.Select("`team_repo`.repo_id").
|
||||
From("team_repo").
|
||||
Where(builder.Eq{"`team_user`.uid": opts.UserID}).
|
||||
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))))
|
||||
}
|
||||
} else {
|
||||
// Not looking at private organisations
|
||||
// We should be able to see all non-private repositories that either:
|
||||
cond = cond.And(builder.Eq{"is_private": false})
|
||||
accessCond := builder.Or(
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})))
|
||||
// A. Aren't in organisations __OR__
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
|
||||
// B. Isn't a private or limited organisation.
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}))))
|
||||
cond = cond.And(accessCond)
|
||||
}
|
||||
|
||||
// Restrict to starred repositories
|
||||
if opts.StarredByID > 0 {
|
||||
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID})))
|
||||
}
|
||||
|
||||
// Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate
|
||||
if opts.OwnerID > 0 {
|
||||
if opts.Starred {
|
||||
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.OwnerID})))
|
||||
} else {
|
||||
var accessCond = builder.NewCond()
|
||||
if opts.Collaborate != util.OptionalBoolTrue {
|
||||
accessCond = builder.Eq{"owner_id": opts.OwnerID}
|
||||
}
|
||||
|
||||
if opts.Collaborate != util.OptionalBoolFalse {
|
||||
collaborateCond := builder.And(
|
||||
builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID),
|
||||
builder.Neq{"owner_id": opts.OwnerID})
|
||||
if !opts.Private {
|
||||
collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
|
||||
}
|
||||
|
||||
accessCond = accessCond.Or(collaborateCond)
|
||||
}
|
||||
|
||||
var exprCond builder.Cond
|
||||
if DbCfg.Type == core.POSTGRES {
|
||||
exprCond = builder.Expr("org_user.org_id = \"user\".id")
|
||||
} else if DbCfg.Type == core.MSSQL {
|
||||
exprCond = builder.Expr("org_user.org_id = [user].id")
|
||||
} else {
|
||||
exprCond = builder.Eq{"org_user.org_id": "user.id"}
|
||||
}
|
||||
|
||||
visibilityCond := builder.Or(
|
||||
builder.In("owner_id",
|
||||
builder.Select("org_id").From("org_user").
|
||||
LeftJoin("`user`", exprCond).
|
||||
Where(
|
||||
builder.And(
|
||||
builder.Eq{"uid": opts.OwnerID},
|
||||
builder.Eq{"visibility": structs.VisibleTypePrivate})),
|
||||
),
|
||||
builder.In("owner_id",
|
||||
builder.Select("id").From("`user`").
|
||||
Where(
|
||||
builder.Or(
|
||||
builder.Eq{"visibility": structs.VisibleTypePublic},
|
||||
builder.Eq{"visibility": structs.VisibleTypeLimited})),
|
||||
),
|
||||
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
|
||||
)
|
||||
cond = cond.And(visibilityCond)
|
||||
|
||||
if opts.AllPublic {
|
||||
accessCond = accessCond.Or(builder.Eq{"is_private": false})
|
||||
}
|
||||
|
||||
cond = cond.And(accessCond)
|
||||
var accessCond = builder.NewCond()
|
||||
if opts.Collaborate != util.OptionalBoolTrue {
|
||||
accessCond = builder.Eq{"owner_id": opts.OwnerID}
|
||||
}
|
||||
|
||||
if opts.Collaborate != util.OptionalBoolFalse {
|
||||
collaborateCond := builder.And(
|
||||
builder.Or(
|
||||
builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID),
|
||||
builder.In("id", builder.Select("`team_repo`.repo_id").
|
||||
From("team_repo").
|
||||
Where(builder.Eq{"`team_user`.uid": opts.OwnerID}).
|
||||
Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"))),
|
||||
builder.Neq{"owner_id": opts.OwnerID})
|
||||
if !opts.Private {
|
||||
collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false))
|
||||
}
|
||||
|
||||
accessCond = accessCond.Or(collaborateCond)
|
||||
}
|
||||
|
||||
if opts.AllPublic {
|
||||
accessCond = accessCond.Or(builder.Eq{"is_private": false})
|
||||
}
|
||||
|
||||
cond = cond.And(accessCond)
|
||||
}
|
||||
|
||||
if opts.Keyword != "" {
|
||||
|
@@ -117,7 +117,7 @@ func TestSearchRepositoryByName(t *testing.T) {
|
||||
count: 4},
|
||||
{name: "PublicRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15},
|
||||
count: 4},
|
||||
count: 5},
|
||||
{name: "PublicRepositoriesOfUser2IncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18},
|
||||
count: 1},
|
||||
@@ -126,13 +126,13 @@ func TestSearchRepositoryByName(t *testing.T) {
|
||||
count: 3},
|
||||
{name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true},
|
||||
count: 8},
|
||||
count: 9},
|
||||
{name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true},
|
||||
count: 4},
|
||||
{name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true},
|
||||
count: 6},
|
||||
count: 7},
|
||||
{name: "PublicRepositoriesOfOrganization",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
|
||||
count: 1},
|
||||
@@ -150,7 +150,7 @@ func TestSearchRepositoryByName(t *testing.T) {
|
||||
count: 19},
|
||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
||||
count: 24},
|
||||
count: 25},
|
||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
||||
count: 13},
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/mcuadros/go-version"
|
||||
)
|
||||
|
||||
// MirrorQueue holds an UniqueQueue object of the mirror
|
||||
@@ -70,7 +71,17 @@ func (m *Mirror) ScheduleNextUpdate() {
|
||||
}
|
||||
|
||||
func remoteAddress(repoPath string) (string, error) {
|
||||
cmd := git.NewCommand("remote", "get-url", "origin")
|
||||
var cmd *git.Command
|
||||
binVersion, err := git.BinVersion()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if version.Compare(binVersion, "2.7", ">=") {
|
||||
cmd = git.NewCommand("remote", "get-url", "origin")
|
||||
} else {
|
||||
cmd = git.NewCommand("config", "--get", "remote.origin.url")
|
||||
}
|
||||
|
||||
result, err := cmd.RunInDir(repoPath)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
|
@@ -107,7 +107,17 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
|
||||
repo.mustOwner(e)
|
||||
}
|
||||
|
||||
if repo.Owner.IsOrganization() && !HasOrgVisible(repo.Owner, user) {
|
||||
var isCollaborator bool
|
||||
if user != nil {
|
||||
isCollaborator, err = repo.isCollaborator(e, user.ID)
|
||||
if err != nil {
|
||||
return perm, err
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent strangers from checking out public repo of private orginization
|
||||
// Allow user if they are collaborator of a repo within a private orginization but not a member of the orginization itself
|
||||
if repo.Owner.IsOrganization() && !HasOrgVisible(repo.Owner, user) && !isCollaborator {
|
||||
perm.AccessMode = AccessModeNone
|
||||
return
|
||||
}
|
||||
@@ -146,9 +156,7 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
|
||||
perm.UnitsMode = make(map[UnitType]AccessMode)
|
||||
|
||||
// Collaborators on organization
|
||||
if isCollaborator, err := repo.isCollaborator(e, user.ID); err != nil {
|
||||
return perm, err
|
||||
} else if isCollaborator {
|
||||
if isCollaborator {
|
||||
for _, u := range repo.Units {
|
||||
perm.UnitsMode[u.Type] = perm.AccessMode
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ type U2FRegistrationList []*U2FRegistration
|
||||
|
||||
// ToRegistrations will convert all U2FRegistrations to u2f.Registrations
|
||||
func (list U2FRegistrationList) ToRegistrations() []u2f.Registration {
|
||||
regs := make([]u2f.Registration, len(list))
|
||||
regs := make([]u2f.Registration, 0, len(list))
|
||||
for _, reg := range list {
|
||||
r, err := reg.Parse()
|
||||
if err != nil {
|
||||
|
@@ -832,10 +832,9 @@ func CreateUser(u *User) (err error) {
|
||||
return err
|
||||
}
|
||||
u.HashPassword(u.Passwd)
|
||||
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization
|
||||
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
|
||||
u.MaxRepoCreation = -1
|
||||
u.Theme = setting.UI.DefaultTheme
|
||||
u.AllowCreateOrganization = !setting.Admin.DisableRegularOrgCreation
|
||||
|
||||
if _, err = sess.Insert(u); err != nil {
|
||||
return err
|
||||
@@ -1347,6 +1346,19 @@ func GetUserByEmail(email string) (*User, error) {
|
||||
return GetUserByID(emailAddress.UID)
|
||||
}
|
||||
|
||||
// Finally, if email address is the protected email address:
|
||||
if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
|
||||
username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
|
||||
user := &User{LowerName: username}
|
||||
has, err := x.Get(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if has {
|
||||
return user, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrUserNotExist{0, email, 0}
|
||||
}
|
||||
|
||||
|
@@ -261,6 +261,8 @@ func TestCreateUser_Issue5882(t *testing.T) {
|
||||
{&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true},
|
||||
}
|
||||
|
||||
setting.Service.DefaultAllowCreateOrganization = true
|
||||
|
||||
for _, v := range tt {
|
||||
setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
)
|
||||
@@ -44,7 +45,7 @@ func checkIsValidRequest(ctx *context.Context, post bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) {
|
||||
func handleLockListOut(ctx *context.Context, repo *models.Repository, lock *models.LFSLock, err error) {
|
||||
if err != nil {
|
||||
if models.IsErrLFSLockNotExist(err) {
|
||||
ctx.JSON(200, api.LFSLockList{
|
||||
@@ -57,7 +58,7 @@ func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if ctx.Repo.Repository.ID != lock.RepoID {
|
||||
if repo.ID != lock.RepoID {
|
||||
ctx.JSON(200, api.LFSLockList{
|
||||
Locks: []*api.LFSLock{},
|
||||
})
|
||||
@@ -75,17 +76,21 @@ func GetListLockHandler(ctx *context.Context) {
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", metaMediaType)
|
||||
|
||||
err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository, models.AccessModeRead)
|
||||
rv := unpack(ctx)
|
||||
|
||||
repository, err := models.GetRepositoryByOwnerAndName(rv.User, rv.Repo)
|
||||
if err != nil {
|
||||
if models.IsErrLFSUnauthorizedAction(err) {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have pull access to list locks : " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(500, api.LFSLockError{
|
||||
Message: "unable to list lock : " + err.Error(),
|
||||
log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err)
|
||||
writeStatus(ctx, 404)
|
||||
return
|
||||
}
|
||||
repository.MustOwner()
|
||||
|
||||
authenticated := authenticate(ctx, repository, rv.Authorization, false)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have pull access to list locks",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -100,19 +105,19 @@ func GetListLockHandler(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
lock, err := models.GetLFSLockByID(int64(v))
|
||||
handleLockListOut(ctx, lock, err)
|
||||
handleLockListOut(ctx, repository, lock, err)
|
||||
return
|
||||
}
|
||||
|
||||
path := ctx.Query("path")
|
||||
if path != "" { //Case where we request a specific id
|
||||
lock, err := models.GetLFSLock(ctx.Repo.Repository, path)
|
||||
handleLockListOut(ctx, lock, err)
|
||||
lock, err := models.GetLFSLock(repository, path)
|
||||
handleLockListOut(ctx, repository, lock, err)
|
||||
return
|
||||
}
|
||||
|
||||
//If no query params path or id
|
||||
lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID)
|
||||
lockList, err := models.GetLFSLockByRepoID(repository.ID)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.LFSLockError{
|
||||
Message: "unable to list locks : " + err.Error(),
|
||||
@@ -135,16 +140,36 @@ func PostLockHandler(ctx *context.Context) {
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", metaMediaType)
|
||||
|
||||
userName := ctx.Params("username")
|
||||
repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git")
|
||||
authorization := ctx.Req.Header.Get("Authorization")
|
||||
|
||||
repository, err := models.GetRepositoryByOwnerAndName(userName, repoName)
|
||||
if err != nil {
|
||||
log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err)
|
||||
writeStatus(ctx, 404)
|
||||
return
|
||||
}
|
||||
repository.MustOwner()
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have push access to create locks",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req api.LFSLockRequest
|
||||
dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
|
||||
err := dec.Decode(&req)
|
||||
if err != nil {
|
||||
if err := dec.Decode(&req); err != nil {
|
||||
writeStatus(ctx, 400)
|
||||
return
|
||||
}
|
||||
|
||||
lock, err := models.CreateLFSLock(&models.LFSLock{
|
||||
Repo: ctx.Repo.Repository,
|
||||
Repo: repository,
|
||||
Path: req.Path,
|
||||
Owner: ctx.User,
|
||||
})
|
||||
@@ -178,23 +203,29 @@ func VerifyLockHandler(ctx *context.Context) {
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", metaMediaType)
|
||||
|
||||
err := models.CheckLFSAccessForRepo(ctx.User, ctx.Repo.Repository, models.AccessModeWrite)
|
||||
userName := ctx.Params("username")
|
||||
repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git")
|
||||
authorization := ctx.Req.Header.Get("Authorization")
|
||||
|
||||
repository, err := models.GetRepositoryByOwnerAndName(userName, repoName)
|
||||
if err != nil {
|
||||
if models.IsErrLFSUnauthorizedAction(err) {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have push access to verify locks : " + err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.JSON(500, api.LFSLockError{
|
||||
Message: "unable to verify lock : " + err.Error(),
|
||||
log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err)
|
||||
writeStatus(ctx, 404)
|
||||
return
|
||||
}
|
||||
repository.MustOwner()
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have push access to verify locks",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//TODO handle body json cursor and limit
|
||||
lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID)
|
||||
lockList, err := models.GetLFSLockByRepoID(repository.ID)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.LFSLockError{
|
||||
Message: "unable to list locks : " + err.Error(),
|
||||
@@ -223,10 +254,30 @@ func UnLockHandler(ctx *context.Context) {
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", metaMediaType)
|
||||
|
||||
userName := ctx.Params("username")
|
||||
repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git")
|
||||
authorization := ctx.Req.Header.Get("Authorization")
|
||||
|
||||
repository, err := models.GetRepositoryByOwnerAndName(userName, repoName)
|
||||
if err != nil {
|
||||
log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err)
|
||||
writeStatus(ctx, 404)
|
||||
return
|
||||
}
|
||||
repository.MustOwner()
|
||||
|
||||
authenticated := authenticate(ctx, repository, authorization, true)
|
||||
if !authenticated {
|
||||
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
|
||||
ctx.JSON(401, api.LFSLockError{
|
||||
Message: "You must have push access to delete locks",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req api.LFSLockDeleteRequest
|
||||
dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
|
||||
err := dec.Decode(&req)
|
||||
if err != nil {
|
||||
if err := dec.Decode(&req); err != nil {
|
||||
writeStatus(ctx, 400)
|
||||
return
|
||||
}
|
||||
|
@@ -15,6 +15,14 @@ import (
|
||||
func Init() {
|
||||
getIssueFullPattern()
|
||||
NewSanitizer()
|
||||
|
||||
// since setting maybe changed extensions, this will reload all parser extensions mapping
|
||||
extParsers = make(map[string]Parser)
|
||||
for _, parser := range parsers {
|
||||
for _, ext := range parser.Extensions() {
|
||||
extParsers[strings.ToLower(ext)] = parser
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parser defines an interface for parsering markup file to HTML
|
||||
|
@@ -20,7 +20,7 @@ var (
|
||||
MaxGitDiffLines int
|
||||
MaxGitDiffLineCharacters int
|
||||
MaxGitDiffFiles int
|
||||
GCArgs []string `delim:" "`
|
||||
GCArgs []string `ini:"GC_ARGS" delim:" "`
|
||||
Timeout struct {
|
||||
Default int
|
||||
Migrate int
|
||||
|
@@ -93,6 +93,10 @@ sqlite_helper = File path for the SQLite3 database.<br>Enter an absolute path if
|
||||
err_empty_db_path = The SQLite3 database path cannot be empty.
|
||||
no_admin_and_disable_registration = You cannot disable user self-registration without creating an administrator account.
|
||||
err_empty_admin_password = The administrator password cannot be empty.
|
||||
err_empty_admin_email = The administrator email cannot be empty.
|
||||
err_admin_name_is_reserved = Administrator Username is invalid, username is reserved
|
||||
err_admin_name_pattern_not_allowed = Administrator Username is invalid, username is pattern is not allowed
|
||||
err_admin_name_is_invalid = Administrator Username is invalid
|
||||
|
||||
general_title = General Settings
|
||||
app_name = Site Title
|
||||
|
File diff suppressed because one or more lines are too long
@@ -23,7 +23,7 @@
|
||||
border-bottom: 1px solid #eaeaea;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
.octicon, .fa {
|
||||
margin-left: 1px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
@@ -326,7 +326,7 @@ func GetAllUsers(ctx *context.APIContext) {
|
||||
|
||||
results := make([]*api.User, len(users))
|
||||
for i := range users {
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
|
||||
ctx.JSON(200, &results)
|
||||
|
@@ -698,14 +698,14 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
m.Combo("/teams", reqToken(), reqOrgMembership()).Get(org.ListTeams).
|
||||
Post(bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
Post(reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
m.Group("/hooks", func() {
|
||||
m.Combo("").Get(org.ListHooks).
|
||||
Post(bind(api.CreateHookOption{}), org.CreateHook)
|
||||
m.Combo("/:id").Get(org.GetHook).
|
||||
Patch(reqOrgOwnership(), bind(api.EditHookOption{}), org.EditHook).
|
||||
Delete(reqOrgOwnership(), org.DeleteHook)
|
||||
}, reqToken(), reqOrgMembership())
|
||||
Patch(bind(api.EditHookOption{}), org.EditHook).
|
||||
Delete(org.DeleteHook)
|
||||
}, reqToken(), reqOrgOwnership())
|
||||
}, orgAssignment(true))
|
||||
m.Group("/teams/:teamid", func() {
|
||||
m.Combo("").Get(org.GetTeam).
|
||||
|
@@ -55,6 +55,15 @@ func Search(ctx *context.APIContext) {
|
||||
// description: search only for repos that the user with the given id owns or contributes to
|
||||
// type: integer
|
||||
// format: int64
|
||||
// - name: starredBy
|
||||
// in: query
|
||||
// description: search only for repos that the user with the given id has starred
|
||||
// type: integer
|
||||
// format: int64
|
||||
// - name: private
|
||||
// in: query
|
||||
// description: include private repositories this user has access to (defaults to true)
|
||||
// type: boolean
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
@@ -95,6 +104,10 @@ func Search(ctx *context.APIContext) {
|
||||
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
|
||||
TopicOnly: ctx.QueryBool("topic"),
|
||||
Collaborate: util.OptionalBoolNone,
|
||||
Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
|
||||
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
StarredByID: ctx.QueryInt64("starredBy"),
|
||||
}
|
||||
|
||||
if ctx.QueryBool("exclusive") {
|
||||
@@ -139,42 +152,6 @@ func Search(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if opts.OwnerID > 0 {
|
||||
var repoOwner *models.User
|
||||
if ctx.User != nil && ctx.User.ID == opts.OwnerID {
|
||||
repoOwner = ctx.User
|
||||
} else {
|
||||
repoOwner, err = models.GetUserByID(opts.OwnerID)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.SearchError{
|
||||
OK: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if repoOwner.IsOrganization() {
|
||||
opts.Collaborate = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
// Check visibility.
|
||||
if ctx.IsSigned {
|
||||
if ctx.User.ID == repoOwner.ID {
|
||||
opts.Private = true
|
||||
} else if repoOwner.IsOrganization() {
|
||||
opts.Private, err = repoOwner.IsOwnedBy(ctx.User.ID)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.SearchError{
|
||||
OK: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repos, count, err := models.SearchRepositoryByName(opts)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.SearchError{
|
||||
|
@@ -67,7 +67,7 @@ func Search(ctx *context.APIContext) {
|
||||
|
||||
results := make([]*api.User, len(users))
|
||||
for i := range users {
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/mailer"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/external"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/ssh"
|
||||
|
||||
@@ -75,6 +76,7 @@ func GlobalInit() {
|
||||
|
||||
if setting.InstallLock {
|
||||
highlight.NewContext()
|
||||
external.RegisterParsers()
|
||||
markup.Init()
|
||||
if err := initDBEngine(); err == nil {
|
||||
log.Info("ORM engine initialization successful!")
|
||||
|
@@ -213,18 +213,42 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check admin password.
|
||||
if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
if form.AdminPasswd != form.AdminConfirmPasswd {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form)
|
||||
return
|
||||
// Check admin user creation
|
||||
if len(form.AdminName) > 0 {
|
||||
// Ensure AdminName is valid
|
||||
if err := models.IsUsableUsername(form.AdminName); err != nil {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminName"] = true
|
||||
if models.IsErrNameReserved(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_reserved"), tplInstall, form)
|
||||
return
|
||||
} else if models.IsErrNamePatternNotAllowed(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_admin_name_pattern_not_allowed"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_invalid"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
// Check Admin email
|
||||
if len(form.AdminEmail) == 0 {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminEmail"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_email"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
// Check admin password.
|
||||
if len(form.AdminPasswd) == 0 {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
if form.AdminPasswd != form.AdminConfirmPasswd {
|
||||
ctx.Data["Err_Admin"] = true
|
||||
ctx.Data["Err_AdminPasswd"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if form.AppURL[len(form.AppURL)-1] != '/' {
|
||||
|
@@ -406,12 +406,14 @@ func NewIssue(ctx *context.Context) {
|
||||
ctx.Data["BodyQuery"] = body
|
||||
|
||||
milestoneID := ctx.QueryInt64("milestone")
|
||||
milestone, err := models.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetMilestoneByID: %d: %v", milestoneID, err)
|
||||
} else {
|
||||
ctx.Data["milestone_id"] = milestoneID
|
||||
ctx.Data["Milestone"] = milestone
|
||||
if milestoneID > 0 {
|
||||
milestone, err := models.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
log.Error(4, "GetMilestoneByID: %d: %v", milestoneID, err)
|
||||
} else {
|
||||
ctx.Data["milestone_id"] = milestoneID
|
||||
ctx.Data["Milestone"] = milestone
|
||||
}
|
||||
}
|
||||
|
||||
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
|
||||
|
@@ -578,7 +578,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
})
|
||||
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef())
|
||||
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.RepoMustNotBeArchived(), repo.Action)
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
|
||||
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/issues", func() {
|
||||
@@ -827,7 +827,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/", lfs.PostLockHandler)
|
||||
m.Post("/verify", lfs.VerifyLockHandler)
|
||||
m.Post("/:lid/unlock", lfs.UnLockHandler)
|
||||
}, context.RepoAssignment())
|
||||
})
|
||||
m.Any("/*", func(ctx *context.Context) {
|
||||
ctx.NotFound("", nil)
|
||||
})
|
||||
|
@@ -435,50 +435,20 @@ func showOrgProfile(ctx *context.Context) {
|
||||
count int64
|
||||
err error
|
||||
)
|
||||
if ctx.IsSigned && !ctx.User.IsAdmin {
|
||||
env, err := org.AccessibleReposEnv(ctx.User.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("AccessibleReposEnv", err)
|
||||
return
|
||||
}
|
||||
env.SetSort(orderBy)
|
||||
if len(keyword) != 0 {
|
||||
env.AddKeyword(keyword)
|
||||
}
|
||||
repos, err = env.Repos(page, setting.UI.User.RepoPagingNum)
|
||||
if err != nil {
|
||||
ctx.ServerError("env.Repos", err)
|
||||
return
|
||||
}
|
||||
count, err = env.CountRepos()
|
||||
if err != nil {
|
||||
ctx.ServerError("env.CountRepos", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
showPrivate := ctx.IsSigned && ctx.User.IsAdmin
|
||||
if len(keyword) == 0 {
|
||||
repos, err = models.GetUserRepositories(org.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepositories", err)
|
||||
return
|
||||
}
|
||||
count = models.CountUserRepositories(org.ID, showPrivate)
|
||||
} else {
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: org.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: showPrivate,
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: org.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := org.GetMembers(); err != nil {
|
||||
|
@@ -259,7 +259,7 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) {
|
||||
ctx.Data["Application"] = app
|
||||
ctx.Data["RedirectURI"] = form.RedirectURI
|
||||
ctx.Data["State"] = form.State
|
||||
ctx.Data["ApplicationUserLink"] = "<a href=\"" + setting.LocalURL + app.User.LowerName + "\">@" + app.User.Name + "</a>"
|
||||
ctx.Data["ApplicationUserLink"] = "<a href=\"" + setting.AppURL + app.User.LowerName + "\">@" + app.User.Name + "</a>"
|
||||
ctx.Data["ApplicationRedirectDomainHTML"] = "<strong>" + form.RedirectURI + "</strong>"
|
||||
// TODO document SESSION <=> FORM
|
||||
ctx.Session.Set("client_id", app.ClientID)
|
||||
|
@@ -158,83 +158,47 @@ func Profile(ctx *context.Context) {
|
||||
}
|
||||
case "stars":
|
||||
ctx.Data["PageIsProfileStarList"] = true
|
||||
if len(keyword) == 0 {
|
||||
repos, err = ctxUser.GetStarredRepos(showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
|
||||
if err != nil {
|
||||
ctx.ServerError("GetStarredRepos", err)
|
||||
return
|
||||
}
|
||||
|
||||
count, err = ctxUser.GetStarredRepoCount(showPrivate)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetStarredRepoCount", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: ctxUser.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: showPrivate,
|
||||
Page: page,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Starred: true,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
StarredByID: ctxUser.ID,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Repos"] = repos
|
||||
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
|
||||
ctx.Data["Total"] = count
|
||||
default:
|
||||
if len(keyword) == 0 {
|
||||
var total int
|
||||
repos, err = models.GetUserRepositories(ctxUser.ID, showPrivate, page, setting.UI.User.RepoPagingNum, orderBy.String())
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepositories", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Repos"] = repos
|
||||
|
||||
if showPrivate {
|
||||
total = ctxUser.NumRepos
|
||||
} else {
|
||||
count, err := models.GetPublicRepositoryCount(ctxUser)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetPublicRepositoryCount", err)
|
||||
return
|
||||
}
|
||||
total = int(count)
|
||||
}
|
||||
|
||||
ctx.Data["Page"] = paginater.New(total, setting.UI.User.RepoPagingNum, page, 5)
|
||||
ctx.Data["Total"] = total
|
||||
} else {
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: ctxUser.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: showPrivate,
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Repos"] = repos
|
||||
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
|
||||
ctx.Data["Total"] = count
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: ctxUser.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Repos"] = repos
|
||||
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
|
||||
ctx.Data["Total"] = count
|
||||
}
|
||||
|
||||
ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.User.ID)
|
||||
|
@@ -1085,6 +1085,19 @@
|
||||
"name": "uid",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "search only for repos that the user with the given id has starred",
|
||||
"name": "starredBy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"description": "include private repositories this user has access to (defaults to true)",
|
||||
"name": "private",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "page number of results to return (1-based)",
|
||||
|
Reference in New Issue
Block a user