Merge remote-tracking branch 'upstream/main'
commit
26f57be49c
|
@ -40,7 +40,7 @@ linters-settings:
|
|||
stylecheck:
|
||||
checks: ["all", "-ST1005", "-ST1003"]
|
||||
nakedret:
|
||||
max-func-lines: 0
|
||||
max-func-lines: 0
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- ifElseChain
|
||||
|
@ -86,6 +86,8 @@ linters-settings:
|
|||
- github.com/unknwon/com: "use gitea's util and replacements"
|
||||
|
||||
issues:
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
exclude-rules:
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -64,8 +64,8 @@ func main() {
|
|||
}
|
||||
|
||||
entries = append(entries, LicenseEntry{
|
||||
Name: name,
|
||||
Path: path,
|
||||
Name: name,
|
||||
Path: path,
|
||||
LicenseText: string(licenseText),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ const (
|
|||
var CmdServ = cli.Command{
|
||||
Name: "serv",
|
||||
Usage: "This command should only be called by SSH shell",
|
||||
Description: `Serv provide access auth for repositories`,
|
||||
Description: "Serv provides access auth for repositories",
|
||||
Action: runServ,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
|
|
|
@ -2153,7 +2153,7 @@ ROUTER = console
|
|||
;[api]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Enables Swagger. True or false; default is true.
|
||||
;; Enables the API documentation endpoints (/api/swagger, /api/v1/swagger, …). True or false.
|
||||
;ENABLE_SWAGGER = true
|
||||
;; Max number of items in a page
|
||||
;MAX_RESPONSE_ITEMS = 50
|
||||
|
@ -2161,7 +2161,7 @@ ROUTER = console
|
|||
;DEFAULT_PAGING_NUM = 30
|
||||
;; Default and maximum number of items per page for git trees api
|
||||
;DEFAULT_GIT_TREES_PER_PAGE = 1000
|
||||
;; Default size of a blob returned by the blobs API (default is 10MiB)
|
||||
;; Default max size of a blob returned by the blobs API (default is 10MiB)
|
||||
;DEFAULT_MAX_BLOB_SIZE = 10485760
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -1015,11 +1015,11 @@ Default templates for project boards:
|
|||
|
||||
## API (`api`)
|
||||
|
||||
- `ENABLE_SWAGGER`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
|
||||
- `ENABLE_SWAGGER`: **true**: Enables the API documentation endpoints (`/api/swagger`, `/api/v1/swagger`, …). True or false.
|
||||
- `MAX_RESPONSE_ITEMS`: **50**: Max number of items in a page.
|
||||
- `DEFAULT_PAGING_NUM`: **30**: Default paging number of API.
|
||||
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: Default and maximum number of items per page for Git trees API.
|
||||
- `DEFAULT_MAX_BLOB_SIZE`: **10485760**: Default max size of a blob that can be return by the blobs API.
|
||||
- `DEFAULT_MAX_BLOB_SIZE`: **10485760** (10MiB): Default max size of a blob that can be returned by the blobs API.
|
||||
|
||||
## OAuth2 (`oauth2`)
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ test01.xls: application/vnd.ms-excel; charset=binary
|
|||
|
||||
## API (`api`)
|
||||
|
||||
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 /api/swagger, /api/v1/swagger etc. endpoints. True 或 false; 默认是 true.
|
||||
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 /api/swagger, /api/v1/swagger etc. endpoints. True 或 false.
|
||||
- `MAX_RESPONSE_ITEMS`: **50**: 一个页面最大的项目数。
|
||||
- `DEFAULT_PAGING_NUM`: **30**: API中默认分页条数。
|
||||
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: GIT TREES API每页的默认最大项数.
|
||||
|
|
|
@ -126,13 +126,13 @@ A "login prohibited" user is a user that is not allowed to log in to Gitea anymo
|
|||
|
||||
## What is Swagger?
|
||||
|
||||
[Swagger](https://swagger.io/) is what Gitea uses for its API.
|
||||
[Swagger](https://swagger.io/) is what Gitea uses for its API documentation.
|
||||
|
||||
All Gitea instances have the built-in API, though it can be disabled by setting `ENABLE_SWAGGER` to `false` in the `api` section of your `app.ini`
|
||||
All Gitea instances have the built-in API and there is no way to disable it completely.
|
||||
You can, however, disable showing its documentation by setting `ENABLE_SWAGGER` to `false` in the `api` section of your `app.ini`.
|
||||
For more information, refer to Gitea's [API docs]({{< relref "doc/developers/api-usage.en-us.md" >}}).
|
||||
|
||||
For more information, refer to Gitea's [API docs]({{< relref "doc/developers/api-usage.en-us.md" >}})
|
||||
|
||||
[Swagger Example](https://try.gitea.io/api/swagger)
|
||||
You can see the latest API (for example) on <https://try.gitea.io/api/swagger>.
|
||||
|
||||
## Adjusting your server for public/private use
|
||||
|
||||
|
|
|
@ -218,6 +218,11 @@ func (a *Action) GetRepoLink() string {
|
|||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
||||
}
|
||||
|
||||
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
||||
func (a *Action) GetRepoAbsoluteLink() string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
||||
}
|
||||
|
||||
// GetCommentLink returns link to action comment.
|
||||
func (a *Action) GetCommentLink() string {
|
||||
return a.getCommentLink(db.DefaultContext)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issue_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -20,7 +21,7 @@ import (
|
|||
|
||||
func TestAction_GetRepoPath(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
action := &activities_model.Action{RepoID: repo.ID}
|
||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
||||
|
@ -28,12 +29,15 @@ func TestAction_GetRepoPath(t *testing.T) {
|
|||
|
||||
func TestAction_GetRepoLink(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
action := &activities_model.Action{RepoID: repo.ID}
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2})
|
||||
action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||
setting.AppSubURL = "/suburl"
|
||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||
assert.Equal(t, expected, action.GetRepoLink())
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
||||
assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
|
||||
}
|
||||
|
||||
func TestGetFeeds(t *testing.T) {
|
||||
|
|
|
@ -124,3 +124,15 @@
|
|||
repo_id: 24
|
||||
mode: 1
|
||||
|
||||
-
|
||||
id: 22
|
||||
user_id: 31
|
||||
repo_id: 27
|
||||
mode: 4
|
||||
|
||||
-
|
||||
id: 23
|
||||
user_id: 31
|
||||
repo_id: 28
|
||||
mode: 4
|
||||
|
||||
|
|
|
@ -12,3 +12,8 @@
|
|||
id: 3
|
||||
user_id: 2
|
||||
follow_id: 8
|
||||
|
||||
-
|
||||
id: 4
|
||||
user_id: 31
|
||||
follow_id: 33
|
||||
|
|
|
@ -69,3 +69,9 @@
|
|||
uid: 2
|
||||
org_id: 17
|
||||
is_public: true
|
||||
|
||||
-
|
||||
id: 13
|
||||
uid: 31
|
||||
org_id: 19
|
||||
is_public: true
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
name: Owners
|
||||
authorize: 4 # owner
|
||||
num_repos: 2
|
||||
num_members: 1
|
||||
num_members: 2
|
||||
can_create_org_repo: true
|
||||
|
||||
-
|
||||
|
|
|
@ -87,3 +87,9 @@
|
|||
org_id: 17
|
||||
team_id: 9
|
||||
uid: 29
|
||||
|
||||
-
|
||||
id: 16
|
||||
org_id: 19
|
||||
team_id: 6
|
||||
uid: 31
|
||||
|
|
|
@ -345,7 +345,7 @@
|
|||
avatar_email: user19@example.com
|
||||
num_repos: 2
|
||||
is_active: true
|
||||
num_members: 1
|
||||
num_members: 2
|
||||
num_teams: 1
|
||||
|
||||
-
|
||||
|
@ -572,6 +572,8 @@
|
|||
avatar: avatar31
|
||||
avatar_email: user31@example.com
|
||||
num_repos: 0
|
||||
num_followers: 0
|
||||
num_following: 1
|
||||
is_active: true
|
||||
|
||||
-
|
||||
|
@ -590,3 +592,23 @@
|
|||
avatar_email: user30@example.com
|
||||
num_repos: 0
|
||||
is_active: true
|
||||
|
||||
-
|
||||
id: 33
|
||||
lower_name: user33
|
||||
name: user33
|
||||
login_name: user33
|
||||
full_name: User 33 (Limited Visibility)
|
||||
email: user33@example.com
|
||||
passwd_hash_algo: argon2
|
||||
passwd: a3d5fcd92bae586c2e3dbe72daea7a0d27833a8d0227aa1704f4bbd775c1f3b03535b76dd93b0d4d8d22a519dca47df1547b # password
|
||||
type: 0 # individual
|
||||
salt: ZogKvWdyEx
|
||||
is_admin: false
|
||||
visibility: 1
|
||||
avatar: avatar33
|
||||
avatar_email: user33@example.com
|
||||
num_repos: 0
|
||||
num_followers: 1
|
||||
num_following: 0
|
||||
is_active: true
|
||||
|
|
|
@ -181,6 +181,10 @@ func createReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, erro
|
|||
Reaction: opts.Type,
|
||||
UserID: opts.DoerID,
|
||||
}
|
||||
if findOpts.CommentID == 0 {
|
||||
// explicit search of Issue Reactions where CommentID = 0
|
||||
findOpts.CommentID = -1
|
||||
}
|
||||
|
||||
existingR, _, err := FindReactions(ctx, findOpts)
|
||||
if err != nil {
|
||||
|
@ -256,16 +260,23 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
|
|||
CommentID: opts.CommentID,
|
||||
}
|
||||
|
||||
_, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction)
|
||||
sess := db.GetEngine(ctx).Where("original_author_id = 0")
|
||||
if opts.CommentID == -1 {
|
||||
reaction.CommentID = 0
|
||||
sess.MustCols("comment_id")
|
||||
}
|
||||
|
||||
_, err := sess.Delete(reaction)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteIssueReaction deletes a reaction on issue.
|
||||
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
CommentID: -1,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -129,29 +129,11 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
|||
if opts.UserID > 0 {
|
||||
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
|
||||
}
|
||||
|
||||
count, err := sess.
|
||||
Where(cond).
|
||||
Count(new(Team))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if opts.UserID > 0 {
|
||||
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
|
||||
}
|
||||
|
||||
if opts.PageSize == -1 {
|
||||
opts.PageSize = int(count)
|
||||
} else {
|
||||
sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
|
||||
}
|
||||
sess = db.SetSessionPagination(sess, opts)
|
||||
|
||||
teams := make([]*Team, 0, opts.PageSize)
|
||||
if err = sess.
|
||||
Where(cond).
|
||||
OrderBy("lower_name").
|
||||
Find(&teams); err != nil {
|
||||
count, err := sess.Where(cond).OrderBy("lower_name").FindAndCount(&teams)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
|
|
|
@ -1267,7 +1267,7 @@ func isUserVisibleToViewerCond(viewer *User) builder.Cond {
|
|||
|
||||
// IsUserVisibleToViewer check if viewer is able to see user profile
|
||||
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||
if viewer != nil && viewer.IsAdmin {
|
||||
if viewer != nil && (viewer.IsAdmin || viewer.ID == u.ID) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1306,7 +1306,7 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
if count < 0 {
|
||||
if count == 0 {
|
||||
// No common organization
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -400,3 +400,56 @@ func TestUnfollowUser(t *testing.T) {
|
|||
|
||||
unittest.CheckConsistencyFor(t, &user_model.User{})
|
||||
}
|
||||
|
||||
func TestIsUserVisibleToViewer(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) // admin, public
|
||||
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // normal, public
|
||||
user20 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) // public, same team as user31
|
||||
user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) // public, is restricted
|
||||
user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31}) // private, same team as user20
|
||||
user33 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 33}) // limited, follows 31
|
||||
|
||||
test := func(u, viewer *user_model.User, expected bool) {
|
||||
name := func(u *user_model.User) string {
|
||||
if u == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return u.Name
|
||||
}
|
||||
assert.Equal(t, expected, user_model.IsUserVisibleToViewer(db.DefaultContext, u, viewer), "user %v should be visible to viewer %v: %v", name(u), name(viewer), expected)
|
||||
}
|
||||
|
||||
// admin viewer
|
||||
test(user1, user1, true)
|
||||
test(user20, user1, true)
|
||||
test(user31, user1, true)
|
||||
test(user33, user1, true)
|
||||
|
||||
// non admin viewer
|
||||
test(user4, user4, true)
|
||||
test(user20, user4, true)
|
||||
test(user31, user4, false)
|
||||
test(user33, user4, true)
|
||||
test(user4, nil, true)
|
||||
|
||||
// public user
|
||||
test(user4, user20, true)
|
||||
test(user4, user31, true)
|
||||
test(user4, user33, true)
|
||||
|
||||
// limited user
|
||||
test(user33, user33, true)
|
||||
test(user33, user4, true)
|
||||
test(user33, user29, false)
|
||||
test(user33, nil, false)
|
||||
|
||||
// private user
|
||||
test(user31, user31, true)
|
||||
test(user31, user4, false)
|
||||
test(user31, user20, true)
|
||||
test(user31, user29, false)
|
||||
test(user31, user33, true)
|
||||
test(user31, nil, false)
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
)
|
||||
|
@ -54,47 +55,11 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
|||
Owner: ctx.ContextUser,
|
||||
}
|
||||
|
||||
if ctx.Package.Owner.IsOrganization() {
|
||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||
|
||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
||||
if ctx.Doer != nil {
|
||||
var err error
|
||||
ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
|
||||
return
|
||||
}
|
||||
// If access mode is less than write check every team for more permissions
|
||||
if ctx.Package.AccessMode < perm.AccessModeWrite {
|
||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "GetUserOrgTeams", err)
|
||||
return
|
||||
}
|
||||
for _, t := range teams {
|
||||
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
||||
if ctx.Package.AccessMode < perm {
|
||||
ctx.Package.AccessMode = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. If authorize level is none, check if org is visible to user
|
||||
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
} else {
|
||||
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||
// 1. Check if user is package owner
|
||||
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
||||
ctx.Package.AccessMode = perm.AccessModeOwner
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
var err error
|
||||
ctx.Package.AccessMode, err = determineAccessMode(ctx)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "determineAccessMode", err)
|
||||
return
|
||||
}
|
||||
|
||||
packageType := ctx.Params("type")
|
||||
|
@ -119,6 +84,57 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
|||
}
|
||||
}
|
||||
|
||||
func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
|
||||
accessMode := perm.AccessModeNone
|
||||
|
||||
if setting.Service.RequireSignInView && ctx.Doer == nil {
|
||||
return accessMode, nil
|
||||
}
|
||||
|
||||
if ctx.Package.Owner.IsOrganization() {
|
||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||
|
||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
||||
if ctx.Doer != nil {
|
||||
var err error
|
||||
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
return accessMode, err
|
||||
}
|
||||
// If access mode is less than write check every team for more permissions
|
||||
if accessMode < perm.AccessModeWrite {
|
||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
return accessMode, err
|
||||
}
|
||||
for _, t := range teams {
|
||||
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
||||
if accessMode < perm {
|
||||
accessMode = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. If authorize level is none, check if org is visible to user
|
||||
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
} else {
|
||||
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||
// 1. Check if user is package owner
|
||||
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
||||
accessMode = perm.AccessModeOwner
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
}
|
||||
|
||||
return accessMode, nil
|
||||
}
|
||||
|
||||
// PackageContexter initializes a package context for a request.
|
||||
func PackageContexter(ctx gocontext.Context) func(next http.Handler) http.Handler {
|
||||
_, rnd := templates.HTMLRenderer(ctx)
|
||||
|
|
|
@ -44,7 +44,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
|||
case "160000":
|
||||
entry.entryMode = EntryModeCommit
|
||||
pos += 14 // skip over "160000 object "
|
||||
case "040000":
|
||||
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
|
||||
entry.entryMode = EntryModeTree
|
||||
pos += 12 // skip over "040000 tree "
|
||||
default:
|
||||
|
@ -119,7 +119,7 @@ loop:
|
|||
entry.entryMode = EntryModeSymlink
|
||||
case "160000":
|
||||
entry.entryMode = EntryModeCommit
|
||||
case "40000":
|
||||
case "40000", "40755": // git uses 40000 for tree object, but some users may get 40755 for unknown reasons
|
||||
entry.entryMode = EntryModeTree
|
||||
default:
|
||||
log.Debug("Unknown mode: %v", string(mode))
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/yuin/goldmark/ast"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
|
@ -337,13 +336,6 @@ func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error
|
|||
func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
||||
repo.LowerName = strings.ToLower(repo.Name)
|
||||
|
||||
if utf8.RuneCountInString(repo.Description) > 255 {
|
||||
repo.Description = string([]rune(repo.Description)[:255])
|
||||
}
|
||||
if utf8.RuneCountInString(repo.Website) > 255 {
|
||||
repo.Website = string([]rune(repo.Website)[:255])
|
||||
}
|
||||
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
|
||||
|
|
|
@ -111,7 +111,7 @@ type CreateRepoOption struct {
|
|||
// unique: true
|
||||
Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
// Description of the repository to create
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Description string `json:"description" binding:"MaxSize(2048)"`
|
||||
// Whether the repository is private
|
||||
Private bool `json:"private"`
|
||||
// Label-Set to use
|
||||
|
@ -140,9 +140,9 @@ type EditRepoOption struct {
|
|||
// unique: true
|
||||
Name *string `json:"name,omitempty" binding:"OmitEmpty;AlphaDashDot;MaxSize(100);"`
|
||||
// a short description of the repository.
|
||||
Description *string `json:"description,omitempty" binding:"MaxSize(255)"`
|
||||
Description *string `json:"description,omitempty" binding:"MaxSize(2048)"`
|
||||
// a URL with more information about the repository.
|
||||
Website *string `json:"website,omitempty" binding:"MaxSize(255)"`
|
||||
Website *string `json:"website,omitempty" binding:"MaxSize(1024)"`
|
||||
// either `true` to make the repository private or `false` to make it public.
|
||||
// Note: you will get a 422 error if the organization restricts changing repository visibility to organization
|
||||
// owners and a non-owner tries to change the value of private.
|
||||
|
@ -208,7 +208,7 @@ type GenerateRepoOption struct {
|
|||
// Default branch of the new repository
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
// Description of the repository to create
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Description string `json:"description" binding:"MaxSize(2048)"`
|
||||
// Whether the repository is private
|
||||
Private bool `json:"private"`
|
||||
// include git content of default branch in template repo
|
||||
|
@ -316,7 +316,7 @@ type MigrateRepoOptions struct {
|
|||
LFS bool `json:"lfs"`
|
||||
LFSEndpoint string `json:"lfs_endpoint"`
|
||||
Private bool `json:"private"`
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Description string `json:"description" binding:"MaxSize(2048)"`
|
||||
Wiki bool `json:"wiki"`
|
||||
Milestones bool `json:"milestones"`
|
||||
Labels bool `json:"labels"`
|
||||
|
|
|
@ -377,17 +377,17 @@ func NewFuncMap() []template.FuncMap {
|
|||
return ""
|
||||
},
|
||||
"RenderLabels": func(labels []*issues_model.Label, repoLink string) template.HTML {
|
||||
html := `<span class="labels-list">`
|
||||
htmlCode := `<span class="labels-list">`
|
||||
for _, label := range labels {
|
||||
// Protect against nil value in labels - shouldn't happen but would cause a panic if so
|
||||
if label == nil {
|
||||
continue
|
||||
}
|
||||
html += fmt.Sprintf("<a href='%s/issues?labels=%d' class='ui label' style='color: %s !important; background-color: %s !important'>%s</a> ",
|
||||
repoLink, label.ID, label.ForegroundColor(), label.Color, RenderEmoji(label.Name))
|
||||
htmlCode += fmt.Sprintf("<a href='%s/issues?labels=%d' class='ui label' style='color: %s !important; background-color: %s !important' title='%s'>%s</a> ",
|
||||
repoLink, label.ID, label.ForegroundColor(), label.Color, html.EscapeString(label.Description), RenderEmoji(label.Name))
|
||||
}
|
||||
html += "</span>"
|
||||
return template.HTML(html)
|
||||
htmlCode += "</span>"
|
||||
return template.HTML(htmlCode)
|
||||
},
|
||||
"MermaidMaxSourceCharacters": func() int {
|
||||
return setting.MermaidMaxSourceCharacters
|
||||
|
|
|
@ -3092,6 +3092,7 @@ container.details.platform=Plataforma
|
|||
container.details.repository_site=Página web do repositório
|
||||
container.details.documentation_site=Página web da documentação
|
||||
container.pull=Puxar a imagem usando a linha de comandos:
|
||||
container.digest=Resumo:
|
||||
container.documentation=Para obter mais informações sobre o registo do Container, consulte <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/container/">a documentação</a>.
|
||||
container.multi_arch=S.O. / Arquit.
|
||||
container.layers=Camadas de imagem
|
||||
|
|
|
@ -759,13 +759,17 @@ func SearchTeam(ctx *context.APIContext) {
|
|||
listOptions := utils.GetListOptions(ctx)
|
||||
|
||||
opts := &organization.SearchTeamOptions{
|
||||
UserID: ctx.Doer.ID,
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
OrgID: ctx.Org.Organization.ID,
|
||||
IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"),
|
||||
ListOptions: listOptions,
|
||||
}
|
||||
|
||||
// Only admin is allowd to search for all teams
|
||||
if !ctx.Doer.IsAdmin {
|
||||
opts.UserID = ctx.Doer.ID
|
||||
}
|
||||
|
||||
teams, maxResults, err := organization.SearchTeam(opts)
|
||||
if err != nil {
|
||||
log.Error("SearchTeam failed: %v", err)
|
||||
|
|
|
@ -24,27 +24,27 @@ import (
|
|||
)
|
||||
|
||||
func toBranchLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch())
|
||||
return act.GetRepoAbsoluteLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch())
|
||||
}
|
||||
|
||||
func toTagLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag())
|
||||
return act.GetRepoAbsoluteLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag())
|
||||
}
|
||||
|
||||
func toIssueLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||
return act.GetRepoAbsoluteLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||
}
|
||||
|
||||
func toPullLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||
return act.GetRepoAbsoluteLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||
}
|
||||
|
||||
func toSrcLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/src/" + util.PathEscapeSegments(act.GetBranch())
|
||||
return act.GetRepoAbsoluteLink() + "/src/" + util.PathEscapeSegments(act.GetBranch())
|
||||
}
|
||||
|
||||
func toReleaseLink(act *activities_model.Action) string {
|
||||
return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
|
||||
return act.GetRepoAbsoluteLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
|
||||
}
|
||||
|
||||
// renderMarkdown creates a minimal markdown render context from an action.
|
||||
|
@ -79,17 +79,17 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
title = act.ActUser.DisplayName() + " "
|
||||
switch act.OpType {
|
||||
case activities_model.ActionCreateRepo:
|
||||
title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoLink(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
case activities_model.ActionRenameRepo:
|
||||
title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
case activities_model.ActionCommitRepo:
|
||||
link.Href = toBranchLink(act)
|
||||
if len(act.Content) != 0 {
|
||||
title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||
title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||
} else {
|
||||
title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||
title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||
}
|
||||
case activities_model.ActionCreateIssue:
|
||||
link.Href = toIssueLink(act)
|
||||
|
@ -98,11 +98,11 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
link.Href = toPullLink(act)
|
||||
title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||
case activities_model.ActionTransferRepo:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||
case activities_model.ActionPushTag:
|
||||
link.Href = toTagLink(act)
|
||||
title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoLink(), link.Href, act.GetTag(), act.ShortRepoPath())
|
||||
title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(), link.Href, act.GetTag(), act.ShortRepoPath())
|
||||
case activities_model.ActionCommentIssue:
|
||||
issueLink := toIssueLink(act)
|
||||
if link.Href == "#" {
|
||||
|
@ -140,26 +140,26 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
}
|
||||
title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||
case activities_model.ActionDeleteTag:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoLink(), act.GetTag(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(), act.GetTag(), act.ShortRepoPath())
|
||||
case activities_model.ActionDeleteBranch:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
|
||||
case activities_model.ActionMirrorSyncPush:
|
||||
srcLink := toSrcLink(act)
|
||||
if link.Href == "#" {
|
||||
link.Href = srcLink
|
||||
}
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||
case activities_model.ActionMirrorSyncCreate:
|
||||
srcLink := toSrcLink(act)
|
||||
if link.Href == "#" {
|
||||
link.Href = srcLink
|
||||
}
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||
case activities_model.ActionMirrorSyncDelete:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoLink(), act.GetBranch(), act.ShortRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(), act.GetBranch(), act.ShortRepoPath())
|
||||
case activities_model.ActionApprovePullRequest:
|
||||
pullLink := toPullLink(act)
|
||||
title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||
|
@ -174,16 +174,16 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
if link.Href == "#" {
|
||||
link.Href = releaseLink
|
||||
}
|
||||
title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoLink(), releaseLink, act.ShortRepoPath(), act.Content)
|
||||
title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(), releaseLink, act.ShortRepoPath(), act.Content)
|
||||
case activities_model.ActionPullReviewDismissed:
|
||||
pullLink := toPullLink(act)
|
||||
title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1])
|
||||
case activities_model.ActionStarRepo:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoLink(), act.GetRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath())
|
||||
case activities_model.ActionWatchRepo:
|
||||
link.Href = act.GetRepoLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoLink(), act.GetRepoPath())
|
||||
link.Href = act.GetRepoAbsoluteLink()
|
||||
title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath())
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
|
||||
}
|
||||
|
@ -193,14 +193,14 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
switch act.OpType {
|
||||
case activities_model.ActionCommitRepo, activities_model.ActionMirrorSyncPush:
|
||||
push := templates.ActionContent2Commits(act)
|
||||
repoLink := act.GetRepoLink()
|
||||
repoLink := act.GetRepoAbsoluteLink()
|
||||
|
||||
for _, commit := range push.Commits {
|
||||
if len(desc) != 0 {
|
||||
desc += "\n\n"
|
||||
}
|
||||
desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s",
|
||||
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), commit.Sha1)),
|
||||
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), commit.Sha1)),
|
||||
commit.Sha1,
|
||||
templates.RenderCommitMessage(ctx, commit.Message, repoLink, nil),
|
||||
)
|
||||
|
@ -209,7 +209,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
|||
if push.Len > 1 {
|
||||
link = &feeds.Link{Href: fmt.Sprintf("%s/%s", setting.AppSubURL, push.CompareURL)}
|
||||
} else if push.Len == 1 {
|
||||
link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), push.Commits[0].Sha1)}
|
||||
link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), push.Commits[0].Sha1)}
|
||||
}
|
||||
|
||||
case activities_model.ActionCreateIssue, activities_model.ActionCreatePullRequest:
|
||||
|
|
|
@ -112,17 +112,17 @@ func setCsvCompareContext(ctx *context.Context) {
|
|||
Error string
|
||||
}
|
||||
|
||||
ctx.Data["CreateCsvDiff"] = func(diffFile *gitdiff.DiffFile, baseCommit, headCommit *git.Commit) CsvDiffResult {
|
||||
if diffFile == nil || baseCommit == nil || headCommit == nil {
|
||||
ctx.Data["CreateCsvDiff"] = func(diffFile *gitdiff.DiffFile, baseBlob, headBlob *git.Blob) CsvDiffResult {
|
||||
if diffFile == nil {
|
||||
return CsvDiffResult{nil, ""}
|
||||
}
|
||||
|
||||
errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
|
||||
|
||||
csvReaderFromCommit := func(ctx *markup.RenderContext, c *git.Commit) (*csv.Reader, io.Closer, error) {
|
||||
blob, err := c.GetBlobByPath(diffFile.Name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
csvReaderFromCommit := func(ctx *markup.RenderContext, blob *git.Blob) (*csv.Reader, io.Closer, error) {
|
||||
if blob == nil {
|
||||
// It's ok for blob to be nil (file added or deleted)
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < blob.Size() {
|
||||
|
@ -138,28 +138,28 @@ func setCsvCompareContext(ctx *context.Context) {
|
|||
return csvReader, reader, err
|
||||
}
|
||||
|
||||
baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseCommit)
|
||||
baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseBlob)
|
||||
if baseBlobCloser != nil {
|
||||
defer baseBlobCloser.Close()
|
||||
}
|
||||
if err == errTooLarge {
|
||||
return CsvDiffResult{nil, err.Error()}
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("CreateCsvDiff error whilst creating baseReader from file %s in commit %s in %s: %v", diffFile.Name, baseCommit.ID.String(), ctx.Repo.Repository.Name, err)
|
||||
return CsvDiffResult{nil, "unable to load file from base commit"}
|
||||
if err == errTooLarge {
|
||||
return CsvDiffResult{nil, err.Error()}
|
||||
}
|
||||
log.Error("error whilst creating csv.Reader from file %s in base commit %s in %s: %v", diffFile.Name, baseBlob.ID.String(), ctx.Repo.Repository.Name, err)
|
||||
return CsvDiffResult{nil, "unable to load file"}
|
||||
}
|
||||
|
||||
headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headCommit)
|
||||
headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headBlob)
|
||||
if headBlobCloser != nil {
|
||||
defer headBlobCloser.Close()
|
||||
}
|
||||
if err == errTooLarge {
|
||||
return CsvDiffResult{nil, err.Error()}
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("CreateCsvDiff error whilst creating headReader from file %s in commit %s in %s: %v", diffFile.Name, headCommit.ID.String(), ctx.Repo.Repository.Name, err)
|
||||
return CsvDiffResult{nil, "unable to load file from head commit"}
|
||||
if err == errTooLarge {
|
||||
return CsvDiffResult{nil, err.Error()}
|
||||
}
|
||||
log.Error("error whilst creating csv.Reader from file %s in head commit %s in %s: %v", diffFile.Name, headBlob.ID.String(), ctx.Repo.Repository.Name, err)
|
||||
return CsvDiffResult{nil, "unable to load file"}
|
||||
}
|
||||
|
||||
sections, err := gitdiff.CreateCsvDiff(diffFile, baseReader, headReader)
|
||||
|
|
|
@ -34,7 +34,7 @@ type CreateRepoForm struct {
|
|||
UID int64 `binding:"Required"`
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Private bool
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Description string `binding:"MaxSize(2048)"`
|
||||
DefaultBranch string `binding:"GitRefName;MaxSize(100)"`
|
||||
AutoInit bool
|
||||
Gitignores string
|
||||
|
@ -76,7 +76,7 @@ type MigrateRepoForm struct {
|
|||
LFS bool `json:"lfs"`
|
||||
LFSEndpoint string `json:"lfs_endpoint"`
|
||||
Private bool `json:"private"`
|
||||
Description string `json:"description" binding:"MaxSize(255)"`
|
||||
Description string `json:"description" binding:"MaxSize(2048)"`
|
||||
Wiki bool `json:"wiki"`
|
||||
Milestones bool `json:"milestones"`
|
||||
Labels bool `json:"labels"`
|
||||
|
@ -116,8 +116,8 @@ func ParseRemoteAddr(remoteAddr, authUsername, authPassword string) (string, err
|
|||
// RepoSettingForm form for changing repository settings
|
||||
type RepoSettingForm struct {
|
||||
RepoName string `binding:"Required;AlphaDashDot;MaxSize(100)"`
|
||||
Description string `binding:"MaxSize(255)"`
|
||||
Website string `binding:"ValidUrl;MaxSize(255)"`
|
||||
Description string `binding:"MaxSize(2048)"`
|
||||
Website string `binding:"ValidUrl;MaxSize(1024)"`
|
||||
Interval string
|
||||
MirrorAddress string
|
||||
MirrorUsername string
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
<tbody>
|
||||
{{range .Queue.Workers}}
|
||||
<tr>
|
||||
<td>{{.Workers}}{{if .IsFlusher}}<span title="{{.locale.Tr "admin.monitor.queue.flush"}}">{{svg "octicon-sync"}}</span>{{end}}</td>
|
||||
<td>{{.Workers}}{{if .IsFlusher}}<span title="{{$.locale.Tr "admin.monitor.queue.flush"}}">{{svg "octicon-sync"}}</span>{{end}}</td>
|
||||
<td>{{DateFmtLong .Start}}</td>
|
||||
<td>{{if .HasTimeout}}{{DateFmtLong .Timeout}}{{else}}-{{end}}</td>
|
||||
<td>
|
||||
|
|
|
@ -57,7 +57,8 @@
|
|||
{{end}}
|
||||
</ol>
|
||||
<div id="diff-file-boxes">
|
||||
{{range $i, $file := .Diff.Files}}
|
||||
{{range $file := .Diff.Files}}
|
||||
{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}}
|
||||
{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}}
|
||||
{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
|
||||
{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
|
||||
|
@ -93,8 +94,8 @@
|
|||
<div class="diff-file-header-actions df ac">
|
||||
{{if $showFileViewToggle}}
|
||||
<div class="ui compact icon buttons">
|
||||
<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$i}}" data-content="{{$.locale.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span>
|
||||
<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$i}}" data-content="{{$.locale.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span>
|
||||
<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span>
|
||||
<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if $file.IsProtected}}
|
||||
|
@ -115,15 +116,14 @@
|
|||
{{if $file.HasChangedSinceLastReview}}
|
||||
<span class="changed-since-last-review unselectable">{{$.locale.Tr "repo.pulls.has_changed_since_last_review"}}</span>
|
||||
{{end}}
|
||||
<div data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}">
|
||||
<input type="checkbox" name="{{$file.GetDiffFileName}}" id="viewed-file-checkbox-{{$i}}" autocomplete="off" {{if $file.IsViewed}}checked{{end}}></input>
|
||||
<label for="viewed-file-checkbox-{{$i}}">{{$.locale.Tr "repo.pulls.has_viewed_file"}}</label>
|
||||
</div>
|
||||
<label data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}">
|
||||
<input type="checkbox" name="{{$file.GetDiffFileName}}" autocomplete="off"{{if $file.IsViewed}} checked{{end}}> {{$.locale.Tr "repo.pulls.has_viewed_file"}}
|
||||
</label>
|
||||
{{end}}
|
||||
</div>
|
||||
</h4>
|
||||
<div class="diff-file-body ui attached unstackable table segment" {{if $file.IsViewed}}data-folded="true"{{end}}>
|
||||
<div id="diff-source-{{$i}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
|
||||
<div id="diff-source-{{$file.NameHash}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
|
||||
{{if or $file.IsIncomplete $file.IsBin}}
|
||||
<div class="diff-file-body binary" style="padding: 5px 10px;">
|
||||
{{if $file.IsIncomplete}}
|
||||
|
@ -148,12 +148,12 @@
|
|||
{{end}}
|
||||
</div>
|
||||
{{if $showFileViewToggle}}
|
||||
<div id="diff-rendered-{{$i}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
|
||||
<div id="diff-rendered-{{$file.NameHash}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
|
||||
<table class="chroma w-100">
|
||||
{{if $isImage}}
|
||||
{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
|
||||
{{else}}
|
||||
{{template "repo/diff/csv_diff" dict "file" . "root" $}}
|
||||
{{template "repo/diff/csv_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<tr>
|
||||
<td>
|
||||
{{$result := call .root.CreateCsvDiff .file .root.BaseCommit .root.HeadCommit}}
|
||||
{{$result := call .root.CreateCsvDiff .file .blobBase .blobHead}}
|
||||
{{if $result.Error}}
|
||||
<div class="ui center">{{$result.Error}}</div>
|
||||
{{else if $result.Sections}}
|
||||
|
|
|
@ -117,7 +117,6 @@
|
|||
{{if eq $n 0}}
|
||||
<div class="ui action tiny input" id="clone-panel">
|
||||
{{template "repo/clone_buttons" .}}
|
||||
{{template "repo/clone_script" .}}
|
||||
<button id="download-btn" class="ui basic small compact jump dropdown icon button tooltip" data-content="{{.locale.Tr "repo.download_archive"}}" data-position="top right">
|
||||
{{svg "octicon-download"}}
|
||||
<div class="menu">
|
||||
|
@ -129,6 +128,7 @@
|
|||
<a class="item js-clone-url-vsc" href="vscode://vscode.git/clone?url={{.CloneButtonOriginLink.HTTPS}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.locale.Tr "repo.clone_in_vsc"}}</a>
|
||||
</div>
|
||||
</button>
|
||||
{{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}}
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
{{end}}
|
||||
<div class="field {{if .Err_Description}}error{{end}}">
|
||||
<label for="description">{{$.locale.Tr "repo.repo_desc"}}</label>
|
||||
<textarea id="description" name="description" rows="2">{{.Repository.Description}}</textarea>
|
||||
<textarea id="description" name="description" rows="2" maxlength="2048">{{.Repository.Description}}</textarea>
|
||||
</div>
|
||||
<div class="field {{if .Err_Website}}error{{end}}">
|
||||
<label for="website">{{.locale.Tr "repo.settings.site"}}</label>
|
||||
<input id="website" name="website" type="url" value="{{.Repository.Website}}">
|
||||
<input id="website" name="website" type="url" maxlength="1024" value="{{.Repository.Website}}">
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
|
|
|
@ -72,8 +72,8 @@ func TestMain(m *testing.M) {
|
|||
os.Exit(exitVal)
|
||||
}
|
||||
|
||||
// This should be the only test e2e necessary. It will collect all "*.test.e2e.js"
|
||||
// files in this directory and build a test for each.
|
||||
// TestE2e should be the only test e2e necessary. It will collect all "*.test.e2e.js"
|
||||
// files in this directory and build a test for each.
|
||||
func TestE2e(t *testing.T) {
|
||||
// Find the paths of all e2e test files in test test directory.
|
||||
searchGlob := filepath.Join(filepath.Dir(setting.AppPath), "tests", "e2e", "*.test.e2e.js")
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestNodeinfo(t *testing.T) {
|
|||
DecodeJSON(t, resp, &nodeinfo)
|
||||
assert.True(t, nodeinfo.OpenRegistrations)
|
||||
assert.Equal(t, "gitea", nodeinfo.Software.Name)
|
||||
assert.Equal(t, 23, nodeinfo.Usage.Users.Total)
|
||||
assert.Equal(t, 24, nodeinfo.Usage.Users.Total)
|
||||
assert.Equal(t, 17, nodeinfo.Usage.LocalPosts)
|
||||
assert.Equal(t, 2, nodeinfo.Usage.LocalComments)
|
||||
})
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
@ -151,3 +152,38 @@ func TestAPIGetAll(t *testing.T) {
|
|||
assert.Equal(t, "org25", apiOrgList[0].FullName)
|
||||
assert.Equal(t, "public", apiOrgList[0].Visibility)
|
||||
}
|
||||
|
||||
func TestAPIOrgSearchEmptyTeam(t *testing.T) {
|
||||
onGiteaRun(t, func(*testing.T, *url.URL) {
|
||||
token := getUserToken(t, "user1")
|
||||
orgName := "org_with_empty_team"
|
||||
|
||||
// create org
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &api.CreateOrgOption{
|
||||
UserName: orgName,
|
||||
})
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// create team with no member
|
||||
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams?token=%s", orgName, token), &api.CreateTeamOption{
|
||||
Name: "Empty",
|
||||
IncludesAllRepositories: true,
|
||||
Permission: "read",
|
||||
Units: []string{"repo.code", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls"},
|
||||
})
|
||||
MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
// case-insensitive search for teams that have no members
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/orgs/%s/teams/search?q=%s&token=%s", orgName, "empty", token))
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
data := struct {
|
||||
Ok bool
|
||||
Data []*api.Team
|
||||
}{}
|
||||
DecodeJSON(t, resp, &data)
|
||||
assert.True(t, data.Ok)
|
||||
if assert.Len(t, data.Data, 1) {
|
||||
assert.EqualValues(t, "Empty", data.Data[0].Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -126,6 +127,18 @@ func TestPackageGeneric(t *testing.T) {
|
|||
req := NewRequest(t, "GET", url+"/not.found")
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
})
|
||||
|
||||
t.Run("RequireSignInView", func(t *testing.T) {
|
||||
defer tests.PrintCurrentTest(t)()
|
||||
|
||||
setting.Service.RequireSignInView = true
|
||||
defer func() {
|
||||
setting.Service.RequireSignInView = false
|
||||
}()
|
||||
|
||||
req = NewRequest(t, "GET", url+"/dummy.bin")
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
|
|
|
@ -737,6 +737,13 @@ a.ui.card:hover,
|
|||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
/* enable fluid page widths for medium size viewports */
|
||||
@media @mediaMdAndUp and @mediaLgAndDown {
|
||||
.ui.ui.ui.container:not(.fluid) {
|
||||
width: calc(100vw - 3em);
|
||||
}
|
||||
}
|
||||
|
||||
.following.bar {
|
||||
z-index: 900;
|
||||
left: 0;
|
||||
|
|
|
@ -409,10 +409,6 @@
|
|||
font-size: .5em;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.file-actions {
|
||||
.btn-octicon {
|
||||
line-height: 1;
|
||||
|
@ -3051,7 +3047,8 @@ td.blob-excerpt {
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
overflow-x: auto;
|
||||
padding: 8px 12px !important;
|
||||
padding: 6px 12px !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
|
|
|
@ -272,13 +272,22 @@ a.blob-excerpt:hover {
|
|||
}
|
||||
|
||||
.viewed-file-form {
|
||||
margin: 0 3px;
|
||||
padding: 0 3px;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px none;
|
||||
padding: 4px 8px;
|
||||
margin: -8px 0; // just like other buttons in the diff box header
|
||||
border-radius: .285rem; // just like .ui.tiny.button
|
||||
font-size: .857rem; // just like .ui.tiny.button
|
||||
}
|
||||
|
||||
.viewed-file-form input {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.viewed-file-checked-form {
|
||||
background-color: var(--color-primary-light-4);
|
||||
background-color: var(--color-primary-light-6);
|
||||
border: 1px solid var(--color-primary-light-4);
|
||||
}
|
||||
|
||||
#viewed-files-summary {
|
||||
|
|
Loading…
Reference in New Issue