Compare commits

..

21 Commits

Author SHA1 Message Date
John Olheiser
cf7a5b3d91 Changelog 1.8.3 (#7230)
* Changelog 1.8.3

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Suggestion

Co-Authored-By: zeripath <art27@cantab.net>
2019-06-17 18:08:50 +01:00
zeripath
5d1a8d23b0 Always set userID on LFS authentication (#7224)
* Always set userID on LFS authentication

Fix #5478
Fix #7219

* Deploy keys should only be able to read their repos
2019-06-17 18:36:42 +03:00
zeripath
dbd0a2e6dc Fix LFS Locks over SSH (#6999) (#7223)
* Fix LFS Locks over SSH
* Mark test as skipped
2019-06-17 14:54:49 +01:00
Lunny Xiao
7697a282d6 fix duplicated file on pull request conflicted files (#7211) (#7214) 2019-06-15 17:22:45 +01:00
zeripath
76e8eec3d9 Detect noreply email address as user (#7133) (#7195) 2019-06-13 12:16:50 -04:00
Lunny Xiao
10effb396a if milestone id is zero don't get it from database (#7174) 2019-06-10 23:29:07 +08:00
Lanre Adelowo
5e97b2d00e archived repos can be starred and watched (#7163) (#7168) 2019-06-10 09:20:34 -04:00
Lunny Xiao
873acd884d fix GCArgs load from ini (#7156) (#7157) 2019-06-08 10:41:44 -04:00
techknowlogick
dc73b2748d 1.8.2 changelog (#7079)
* 1.8.2 changelog
2019-05-29 20:29:53 +01:00
Lunny Xiao
31ad8b7026 Fix wrong init dependency on markup extensions (#7038) (#7074)
* fix wrong init dependency on markup extensions
2019-05-29 12:05:36 -04:00
techknowlogick
d07edc5336 Handle early git version's lack of get-url (#7065) (#7076) 2019-05-29 12:04:55 -04:00
Lunny Xiao
63cb160cb1 fix possbile mysql invalid connnection error (#7051) (#7071) 2019-05-29 10:49:03 +01:00
zeripath
8d5c3d3d0b Install page - Handle invalid administrator username better (#7060) (#7063)
* Install page - detect invalid admin username before installing

* Also fix #6954
2019-05-28 10:38:13 +01:00
techknowlogick
706d85b87d Disable arm7 builds (#7037) (#7042) 2019-05-25 20:03:43 +01:00
jpicht
75e491c03e Fix default for allowing new organization creation for new users (#7017) (#7034)
* FIX issue 6542

When creating users DefaultAllowCreateOrganization was ignored.

Signed-off-by: Julian Picht <julian.picht@gmail.com>

* fix TestCreateUser_Issue5882

Signed-off-by: Julian Picht <julian.picht@gmail.com>
2019-05-25 02:00:04 +03:00
Lauris BH
608f46e59c SearchRepositoryByName improvements and unification (#6897) (#7002)
* SearchRepositoryByName improvements and unification (#6897)

* Update tests

Co-Authored-By: zeripath <art27@cantab.net>

* Update tests

Co-Authored-By: zeripath <art27@cantab.net>

* Update tests

Co-Authored-By: zeripath <art27@cantab.net>

* Fix tests
2019-05-21 18:07:07 +03:00
David Schneiderbauer
895764e7f5 fix u2f registrationlist ToRegistrations() method (#6980) (#6982) 2019-05-18 10:15:41 -04:00
mrsdizzie
21983965d0 Allow collaborators to view repo owned by private org (#6965) (#6968)
* Allow collaborators to view repo owned private org (#6965)

Handle case where an orginization is private but a user who is not a
member of the orgninization has been added as a collaborator of a repo
within that org

Fixes #6962

* Match release/v1.8 fixtures
2019-05-16 18:01:55 -04:00
techknowlogick
e069a75817 Use AppURL for Oauth user link (#6894) (#6925) 2019-05-13 07:53:02 +03:00
zeripath
ebb8fa610c Escape the commit message on issues update (#6901) (#6902) 2019-05-10 21:19:45 +01:00
Richard Mahn
c8fc7fce4a Fixes #6881 - API users search fix (#6882) (#6885) 2019-05-09 13:37:49 +08:00
36 changed files with 629 additions and 412 deletions

View File

@@ -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 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). 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 ## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08
* BUGFIXES * BUGFIXES
* Fix 404 when sending pull requests in some situations (#6871) (#6873) * Fix 404 when sending pull requests in some situations (#6871) (#6873)

View File

@@ -336,7 +336,7 @@ release-linux:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u src.techknowlogick.com/xgo; \ $(GO) get -u src.techknowlogick.com/xgo; \
fi 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) ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries cp /build/* $(DIST)/binaries
endif endif

View File

@@ -219,8 +219,9 @@ func runServ(c *cli.Context) error {
var ( var (
keyID int64 keyID int64
user *models.User user *models.User
userID int64
) )
if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
keys := strings.Split(c.Args()[0], "-") keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 { if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0]) fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
@@ -231,8 +232,8 @@ func runServ(c *cli.Context) error {
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err) fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
} }
keyID = key.ID keyID = key.ID
userID = key.OwnerID
// Check deploy key or user key.
if key.Type == models.KeyTypeDeploy { if key.Type == models.KeyTypeDeploy {
// Now we have to get the deploy key for this repo // Now we have to get the deploy key for this repo
deployKey, err := private.GetDeployKey(key.ID, repo.ID) deployKey, err := private.GetDeployKey(key.ID, repo.ID)
@@ -258,7 +259,9 @@ func runServ(c *cli.Context) error {
// so for now use the owner // so for now use the owner
os.Setenv(models.EnvPusherName, username) os.Setenv(models.EnvPusherName, username)
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID)) os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
} else { userID = repo.OwnerID
} else if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
// Check deploy key or user key.
user, err = private.GetUserByKeyID(key.ID) user, err = private.GetUserByKeyID(key.ID)
if err != nil { if err != nil {
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err) fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
@@ -286,7 +289,6 @@ func runServ(c *cli.Context) error {
os.Setenv(models.EnvPusherName, user.Name) os.Setenv(models.EnvPusherName, user.Name)
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID)) os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
} }
}
//LFS token authentication //LFS token authentication
if verb == lfsAuthenticateVerb { if verb == lfsAuthenticateVerb {
@@ -299,8 +301,8 @@ func runServ(c *cli.Context) error {
"exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(), "exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
"nbf": now.Unix(), "nbf": now.Unix(),
} }
if user != nil { if userID > 0 {
claims["user"] = user.ID claims["user"] = userID
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

View File

@@ -15,7 +15,6 @@ import (
"strings" "strings"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes" "code.gitea.io/gitea/routers/routes"
@@ -120,8 +119,6 @@ func runWeb(ctx *cli.Context) error {
routers.GlobalInit() routers.GlobalInit()
external.RegisterParsers()
m := routes.NewMacaron() m := routes.NewMacaron()
routes.RegisterRoutes(m) routes.RegisterRoutes(m)

View File

@@ -20,6 +20,7 @@ import (
"strconv" "strconv"
"time" "time"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/routers" "code.gitea.io/gitea/routers"
"code.gitea.io/gitea/routers/routes" "code.gitea.io/gitea/routers/routes"
@@ -113,6 +114,7 @@ func runPR() {
log.Printf("[PR] Setting up router\n") log.Printf("[PR] Setting up router\n")
//routers.GlobalInit() //routers.GlobalInit()
external.RegisterParsers() external.RegisterParsers()
markup.Init()
m := routes.NewMacaron() m := routes.NewMacaron()
routes.RegisterRoutes(m) routes.RegisterRoutes(m)

View File

@@ -129,3 +129,18 @@ func TestAPIListUsers(t *testing.T) {
numberOfUsers := models.GetCount(t, &models.User{}, "type = 0") numberOfUsers := models.GetCount(t, &models.User{}, "type = 0")
assert.Equal(t, numberOfUsers, len(users)) 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)
}

View File

@@ -69,40 +69,41 @@ func TestAPISearchRepo(t *testing.T) {
name, requestURL string name, requestURL string
expectedResults 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}, nil: {count: 19},
user: {count: 19}, user: {count: 19},
user2: {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}, nil: {count: 10},
user: {count: 10}, user: {count: 10},
user2: {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}, nil: {count: 10},
user: {count: 10}, user: {count: 10},
user2: {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_"}, nil: {count: 7, repoName: "big_test_"},
user: {count: 7, repoName: "big_test_"}, user: {count: 7, repoName: "big_test_"},
user2: {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{ {name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{
nil: {count: 4}, nil: {count: 5},
user: {count: 8, includesPrivate: true}, user: {count: 9, includesPrivate: true},
user2: {count: 4}}, user2: {count: 5, includesPrivate: true}},
}, },
{name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser2", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user2.ID), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 2, includesPrivate: true},
user2: {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{ {name: "RepositoriesAccessibleAndRelatedToUser3", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user3.ID), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 4, includesPrivate: true},
user2: {count: 1}, user2: {count: 2, includesPrivate: true},
user3: {count: 4, includesPrivate: true}}, user3: {count: 4, includesPrivate: true}},
}, },
{name: "RepositoriesOwnedByOrganization", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", orgUser.ID), expectedResults: expectedResults{ {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{ {name: "RepositoriesAccessibleAndRelatedToUser4", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user4.ID), expectedResults: expectedResults{
nil: {count: 3}, nil: {count: 3},
user: {count: 3}, user: {count: 4, includesPrivate: true},
user4: {count: 6, 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{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeSource", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "source"), expectedResults: expectedResults{
nil: {count: 0}, nil: {count: 0},
user: {count: 0}, user: {count: 1, includesPrivate: true},
user4: {count: 0, 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{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeFork", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "fork"), expectedResults: expectedResults{
nil: {count: 1}, nil: {count: 1},
user: {count: 1}, user: {count: 1},
@@ -136,8 +137,8 @@ func TestAPISearchRepo(t *testing.T) {
user4: {count: 2, includesPrivate: true}}}, user4: {count: 2, includesPrivate: true}}},
{name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{ {name: "RepositoriesAccessibleAndRelatedToUser4/SearchModeCollaborative", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d&mode=%s", user4.ID, "collaborative"), expectedResults: expectedResults{
nil: {count: 0}, nil: {count: 0},
user: {count: 0}, user: {count: 1, includesPrivate: true},
user4: {count: 0, includesPrivate: true}}}, user4: {count: 1, includesPrivate: true}}},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
@@ -164,14 +165,19 @@ func TestAPISearchRepo(t *testing.T) {
var body api.SearchResults var body api.SearchResults
DecodeJSON(t, response, &body) 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 { for _, repo := range body.Data {
r := getRepo(t, repo.ID) r := getRepo(t, repo.ID)
hasAccess, err := models.HasAccess(userID, r) hasAccess, err := models.HasAccess(userID, r)
assert.NoError(t, err) assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err)
assert.True(t, hasAccess) assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName)
assert.NotEmpty(t, repo.Name) assert.NotEmpty(t, repo.Name)
assert.Equal(t, repo.Name, r.Name)
if len(expected.repoName) > 0 { if len(expected.repoName) > 0 {
assert.Contains(t, repo.Name, expected.repoName) assert.Contains(t, repo.Name, expected.repoName)
@@ -182,7 +188,7 @@ func TestAPISearchRepo(t *testing.T) {
} }
if !expected.includesPrivate { if !expected.includesPrivate {
assert.False(t, repo.Private) assert.False(t, repo.Private, "User: %d not expecting private repository: %s", userID, repo.FullName)
} }
} }
}) })

View 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)
}
}

View File

@@ -61,6 +61,10 @@ func testGit(t *testing.T, u *url.URL) {
little = commitAndPush(t, littleSize, dstPath) little = commitAndPush(t, littleSize, dstPath)
}) })
t.Run("Big", func(t *testing.T) { t.Run("Big", func(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
return
}
big = commitAndPush(t, bigSize, dstPath) big = commitAndPush(t, bigSize, dstPath)
}) })
}) })
@@ -77,9 +81,15 @@ func testGit(t *testing.T, u *url.URL) {
t.Run("Little", func(t *testing.T) { t.Run("Little", func(t *testing.T) {
littleLFS = commitAndPush(t, littleSize, dstPath) littleLFS = commitAndPush(t, littleSize, dstPath)
lockFileTest(t, littleLFS, dstPath)
}) })
t.Run("Big", func(t *testing.T) { t.Run("Big", func(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
return
}
bigLFS = commitAndPush(t, bigSize, dstPath) bigLFS = commitAndPush(t, bigSize, dstPath)
lockFileTest(t, bigLFS, dstPath)
}) })
}) })
t.Run("Locks", func(t *testing.T) { 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) resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Body.Len()) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", littleLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, littleSize, resp.Body.Len()) assert.NotEqual(t, littleSize, resp.Body.Len())
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/raw/branch/master/", bigLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, bigSize, resp.Body.Len()) assert.NotEqual(t, bigSize, resp.Body.Len())
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
}
}) })
t.Run("Media", func(t *testing.T) { 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) resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", littleLFS))
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) assert.Equal(t, littleSize, 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-17/media/branch/master/", bigLFS))
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, bigSize, resp.Length) assert.Equal(t, bigSize, resp.Length)
}
}) })
}) })
@@ -160,6 +174,10 @@ func testGit(t *testing.T, u *url.URL) {
little = commitAndPush(t, littleSize, dstPath) little = commitAndPush(t, littleSize, dstPath)
}) })
t.Run("Big", func(t *testing.T) { t.Run("Big", func(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
return
}
big = commitAndPush(t, bigSize, dstPath) big = commitAndPush(t, bigSize, dstPath)
}) })
}) })
@@ -176,9 +194,16 @@ func testGit(t *testing.T, u *url.URL) {
t.Run("Little", func(t *testing.T) { t.Run("Little", func(t *testing.T) {
littleLFS = commitAndPush(t, littleSize, dstPath) littleLFS = commitAndPush(t, littleSize, dstPath)
lockFileTest(t, littleLFS, dstPath)
}) })
t.Run("Big", func(t *testing.T) { t.Run("Big", func(t *testing.T) {
if testing.Short() {
return
}
bigLFS = commitAndPush(t, bigSize, dstPath) bigLFS = commitAndPush(t, bigSize, dstPath)
lockFileTest(t, bigLFS, dstPath)
}) })
}) })
t.Run("Locks", func(t *testing.T) { 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) resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Body.Len()) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", littleLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, littleSize, resp.Body.Len()) assert.NotEqual(t, littleSize, resp.Body.Len())
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/raw/branch/master/", bigLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, bigSize, resp.Body.Len()) assert.NotEqual(t, bigSize, resp.Body.Len())
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
}
}) })
t.Run("Media", func(t *testing.T) { t.Run("Media", func(t *testing.T) {
session := loginUser(t, "user2") session := loginUser(t, "user2")
@@ -216,17 +242,19 @@ func testGit(t *testing.T, u *url.URL) {
resp := session.MakeRequest(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Body.Len()) 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", littleLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Body.Len()) assert.Equal(t, littleSize, 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)) req = NewRequest(t, "GET", path.Join("/user2/repo-tmp-18/media/branch/master/", bigLFS))
resp = session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, bigSize, resp.Body.Len()) 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) { 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) assert.NoError(t, err)
_, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath) _, err = git.NewCommand("lfs").AddArguments("locks").RunInDir(repoPath)
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand("lfs").AddArguments("lock", "README.md").RunInDir(repoPath) _, err = git.NewCommand("lfs").AddArguments("unlock", filename).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)
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -92,6 +92,15 @@ func TestPrivateOrg(t *testing.T) {
req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org") req = NewRequest(t, "GET", "/privated_org/private_repo_on_private_org")
session.MakeRequest(t, req, http.StatusNotFound) 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 // site admin
session = loginUser(t, "user1") session = loginUser(t, "user1")
req = NewRequest(t, "GET", "/privated_org") req = NewRequest(t, "GET", "/privated_org")

View File

@@ -7,6 +7,7 @@ package models
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"html"
"path" "path"
"regexp" "regexp"
"strconv" "strconv"
@@ -532,7 +533,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
} }
refMarked[issue.ID] = true 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 { if err = CreateRefComment(doer, repo, issue, message, c.Sha1); err != nil {
return err return err
} }

View File

@@ -9,3 +9,9 @@
repo_id: 4 repo_id: 4
user_id: 4 user_id: 4
mode: 2 # write mode: 2 # write
-
id: 3
repo_id: 38
user_id: 4
mode: 2 # write

View File

@@ -14,6 +14,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@@ -277,6 +278,11 @@ func SetEngine() (err error) {
// so use log file to instead print to stdout. // so use log file to instead print to stdout.
x.SetLogger(log.XORMLogger) x.SetLogger(log.XORMLogger)
x.ShowSQL(setting.LogSQL) x.ShowSQL(setting.LogSQL)
if DbCfg.Type == "mysql" {
x.SetMaxIdleConns(0)
x.SetConnMaxLifetime(3 * time.Second)
}
return nil return nil
} }

View File

@@ -861,7 +861,17 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
line := scanner.Text() line := scanner.Text()
if strings.HasPrefix(line, prefix) { 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 // only list 10 conflicted files
if len(pr.ConflictedFiles) >= 10 { if len(pr.ConflictedFiles) >= 10 {

View File

@@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"github.com/go-xorm/builder" "github.com/go-xorm/builder"
"github.com/go-xorm/core"
) )
// RepositoryListDefaultPageSize is the default number of repositories // RepositoryListDefaultPageSize is the default number of repositories
@@ -112,11 +111,13 @@ func (repos MirrorRepositoryList) LoadAttributes() error {
// SearchRepoOptions holds the search options // SearchRepoOptions holds the search options
type SearchRepoOptions struct { type SearchRepoOptions struct {
UserID int64
UserIsAdmin bool
Keyword string Keyword string
OwnerID int64 OwnerID int64
OrderBy SearchOrderBy OrderBy SearchOrderBy
Private bool // Include private repositories in results Private bool // Include private repositories in results
Starred bool StarredByID int64
Page int Page int
IsProfile bool IsProfile bool
AllPublic bool // Include also all public repositories AllPublic bool // Include also all public repositories
@@ -168,21 +169,53 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
if opts.Page <= 0 { if opts.Page <= 0 {
opts.Page = 1 opts.Page = 1
} }
var cond = builder.NewCond() 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}) cond = cond.And(builder.Eq{"is_private": false})
accessCond := builder.Or( 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}))), // A. Aren't in organisations __OR__
builder.NotIn("owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization}))) 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) 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.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() var accessCond = builder.NewCond()
if opts.Collaborate != util.OptionalBoolTrue { if opts.Collaborate != util.OptionalBoolTrue {
accessCond = builder.Eq{"owner_id": opts.OwnerID} accessCond = builder.Eq{"owner_id": opts.OwnerID}
@@ -190,7 +223,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
if opts.Collaborate != util.OptionalBoolFalse { if opts.Collaborate != util.OptionalBoolFalse {
collaborateCond := builder.And( collaborateCond := builder.And(
builder.Or(
builder.Expr("repository.id IN (SELECT repo_id FROM `access` WHERE access.user_id = ?)", opts.OwnerID), 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}) builder.Neq{"owner_id": opts.OwnerID})
if !opts.Private { 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)) 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))
@@ -199,42 +237,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
accessCond = accessCond.Or(collaborateCond) 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 { if opts.AllPublic {
accessCond = accessCond.Or(builder.Eq{"is_private": false}) accessCond = accessCond.Or(builder.Eq{"is_private": false})
} }
cond = cond.And(accessCond) cond = cond.And(accessCond)
} }
}
if opts.Keyword != "" { if opts.Keyword != "" {
// separate keyword // separate keyword

View File

@@ -117,7 +117,7 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 4}, count: 4},
{name: "PublicRepositoriesOfUserIncludingCollaborative", {name: "PublicRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15},
count: 4}, count: 5},
{name: "PublicRepositoriesOfUser2IncludingCollaborative", {name: "PublicRepositoriesOfUser2IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18},
count: 1}, count: 1},
@@ -126,13 +126,13 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 3}, count: 3},
{name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true},
count: 8}, count: 9},
{name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 18, Private: true},
count: 4}, count: 4},
{name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative", {name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 20, Private: true},
count: 6}, count: 7},
{name: "PublicRepositoriesOfOrganization", {name: "PublicRepositoriesOfOrganization",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, Collaborate: util.OptionalBoolFalse},
count: 1}, count: 1},
@@ -150,7 +150,7 @@ func TestSearchRepositoryByName(t *testing.T) {
count: 19}, count: 19},
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
count: 24}, count: 25},
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", {name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true}, opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
count: 13}, count: 13},

View File

@@ -20,6 +20,7 @@ import (
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/mcuadros/go-version"
) )
// MirrorQueue holds an UniqueQueue object of the mirror // MirrorQueue holds an UniqueQueue object of the mirror
@@ -70,7 +71,17 @@ func (m *Mirror) ScheduleNextUpdate() {
} }
func remoteAddress(repoPath string) (string, error) { 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) result, err := cmd.RunInDir(repoPath)
if err != nil { if err != nil {
if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {

View File

@@ -107,7 +107,17 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
repo.mustOwner(e) 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 perm.AccessMode = AccessModeNone
return return
} }
@@ -146,9 +156,7 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
perm.UnitsMode = make(map[UnitType]AccessMode) perm.UnitsMode = make(map[UnitType]AccessMode)
// Collaborators on organization // Collaborators on organization
if isCollaborator, err := repo.isCollaborator(e, user.ID); err != nil { if isCollaborator {
return perm, err
} else if isCollaborator {
for _, u := range repo.Units { for _, u := range repo.Units {
perm.UnitsMode[u.Type] = perm.AccessMode perm.UnitsMode[u.Type] = perm.AccessMode
} }

View File

@@ -48,7 +48,7 @@ type U2FRegistrationList []*U2FRegistration
// ToRegistrations will convert all U2FRegistrations to u2f.Registrations // ToRegistrations will convert all U2FRegistrations to u2f.Registrations
func (list U2FRegistrationList) ToRegistrations() []u2f.Registration { func (list U2FRegistrationList) ToRegistrations() []u2f.Registration {
regs := make([]u2f.Registration, len(list)) regs := make([]u2f.Registration, 0, len(list))
for _, reg := range list { for _, reg := range list {
r, err := reg.Parse() r, err := reg.Parse()
if err != nil { if err != nil {

View File

@@ -832,10 +832,9 @@ func CreateUser(u *User) (err error) {
return err return err
} }
u.HashPassword(u.Passwd) u.HashPassword(u.Passwd)
u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
u.MaxRepoCreation = -1 u.MaxRepoCreation = -1
u.Theme = setting.UI.DefaultTheme u.Theme = setting.UI.DefaultTheme
u.AllowCreateOrganization = !setting.Admin.DisableRegularOrgCreation
if _, err = sess.Insert(u); err != nil { if _, err = sess.Insert(u); err != nil {
return err return err
@@ -1347,6 +1346,19 @@ func GetUserByEmail(email string) (*User, error) {
return GetUserByID(emailAddress.UID) 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} return nil, ErrUserNotExist{0, email, 0}
} }

View File

@@ -261,6 +261,8 @@ func TestCreateUser_Issue5882(t *testing.T) {
{&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true}, {&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true},
} }
setting.Service.DefaultAllowCreateOrganization = true
for _, v := range tt { for _, v := range tt {
setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation

View File

@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/sdk/gitea" api "code.gitea.io/sdk/gitea"
) )
@@ -44,7 +45,7 @@ func checkIsValidRequest(ctx *context.Context, post bool) bool {
return true 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 err != nil {
if models.IsErrLFSLockNotExist(err) { if models.IsErrLFSLockNotExist(err) {
ctx.JSON(200, api.LFSLockList{ ctx.JSON(200, api.LFSLockList{
@@ -57,7 +58,7 @@ func handleLockListOut(ctx *context.Context, lock *models.LFSLock, err error) {
}) })
return return
} }
if ctx.Repo.Repository.ID != lock.RepoID { if repo.ID != lock.RepoID {
ctx.JSON(200, api.LFSLockList{ ctx.JSON(200, api.LFSLockList{
Locks: []*api.LFSLock{}, Locks: []*api.LFSLock{},
}) })
@@ -75,17 +76,21 @@ func GetListLockHandler(ctx *context.Context) {
} }
ctx.Resp.Header().Set("Content-Type", metaMediaType) 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 err != nil {
if models.IsErrLFSUnauthorizedAction(err) { log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err)
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") writeStatus(ctx, 404)
ctx.JSON(401, api.LFSLockError{
Message: "You must have pull access to list locks : " + err.Error(),
})
return return
} }
ctx.JSON(500, api.LFSLockError{ repository.MustOwner()
Message: "unable to list lock : " + err.Error(),
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 return
} }
@@ -100,19 +105,19 @@ func GetListLockHandler(ctx *context.Context) {
return return
} }
lock, err := models.GetLFSLockByID(int64(v)) lock, err := models.GetLFSLockByID(int64(v))
handleLockListOut(ctx, lock, err) handleLockListOut(ctx, repository, lock, err)
return return
} }
path := ctx.Query("path") path := ctx.Query("path")
if path != "" { //Case where we request a specific id if path != "" { //Case where we request a specific id
lock, err := models.GetLFSLock(ctx.Repo.Repository, path) lock, err := models.GetLFSLock(repository, path)
handleLockListOut(ctx, lock, err) handleLockListOut(ctx, repository, lock, err)
return return
} }
//If no query params path or id //If no query params path or id
lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID) lockList, err := models.GetLFSLockByRepoID(repository.ID)
if err != nil { if err != nil {
ctx.JSON(500, api.LFSLockError{ ctx.JSON(500, api.LFSLockError{
Message: "unable to list locks : " + err.Error(), Message: "unable to list locks : " + err.Error(),
@@ -135,16 +140,36 @@ func PostLockHandler(ctx *context.Context) {
} }
ctx.Resp.Header().Set("Content-Type", metaMediaType) 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 var req api.LFSLockRequest
dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
err := dec.Decode(&req) if err := dec.Decode(&req); err != nil {
if err != nil {
writeStatus(ctx, 400) writeStatus(ctx, 400)
return return
} }
lock, err := models.CreateLFSLock(&models.LFSLock{ lock, err := models.CreateLFSLock(&models.LFSLock{
Repo: ctx.Repo.Repository, Repo: repository,
Path: req.Path, Path: req.Path,
Owner: ctx.User, Owner: ctx.User,
}) })
@@ -178,23 +203,29 @@ func VerifyLockHandler(ctx *context.Context) {
} }
ctx.Resp.Header().Set("Content-Type", metaMediaType) 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 err != nil {
if models.IsErrLFSUnauthorizedAction(err) { log.Debug("Could not find repository: %s/%s - %s", userName, repoName, err)
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") writeStatus(ctx, 404)
ctx.JSON(401, api.LFSLockError{
Message: "You must have push access to verify locks : " + err.Error(),
})
return return
} }
ctx.JSON(500, api.LFSLockError{ repository.MustOwner()
Message: "unable to verify lock : " + err.Error(),
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 return
} }
//TODO handle body json cursor and limit //TODO handle body json cursor and limit
lockList, err := models.GetLFSLockByRepoID(ctx.Repo.Repository.ID) lockList, err := models.GetLFSLockByRepoID(repository.ID)
if err != nil { if err != nil {
ctx.JSON(500, api.LFSLockError{ ctx.JSON(500, api.LFSLockError{
Message: "unable to list locks : " + err.Error(), Message: "unable to list locks : " + err.Error(),
@@ -223,10 +254,30 @@ func UnLockHandler(ctx *context.Context) {
} }
ctx.Resp.Header().Set("Content-Type", metaMediaType) 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 var req api.LFSLockDeleteRequest
dec := json.NewDecoder(ctx.Req.Body().ReadCloser()) dec := json.NewDecoder(ctx.Req.Body().ReadCloser())
err := dec.Decode(&req) if err := dec.Decode(&req); err != nil {
if err != nil {
writeStatus(ctx, 400) writeStatus(ctx, 400)
return return
} }

View File

@@ -15,6 +15,14 @@ import (
func Init() { func Init() {
getIssueFullPattern() getIssueFullPattern()
NewSanitizer() 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 // Parser defines an interface for parsering markup file to HTML

View File

@@ -20,7 +20,7 @@ var (
MaxGitDiffLines int MaxGitDiffLines int
MaxGitDiffLineCharacters int MaxGitDiffLineCharacters int
MaxGitDiffFiles int MaxGitDiffFiles int
GCArgs []string `delim:" "` GCArgs []string `ini:"GC_ARGS" delim:" "`
Timeout struct { Timeout struct {
Default int Default int
Migrate int Migrate int

View File

@@ -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. 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. 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_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 general_title = General Settings
app_name = Site Title app_name = Site Title

View File

@@ -326,7 +326,7 @@ func GetAllUsers(ctx *context.APIContext) {
results := make([]*api.User, len(users)) results := make([]*api.User, len(users))
for i := range 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) ctx.JSON(200, &results)

View File

@@ -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 // description: search only for repos that the user with the given id owns or contributes to
// type: integer // type: integer
// format: int64 // 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 // - name: page
// in: query // in: query
// description: page number of results to return (1-based) // description: page number of results to return (1-based)
@@ -95,6 +104,10 @@ func Search(ctx *context.APIContext) {
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")), PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
TopicOnly: ctx.QueryBool("topic"), TopicOnly: ctx.QueryBool("topic"),
Collaborate: util.OptionalBoolNone, 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") { if ctx.QueryBool("exclusive") {
@@ -139,42 +152,6 @@ func Search(ctx *context.APIContext) {
} }
var err error 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) repos, count, err := models.SearchRepositoryByName(opts)
if err != nil { if err != nil {
ctx.JSON(500, api.SearchError{ ctx.JSON(500, api.SearchError{

View File

@@ -67,7 +67,7 @@ func Search(ctx *context.APIContext) {
results := make([]*api.User, len(users)) results := make([]*api.User, len(users))
for i := range 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{}{ ctx.JSON(200, map[string]interface{}{

View File

@@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/mailer" "code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/ssh" "code.gitea.io/gitea/modules/ssh"
@@ -75,6 +76,7 @@ func GlobalInit() {
if setting.InstallLock { if setting.InstallLock {
highlight.NewContext() highlight.NewContext()
external.RegisterParsers()
markup.Init() markup.Init()
if err := initDBEngine(); err == nil { if err := initDBEngine(); err == nil {
log.Info("ORM engine initialization successful!") log.Info("ORM engine initialization successful!")

View File

@@ -213,8 +213,31 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
return 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. // Check admin password.
if len(form.AdminName) > 0 && len(form.AdminPasswd) == 0 { if len(form.AdminPasswd) == 0 {
ctx.Data["Err_Admin"] = true ctx.Data["Err_Admin"] = true
ctx.Data["Err_AdminPasswd"] = true ctx.Data["Err_AdminPasswd"] = true
ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form) ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form)
@@ -226,6 +249,7 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form) ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form)
return return
} }
}
if form.AppURL[len(form.AppURL)-1] != '/' { if form.AppURL[len(form.AppURL)-1] != '/' {
form.AppURL += "/" form.AppURL += "/"

View File

@@ -406,6 +406,7 @@ func NewIssue(ctx *context.Context) {
ctx.Data["BodyQuery"] = body ctx.Data["BodyQuery"] = body
milestoneID := ctx.QueryInt64("milestone") milestoneID := ctx.QueryInt64("milestone")
if milestoneID > 0 {
milestone, err := models.GetMilestoneByID(milestoneID) milestone, err := models.GetMilestoneByID(milestoneID)
if err != nil { if err != nil {
log.Error(4, "GetMilestoneByID: %d: %v", milestoneID, err) log.Error(4, "GetMilestoneByID: %d: %v", milestoneID, err)
@@ -413,6 +414,7 @@ func NewIssue(ctx *context.Context) {
ctx.Data["milestone_id"] = milestoneID ctx.Data["milestone_id"] = milestoneID
ctx.Data["Milestone"] = milestone ctx.Data["Milestone"] = milestone
} }
}
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
renderAttachmentSettings(ctx) renderAttachmentSettings(ctx)

View File

@@ -578,7 +578,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}) })
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef()) }, 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("/:username/:reponame", func() {
m.Group("/issues", func() { m.Group("/issues", func() {
@@ -827,7 +827,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/", lfs.PostLockHandler) m.Post("/", lfs.PostLockHandler)
m.Post("/verify", lfs.VerifyLockHandler) m.Post("/verify", lfs.VerifyLockHandler)
m.Post("/:lid/unlock", lfs.UnLockHandler) m.Post("/:lid/unlock", lfs.UnLockHandler)
}, context.RepoAssignment()) })
m.Any("/*", func(ctx *context.Context) { m.Any("/*", func(ctx *context.Context) {
ctx.NotFound("", nil) ctx.NotFound("", nil)
}) })

View File

@@ -435,41 +435,13 @@ func showOrgProfile(ctx *context.Context) {
count int64 count int64
err error 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{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: org.ID, OwnerID: org.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
IsProfile: true, IsProfile: true,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
@@ -478,8 +450,6 @@ func showOrgProfile(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByName", err) ctx.ServerError("SearchRepositoryByName", err)
return return
} }
}
}
if err := org.GetMembers(); err != nil { if err := org.GetMembers(); err != nil {
ctx.ServerError("GetMembers", err) ctx.ServerError("GetMembers", err)

View File

@@ -259,7 +259,7 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) {
ctx.Data["Application"] = app ctx.Data["Application"] = app
ctx.Data["RedirectURI"] = form.RedirectURI ctx.Data["RedirectURI"] = form.RedirectURI
ctx.Data["State"] = form.State 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>" ctx.Data["ApplicationRedirectDomainHTML"] = "<strong>" + form.RedirectURI + "</strong>"
// TODO document SESSION <=> FORM // TODO document SESSION <=> FORM
ctx.Session.Set("client_id", app.ClientID) ctx.Session.Set("client_id", app.ClientID)

View File

@@ -158,27 +158,15 @@ func Profile(ctx *context.Context) {
} }
case "stars": case "stars":
ctx.Data["PageIsProfileStarList"] = true 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{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: ctxUser.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
Starred: true, StarredByID: ctxUser.ID,
Collaborate: util.OptionalBoolFalse, Collaborate: util.OptionalBoolFalse,
TopicOnly: topicOnly, TopicOnly: topicOnly,
}) })
@@ -186,40 +174,18 @@ func Profile(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByName", err) ctx.ServerError("SearchRepositoryByName", err)
return return
} }
}
ctx.Data["Repos"] = repos ctx.Data["Repos"] = repos
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
ctx.Data["Total"] = count ctx.Data["Total"] = count
default: 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{ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: ctxUser.ID, OwnerID: ctxUser.ID,
OrderBy: orderBy, OrderBy: orderBy,
Private: showPrivate, Private: ctx.IsSigned,
UserIsAdmin: ctx.IsSigned && ctx.User.IsAdmin,
UserID: ctx.Data["SignedUserID"].(int64),
Page: page, Page: page,
IsProfile: true, IsProfile: true,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
@@ -230,12 +196,10 @@ func Profile(ctx *context.Context) {
ctx.ServerError("SearchRepositoryByName", err) ctx.ServerError("SearchRepositoryByName", err)
return return
} }
ctx.Data["Repos"] = repos ctx.Data["Repos"] = repos
ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) ctx.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
ctx.Data["Total"] = count ctx.Data["Total"] = count
} }
}
ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.User.ID) ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.User.ID)

View File

@@ -1085,6 +1085,19 @@
"name": "uid", "name": "uid",
"in": "query" "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", "type": "integer",
"description": "page number of results to return (1-based)", "description": "page number of results to return (1-based)",