mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-14 13:08:11 +02:00
Merge branch 'main' into lunny/hide_delete_dir_mirror_archive
This commit is contained in:
commit
04f4a3cc19
@ -66,6 +66,21 @@ type Link struct {
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
}
|
||||
|
||||
func NewLink(href string) *Link {
|
||||
return &Link{Href: href}
|
||||
}
|
||||
|
||||
func (l *Link) WithHeader(k, v string) *Link {
|
||||
if v == "" {
|
||||
return l
|
||||
}
|
||||
if l.Header == nil {
|
||||
l.Header = make(map[string]string)
|
||||
}
|
||||
l.Header[k] = v
|
||||
return l
|
||||
}
|
||||
|
||||
// ObjectError defines the JSON structure returned to the client in case of an error.
|
||||
type ObjectError struct {
|
||||
Code int `json:"code"`
|
||||
|
||||
@ -8,8 +8,8 @@ import (
|
||||
"net/url"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
@ -25,11 +25,17 @@ func ToNotificationThread(ctx context.Context, n *activities_model.Notification)
|
||||
|
||||
// since user only get notifications when he has access to use minimal access mode
|
||||
if n.Repository != nil {
|
||||
result.Repository = ToRepo(ctx, n.Repository, access_model.Permission{AccessMode: perm.AccessModeRead})
|
||||
|
||||
// This permission is not correct and we should not be reporting it
|
||||
for repository := result.Repository; repository != nil; repository = repository.Parent {
|
||||
repository.Permissions = nil
|
||||
perm, err := access_model.GetUserRepoPermission(ctx, n.Repository, n.User)
|
||||
if err != nil {
|
||||
log.Error("GetUserRepoPermission failed: %v", err)
|
||||
return result
|
||||
}
|
||||
if perm.HasAnyUnitAccessOrPublicAccess() { // if user has been revoked access to repo, do not show repo info
|
||||
result.Repository = ToRepo(ctx, n.Repository, perm)
|
||||
// This permission is not correct and we should not be reporting it
|
||||
for repository := result.Repository; repository != nil; repository = repository.Parent {
|
||||
repository.Permissions = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
57
services/convert/notification_test.go
Normal file
57
services/convert/notification_test.go
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToNotificationThreadIncludesRepoForAccessibleUser(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
n := newRepoNotification(t, 1, 4)
|
||||
thread := ToNotificationThread(t.Context(), n)
|
||||
|
||||
if assert.NotNil(t, thread.Repository) {
|
||||
assert.Equal(t, n.Repository.FullName(), thread.Repository.FullName)
|
||||
assert.Nil(t, thread.Repository.Permissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToNotificationThreadOmitsRepoWhenAccessRevoked(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
n := newRepoNotification(t, 2, 4)
|
||||
thread := ToNotificationThread(t.Context(), n)
|
||||
|
||||
assert.Nil(t, thread.Repository)
|
||||
}
|
||||
|
||||
func newRepoNotification(t *testing.T, repoID, userID int64) *activities_model.Notification {
|
||||
t.Helper()
|
||||
|
||||
ctx := t.Context()
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
|
||||
assert.NoError(t, repo.LoadOwner(ctx))
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
|
||||
|
||||
return &activities_model.Notification{
|
||||
ID: repoID*1000 + userID,
|
||||
UserID: user.ID,
|
||||
RepoID: repo.ID,
|
||||
Status: activities_model.NotificationStatusUnread,
|
||||
Source: activities_model.NotificationSourceRepository,
|
||||
UpdatedUnix: timeutil.TimeStampNow(),
|
||||
Repository: repo,
|
||||
User: user,
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
@ -487,40 +486,32 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
|
||||
rep.Error = err
|
||||
} else {
|
||||
rep.Actions = make(map[string]*lfs_module.Link)
|
||||
|
||||
header := make(map[string]string)
|
||||
|
||||
if len(rc.Authorization) > 0 {
|
||||
header["Authorization"] = rc.Authorization
|
||||
}
|
||||
|
||||
if download {
|
||||
var link *lfs_module.Link
|
||||
if setting.LFS.Storage.ServeDirect() {
|
||||
// If we have a signed url (S3, object storage), redirect to this directly.
|
||||
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, rc.Method, nil)
|
||||
if u != nil && err == nil {
|
||||
// Presigned url does not need the Authorization header
|
||||
// https://github.com/go-gitea/gitea/issues/21525
|
||||
delete(header, "Authorization")
|
||||
link = &lfs_module.Link{Href: u.String(), Header: header}
|
||||
link = lfs_module.NewLink(u.String()) // Presigned url does not need the Authorization header
|
||||
}
|
||||
}
|
||||
if link == nil {
|
||||
link = &lfs_module.Link{Href: rc.DownloadLink(pointer), Header: header}
|
||||
link = lfs_module.NewLink(rc.DownloadLink(pointer)).WithHeader("Authorization", rc.Authorization)
|
||||
}
|
||||
rep.Actions["download"] = link
|
||||
}
|
||||
if upload {
|
||||
rep.Actions["upload"] = &lfs_module.Link{Href: rc.UploadLink(pointer), Header: header}
|
||||
// Set Transfer-Encoding header to enable chunked uploads. Required by git-lfs client to do chunked transfer.
|
||||
// See: https://github.com/git-lfs/git-lfs/blob/main/tq/basic_upload.go#L58-59
|
||||
rep.Actions["upload"] = lfs_module.NewLink(rc.UploadLink(pointer)).
|
||||
WithHeader("Authorization", rc.Authorization).
|
||||
WithHeader("Transfer-Encoding", "chunked")
|
||||
|
||||
verifyHeader := make(map[string]string)
|
||||
maps.Copy(verifyHeader, header)
|
||||
|
||||
// This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662
|
||||
verifyHeader["Accept"] = lfs_module.AcceptHeader
|
||||
|
||||
rep.Actions["verify"] = &lfs_module.Link{Href: rc.VerifyLink(pointer), Header: verifyHeader}
|
||||
// "Accept" header is the workaround for git-lfs < 2.8.0 (before 2019).
|
||||
// This workaround could be removed in the future: https://github.com/git-lfs/git-lfs/issues/3662
|
||||
rep.Actions["verify"] = lfs_module.NewLink(rc.VerifyLink(pointer)).
|
||||
WithHeader("Authorization", rc.Authorization).
|
||||
WithHeader("Accept", lfs_module.AcceptHeader)
|
||||
}
|
||||
}
|
||||
return rep
|
||||
|
||||
@ -317,6 +317,7 @@ func TestAPILFSBatch(t *testing.T) {
|
||||
ul := br.Objects[0].Actions["upload"]
|
||||
assert.NotNil(t, ul)
|
||||
assert.NotEmpty(t, ul.Href)
|
||||
assert.Equal(t, "chunked", ul.Header["Transfer-Encoding"], "git-lfs client needs Transfer-Encoding to do chunked transfer")
|
||||
assert.Contains(t, br.Objects[0].Actions, "verify")
|
||||
vl := br.Objects[0].Actions["verify"]
|
||||
assert.NotNil(t, vl)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user