diff --git a/services/convert/notification.go b/services/convert/notification.go index 69470638be..87166501a6 100644 --- a/services/convert/notification.go +++ b/services/convert/notification.go @@ -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 + } } } diff --git a/services/convert/notification_test.go b/services/convert/notification_test.go new file mode 100644 index 0000000000..718a070819 --- /dev/null +++ b/services/convert/notification_test.go @@ -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, + } +}