2019-04-20 06:15:19 +02:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2016-12-30 16:49:54 -02:00
package user
import (
2017-01-12 02:27:09 -02:00
"errors"
2016-12-30 16:49:54 -02:00
"fmt"
2020-04-24 04:57:38 +01:00
"net/http"
2021-10-16 11:34:07 +08:00
"net/url"
2017-01-02 16:31:50 -02:00
"strings"
2016-12-30 16:49:54 -02:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
2017-01-12 02:27:09 -02:00
"code.gitea.io/gitea/modules/setting"
2016-12-30 16:49:54 -02:00
)
const (
2020-04-24 04:57:38 +01:00
tplNotification base . TplName = "user/notification/notification"
tplNotificationDiv base . TplName = "user/notification/notification_div"
2016-12-30 16:49:54 -02:00
)
// GetNotificationCount is the middleware that sets the notification count in the context
func GetNotificationCount ( c * context . Context ) {
2017-01-02 16:31:50 -02:00
if strings . HasPrefix ( c . Req . URL . Path , "/api" ) {
return
}
2016-12-30 16:49:54 -02:00
if ! c . IsSigned {
return
}
2020-04-24 04:57:38 +01:00
c . Data [ "NotificationUnreadCount" ] = func ( ) int64 {
2022-03-22 08:03:22 +01:00
count , err := models . GetNotificationCount ( c . Doer , models . NotificationStatusUnread )
2020-04-24 04:57:38 +01:00
if err != nil {
c . ServerError ( "GetNotificationCount" , err )
return - 1
}
2016-12-30 16:49:54 -02:00
2020-04-24 04:57:38 +01:00
return count
}
2016-12-30 16:49:54 -02:00
}
// Notifications is the notifications page
func Notifications ( c * context . Context ) {
2020-04-24 04:57:38 +01:00
getNotifications ( c )
if c . Written ( ) {
return
}
2021-07-29 09:42:15 +08:00
if c . FormBool ( "div-only" ) {
2021-08-11 02:31:13 +02:00
c . Data [ "SequenceNumber" ] = c . FormString ( "sequence-number" )
2020-04-24 04:57:38 +01:00
c . HTML ( http . StatusOK , tplNotificationDiv )
return
}
c . HTML ( http . StatusOK , tplNotification )
}
func getNotifications ( c * context . Context ) {
2017-01-03 17:09:36 -02:00
var (
2021-08-11 17:08:52 +02:00
keyword = c . FormTrim ( "q" )
2017-01-03 17:09:36 -02:00
status models . NotificationStatus
2021-07-29 09:42:15 +08:00
page = c . FormInt ( "page" )
perPage = c . FormInt ( "perPage" )
2017-01-03 17:09:36 -02:00
)
if page < 1 {
page = 1
}
if perPage < 1 {
perPage = 20
}
switch keyword {
2016-12-30 16:49:54 -02:00
case "read" :
status = models . NotificationStatusRead
default :
status = models . NotificationStatusUnread
}
2022-03-22 08:03:22 +01:00
total , err := models . GetNotificationCount ( c . Doer , status )
2020-01-18 02:31:26 +08:00
if err != nil {
c . ServerError ( "ErrGetNotificationCount" , err )
return
}
// redirect to last page if request page is more than total pages
pager := context . NewPagination ( int ( total ) , perPage , page , 5 )
if pager . Paginater . Current ( ) < page {
2021-10-16 11:34:07 +08:00
c . Redirect ( fmt . Sprintf ( "%s/notifications?q=%s&page=%d" , setting . AppSubURL , url . QueryEscape ( c . FormString ( "q" ) ) , pager . Paginater . Current ( ) ) )
2020-01-18 02:31:26 +08:00
return
}
2017-01-12 02:27:09 -02:00
statuses := [ ] models . NotificationStatus { status , models . NotificationStatusPinned }
2022-03-22 08:03:22 +01:00
notifications , err := models . NotificationsForUser ( c . Doer , statuses , page , perPage )
2016-12-30 16:49:54 -02:00
if err != nil {
2018-01-10 22:34:17 +01:00
c . ServerError ( "ErrNotificationsForUser" , err )
2016-12-30 16:49:54 -02:00
return
}
2020-03-29 20:51:14 +01:00
failCount := 0
repos , failures , err := notifications . LoadRepos ( )
2019-11-12 16:33:34 +08:00
if err != nil {
c . ServerError ( "LoadRepos" , err )
return
}
2020-03-29 20:51:14 +01:00
notifications = notifications . Without ( failures )
2019-11-12 16:33:34 +08:00
if err := repos . LoadAttributes ( ) ; err != nil {
c . ServerError ( "LoadAttributes" , err )
return
}
2020-03-29 20:51:14 +01:00
failCount += len ( failures )
2019-11-12 16:33:34 +08:00
2020-03-29 20:51:14 +01:00
failures , err = notifications . LoadIssues ( )
if err != nil {
2019-11-12 16:33:34 +08:00
c . ServerError ( "LoadIssues" , err )
return
}
2020-03-29 20:51:14 +01:00
notifications = notifications . Without ( failures )
failCount += len ( failures )
failures , err = notifications . LoadComments ( )
if err != nil {
2019-11-12 16:33:34 +08:00
c . ServerError ( "LoadComments" , err )
return
}
2020-03-29 20:51:14 +01:00
notifications = notifications . Without ( failures )
failCount += len ( failures )
if failCount > 0 {
c . Flash . Error ( fmt . Sprintf ( "ERROR: %d notifications were removed due to missing parts - check the logs" , failCount ) )
}
2019-11-12 16:33:34 +08:00
2020-04-24 04:57:38 +01:00
c . Data [ "Title" ] = c . Tr ( "notifications" )
2017-01-03 17:09:36 -02:00
c . Data [ "Keyword" ] = keyword
2016-12-30 16:49:54 -02:00
c . Data [ "Status" ] = status
c . Data [ "Notifications" ] = notifications
2019-04-20 06:15:19 +02:00
pager . SetDefaultParams ( c )
c . Data [ "Page" ] = pager
2016-12-30 16:49:54 -02:00
}
2017-01-12 02:27:09 -02:00
// NotificationStatusPost is a route for changing the status of a notification
func NotificationStatusPost ( c * context . Context ) {
var (
2021-08-11 17:08:52 +02:00
notificationID = c . FormInt64 ( "notification_id" )
statusStr = c . FormString ( "status" )
status models . NotificationStatus
2017-01-12 02:27:09 -02:00
)
switch statusStr {
case "read" :
status = models . NotificationStatusRead
case "unread" :
status = models . NotificationStatusUnread
case "pinned" :
status = models . NotificationStatusPinned
default :
2018-01-10 22:34:17 +01:00
c . ServerError ( "InvalidNotificationStatus" , errors . New ( "Invalid notification status" ) )
2017-01-12 02:27:09 -02:00
return
}
2022-03-22 08:03:22 +01:00
if _ , err := models . SetNotificationStatus ( notificationID , c . Doer , status ) ; err != nil {
2018-01-10 22:34:17 +01:00
c . ServerError ( "SetNotificationStatus" , err )
2017-01-12 02:27:09 -02:00
return
}
2021-07-29 09:42:15 +08:00
if ! c . FormBool ( "noredirect" ) {
2021-11-16 18:18:25 +00:00
url := fmt . Sprintf ( "%s/notifications?page=%s" , setting . AppSubURL , url . QueryEscape ( c . FormString ( "page" ) ) )
2020-04-24 04:57:38 +01:00
c . Redirect ( url , http . StatusSeeOther )
}
getNotifications ( c )
if c . Written ( ) {
return
}
2021-02-19 21:36:43 +00:00
c . Data [ "Link" ] = setting . AppURL + "notifications"
2021-07-17 17:18:10 +01:00
c . Data [ "SequenceNumber" ] = c . Req . PostFormValue ( "sequence-number" )
2020-04-24 04:57:38 +01:00
c . HTML ( http . StatusOK , tplNotificationDiv )
2017-01-12 02:27:09 -02:00
}
2017-12-07 12:52:57 +07:00
// NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read
func NotificationPurgePost ( c * context . Context ) {
2022-03-22 08:03:22 +01:00
err := models . UpdateNotificationStatuses ( c . Doer , models . NotificationStatusUnread , models . NotificationStatusRead )
2017-12-07 12:52:57 +07:00
if err != nil {
2018-01-10 22:34:17 +01:00
c . ServerError ( "ErrUpdateNotificationStatuses" , err )
2017-12-07 12:52:57 +07:00
return
}
2021-11-16 18:18:25 +00:00
c . Redirect ( setting . AppSubURL + "/notifications" , http . StatusSeeOther )
2017-12-07 12:52:57 +07:00
}