aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Song <i@wolfogre.com>2024-08-11 22:48:20 +0800
committerGitHub <noreply@github.com>2024-08-11 14:48:20 +0000
commit0470646d46f90c20f40fde718be6ef8d8c84ee2c (patch)
tree6efe8af611b1c639b0235e4a46c4976ed5333e9f
parente45a4c98292bf7c53700ff2f6f8e4dc7ba2e3e68 (diff)
downloadgitea-0470646d46f90c20f40fde718be6ef8d8c84ee2c.tar.gz
gitea-0470646d46f90c20f40fde718be6ef8d8c84ee2c.zip
Show lock owner instead of repo owner on LFS setting page (#31788)
Fix #31784. Before: <img width="1648" alt="image" src="https://github.com/user-attachments/assets/03f32545-4a85-42ed-bafc-2b193a5d8023"> After: <img width="1653" alt="image" src="https://github.com/user-attachments/assets/e5bcaf93-49cb-421f-aac1-5122bc488b02">
-rw-r--r--models/git/lfs_lock.go45
-rw-r--r--models/git/lfs_lock_list.go54
-rw-r--r--routers/web/repo/setting/lfs.go5
-rw-r--r--templates/repo/settings/lfs_locks.tmpl6
-rw-r--r--tests/integration/lfs_view_test.go62
5 files changed, 162 insertions, 10 deletions
diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go
index 2f65833fe3..07ce7d4abf 100644
--- a/models/git/lfs_lock.go
+++ b/models/git/lfs_lock.go
@@ -6,6 +6,7 @@ package git
import (
"context"
"errors"
+ "fmt"
"strings"
"time"
@@ -21,11 +22,12 @@ import (
// LFSLock represents a git lfs lock of repository.
type LFSLock struct {
- ID int64 `xorm:"pk autoincr"`
- RepoID int64 `xorm:"INDEX NOT NULL"`
- OwnerID int64 `xorm:"INDEX NOT NULL"`
- Path string `xorm:"TEXT"`
- Created time.Time `xorm:"created"`
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX NOT NULL"`
+ OwnerID int64 `xorm:"INDEX NOT NULL"`
+ Owner *user_model.User `xorm:"-"`
+ Path string `xorm:"TEXT"`
+ Created time.Time `xorm:"created"`
}
func init() {
@@ -37,6 +39,35 @@ func (l *LFSLock) BeforeInsert() {
l.Path = util.PathJoinRel(l.Path)
}
+// LoadAttributes loads attributes of the lock.
+func (l *LFSLock) LoadAttributes(ctx context.Context) error {
+ // Load owner
+ if err := l.LoadOwner(ctx); err != nil {
+ return fmt.Errorf("load owner: %w", err)
+ }
+
+ return nil
+}
+
+// LoadOwner loads owner of the lock.
+func (l *LFSLock) LoadOwner(ctx context.Context) error {
+ if l.Owner != nil {
+ return nil
+ }
+
+ owner, err := user_model.GetUserByID(ctx, l.OwnerID)
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ l.Owner = user_model.NewGhostUser()
+ return nil
+ }
+ return err
+ }
+ l.Owner = owner
+
+ return nil
+}
+
// CreateLFSLock creates a new lock.
func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) {
dbCtx, committer, err := db.TxContext(ctx)
@@ -94,7 +125,7 @@ func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) {
}
// GetLFSLockByRepoID returns a list of locks of repository.
-func GetLFSLockByRepoID(ctx context.Context, repoID int64, page, pageSize int) ([]*LFSLock, error) {
+func GetLFSLockByRepoID(ctx context.Context, repoID int64, page, pageSize int) (LFSLockList, error) {
e := db.GetEngine(ctx)
if page >= 0 && pageSize > 0 {
start := 0
@@ -103,7 +134,7 @@ func GetLFSLockByRepoID(ctx context.Context, repoID int64, page, pageSize int) (
}
e.Limit(pageSize, start)
}
- lfsLocks := make([]*LFSLock, 0, pageSize)
+ lfsLocks := make(LFSLockList, 0, pageSize)
return lfsLocks, e.Find(&lfsLocks, &LFSLock{RepoID: repoID})
}
diff --git a/models/git/lfs_lock_list.go b/models/git/lfs_lock_list.go
new file mode 100644
index 0000000000..cab1e61cab
--- /dev/null
+++ b/models/git/lfs_lock_list.go
@@ -0,0 +1,54 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+ "context"
+ "fmt"
+
+ "code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/container"
+)
+
+// LFSLockList is a list of LFSLock
+type LFSLockList []*LFSLock
+
+// LoadAttributes loads the attributes for the given locks
+func (locks LFSLockList) LoadAttributes(ctx context.Context) error {
+ if len(locks) == 0 {
+ return nil
+ }
+
+ if err := locks.LoadOwner(ctx); err != nil {
+ return fmt.Errorf("load owner: %w", err)
+ }
+
+ return nil
+}
+
+// LoadOwner loads the owner of the locks
+func (locks LFSLockList) LoadOwner(ctx context.Context) error {
+ if len(locks) == 0 {
+ return nil
+ }
+
+ usersIDs := container.FilterSlice(locks, func(lock *LFSLock) (int64, bool) {
+ return lock.OwnerID, true
+ })
+ users := make(map[int64]*user_model.User, len(usersIDs))
+ if err := db.GetEngine(ctx).
+ In("id", usersIDs).
+ Find(&users); err != nil {
+ return fmt.Errorf("find users: %w", err)
+ }
+ for _, v := range locks {
+ v.Owner = users[v.OwnerID]
+ if v.Owner == nil { // not exist
+ v.Owner = user_model.NewGhostUser()
+ }
+ }
+
+ return nil
+}
diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go
index 3b96f93ff2..fad6359668 100644
--- a/routers/web/repo/setting/lfs.go
+++ b/routers/web/repo/setting/lfs.go
@@ -95,6 +95,11 @@ func LFSLocks(ctx *context.Context) {
ctx.ServerError("LFSLocks", err)
return
}
+ if err := lfsLocks.LoadAttributes(ctx); err != nil {
+ ctx.ServerError("LFSLocks", err)
+ return
+ }
+
ctx.Data["LFSLocks"] = lfsLocks
if len(lfsLocks) == 0 {
diff --git a/templates/repo/settings/lfs_locks.tmpl b/templates/repo/settings/lfs_locks.tmpl
index 98f0e49097..9a18f525e9 100644
--- a/templates/repo/settings/lfs_locks.tmpl
+++ b/templates/repo/settings/lfs_locks.tmpl
@@ -30,9 +30,9 @@
{{end}}
</td>
<td>
- <a href="{{$.Owner.HomeLink}}">
- {{ctx.AvatarUtils.Avatar $.Owner}}
- {{$.Owner.DisplayName}}
+ <a href="{{$lock.Owner.HomeLink}}">
+ {{ctx.AvatarUtils.Avatar $lock.Owner}}
+ {{$lock.Owner.DisplayName}}
</a>
</td>
<td>{{TimeSince .Created ctx.Locale}}</td>
diff --git a/tests/integration/lfs_view_test.go b/tests/integration/lfs_view_test.go
index 1775fa629f..c28ecf1d7a 100644
--- a/tests/integration/lfs_view_test.go
+++ b/tests/integration/lfs_view_test.go
@@ -4,12 +4,21 @@
package integration
import (
+ "context"
+ "fmt"
"net/http"
+ "strings"
"testing"
+ 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/lfs"
+ api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
// check that files stored in LFS render properly in the web UI
@@ -81,3 +90,56 @@ func TestLFSRender(t *testing.T) {
assert.Contains(t, content, "Testing READMEs in LFS")
})
}
+
+// TestLFSLockView tests the LFS lock view on settings page of repositories
+func TestLFSLockView(t *testing.T) {
+ defer tests.PrepareTestEnv(t)()
+
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // in org 3
+ repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // own by org 3
+ session := loginUser(t, user2.Name)
+
+ // create a lock
+ lockPath := "test_lfs_lock_view.zip"
+ lockID := ""
+ {
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", repo3.FullName()), map[string]string{"path": lockPath})
+ req.Header.Set("Accept", lfs.AcceptHeader)
+ req.Header.Set("Content-Type", lfs.MediaType)
+ resp := session.MakeRequest(t, req, http.StatusCreated)
+ lockResp := &api.LFSLockResponse{}
+ DecodeJSON(t, resp, lockResp)
+ lockID = lockResp.Lock.ID
+ }
+ defer func() {
+ // release the lock
+ req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/%s/unlock", repo3.FullName(), lockID), map[string]string{})
+ req.Header.Set("Accept", lfs.AcceptHeader)
+ req.Header.Set("Content-Type", lfs.MediaType)
+ session.MakeRequest(t, req, http.StatusOK)
+ }()
+
+ t.Run("owner name", func(t *testing.T) {
+ defer tests.PrintCurrentTest(t)()
+
+ // make sure the display names are different, or the test is meaningless
+ require.NoError(t, repo3.LoadOwner(context.Background()))
+ require.NotEqual(t, user2.DisplayName(), repo3.Owner.DisplayName())
+
+ req := NewRequest(t, "GET", fmt.Sprintf("/%s/settings/lfs/locks", repo3.FullName()))
+ resp := session.MakeRequest(t, req, http.StatusOK)
+
+ doc := NewHTMLParser(t, resp.Body).doc
+
+ tr := doc.Find("table#lfs-files-locks-table tbody tr")
+ require.Equal(t, 1, tr.Length())
+
+ td := tr.First().Find("td")
+ require.Equal(t, 4, td.Length())
+
+ // path
+ assert.Equal(t, lockPath, strings.TrimSpace(td.Eq(0).Text()))
+ // owner name
+ assert.Equal(t, user2.DisplayName(), strings.TrimSpace(td.Eq(1).Text()))
+ })
+}