enhance(notifications): mark current notification page as read (#39294)

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Mitrahsoft
2026-09-16 06:01:16 +05:30
committed by GitHub
parent f9d3268dbe
commit a583a30d4a
5 changed files with 42 additions and 16 deletions
+7 -10
View File
@@ -326,16 +326,6 @@ type UserIDCount struct {
Count int64
}
// GetUIDsAndNotificationCounts returns the unread counts for every user between the two provided times.
// It must return all user IDs which appear during the period, including count=0 for users who have read all.
func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) {
sql := `SELECT user_id, sum(case when status= ? then 1 else 0 end) AS count FROM notification ` +
`WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
`updated_unix < ?) GROUP BY user_id`
var res []UserIDCount
return res, db.GetEngine(ctx).SQL(sql, NotificationStatusUnread, since, until).Find(&res)
}
// SetIssueReadBy sets issue to be read by given user. The bool result is true
// when the unread count actually decreased, so callers can skip a push on no-op.
func SetIssueReadBy(ctx context.Context, issueID, userID int64) (bool, error) {
@@ -410,6 +400,13 @@ func GetNotificationByID(ctx context.Context, notificationID int64) (*Notificati
return notification, nil
}
func GetNotificationsByIDs(ctx context.Context, ids []int64, userID int64) (ret NotificationList, _ error) {
err := db.GetEngine(ctx).
Where("user_id = ?", userID).And(builder.In("id", ids)).
Find(&ret)
return ret, err
}
// UpdateNotificationStatuses updates the statuses of all of a user's notifications
// that are of the currentStatus type to the desiredStatus. Returns the number of
// rows actually changed so callers can skip downstream work on a no-op.
+1
View File
@@ -3548,6 +3548,7 @@
"notification.mark_as_read": "Mark as read",
"notification.mark_as_unread": "Mark as unread",
"notification.mark_all_as_read": "Mark all as read",
"notification.mark_page_as_read": "Mark this page as read",
"notification.subscriptions": "Subscriptions",
"notification.watching": "Watching",
"notification.no_subscriptions": "No subscriptions",
+23 -1
View File
@@ -132,9 +132,17 @@ func prepareUserNotificationsData(ctx *context.Context) {
ctx.Flash.Error(fmt.Sprintf("ERROR: %d notifications were removed due to missing parts - check the logs", failCount))
}
var unreadNotificationIDs []int64
for _, n := range notifications {
if n.Status == activities_model.NotificationStatusUnread {
unreadNotificationIDs = append(unreadNotificationIDs, n.ID)
}
}
ctx.Data["Title"] = ctx.Tr("notifications")
ctx.Data["PageType"] = pageType
ctx.Data["Notifications"] = notifications
ctx.Data["CurUnreadNotificationIDs"] = strings.Join(base.Int64sToStrings(unreadNotificationIDs), ",")
ctx.Data["Link"] = setting.AppSubURL + "/notifications"
ctx.Data["SequenceNumber"] = ctx.FormString("sequence-number")
@@ -192,8 +200,22 @@ func NotificationPurgePost(ctx *context.Context) {
ctx.ServerError("MarkAllRead", err)
return
}
ctx.JSONRedirect(setting.AppSubURL + "/notifications")
}
ctx.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther)
// NotificationPurgePagePost is a route for marking only the notifications on the current page as read
func NotificationPurgePagePost(ctx *context.Context) {
nl, err := activities_model.GetNotificationsByIDs(ctx, ctx.FormStringInt64s("ids"), ctx.Doer.ID)
if err != nil {
ctx.ServerError("GetNotificationsByIDs", err)
return
}
_, err = notifications.SetManyNotificationStatuses(ctx, nl, ctx.Doer, activities_model.NotificationStatusRead)
if err != nil {
ctx.ServerError("SetManyNotificationStatuses", err)
return
}
ctx.JSONRedirect("")
}
// NotificationSubscriptions returns the list of subscribed issues
+1
View File
@@ -1776,6 +1776,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
m.Get("/watching", user.NotificationWatching)
m.Post("/status", user.NotificationStatusPost)
m.Post("/purge", user.NotificationPurgePost)
m.Post("/purge-page", user.NotificationPurgePagePost)
m.Get("/new", user.NewAvailable)
}, reqSignIn)
@@ -14,11 +14,16 @@
</a>
</div>
{{if and (not $pageTypeIsRead) $notificationUnreadCount}}
<form action="{{AppSubUrl}}/notifications/purge" method="post">
<button type="submit" class="ui mini button primary tw-mr-0" title="{{ctx.Locale.Tr "notification.mark_all_as_read"}}">
{{svg "octicon-checklist"}}
</button>
</form>
<div class="flex-text-block">
{{if .CurUnreadNotificationIDs}}
<button type="button" class="ui mini button link-action" data-tooltip-content="{{ctx.Locale.Tr "notification.mark_page_as_read"}}"
data-url="{{AppSubUrl}}/notifications/purge-page?ids={{.CurUnreadNotificationIDs}}"
>{{svg "octicon-check"}}</button>
{{end}}
<button type="button" class="ui mini button primary link-action" data-tooltip-content="{{ctx.Locale.Tr "notification.mark_all_as_read"}}"
data-url="{{AppSubUrl}}/notifications/purge"
>{{svg "octicon-checklist"}}</button>
</div>
{{end}}
</div>
<div id="notification_table">