2021-04-07 12:57:14 +00:00
package protocol
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"strings"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/protocol/common"
)
2023-06-10 02:00:17 +00:00
const allFieldsForTableActivityCenterNotification = ` id , timestamp , notification_type , chat_id , read , dismissed , accepted , message , author ,
reply_message , community_id , membership_status , contact_verification_status , deleted , updated_at `
2023-10-22 09:41:20 +00:00
var emptyNotifications = make ( [ ] * ActivityCenterNotification , 0 )
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DeleteActivityCenterNotificationByID ( id [ ] byte , updatedAt uint64 ) error {
_ , err := db . db . Exec ( ` UPDATE activity_center_notifications SET deleted = 1, updated_at = ? WHERE id = ? AND NOT deleted ` , updatedAt , id )
2021-04-07 12:57:14 +00:00
return err
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DeleteActivityCenterNotificationForMessage ( chatID string , messageID string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2021-08-23 14:23:55 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
2023-06-10 02:00:17 +00:00
return nil , err
2021-08-23 14:23:55 +00:00
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2022-08-31 14:41:58 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
chatID : chatID ,
2022-08-31 14:41:58 +00:00
}
_ , notifications , err := db . buildActivityCenterQuery ( tx , params )
2021-08-23 14:23:55 +00:00
if err != nil {
2023-06-10 02:00:17 +00:00
return nil , err
2021-08-23 14:23:55 +00:00
}
var ids [ ] types . HexBytes
2023-06-10 02:00:17 +00:00
var matchNotifications [ ] * ActivityCenterNotification
withNotification := func ( a * ActivityCenterNotification ) {
a . Read = true
a . Dismissed = true
a . Deleted = true
a . UpdatedAt = updatedAt
ids = append ( ids , a . ID )
matchNotifications = append ( matchNotifications , a )
}
2021-08-23 14:23:55 +00:00
for _ , notification := range notifications {
2022-09-12 13:39:07 +00:00
if notification . LastMessage != nil && notification . LastMessage . ID == messageID {
2023-06-10 02:00:17 +00:00
withNotification ( notification )
2022-09-12 13:39:07 +00:00
}
2021-08-23 14:23:55 +00:00
if notification . Message != nil && notification . Message . ID == messageID {
2023-06-10 02:00:17 +00:00
withNotification ( notification )
2021-08-23 14:23:55 +00:00
}
}
if len ( ids ) > 0 {
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
2021-08-23 14:23:55 +00:00
for _ , id := range ids {
2023-06-10 02:00:17 +00:00
args = append ( args , id )
2021-08-23 14:23:55 +00:00
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-06-10 02:00:17 +00:00
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, deleted = 1, updated_at = ? WHERE id IN (" + inVector + ")" // nolint: gosec
_ , err = tx . Exec ( query , args ... )
return matchNotifications , err
2021-08-23 14:23:55 +00:00
}
2023-06-10 02:00:17 +00:00
return matchNotifications , nil
2021-08-23 14:23:55 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) SaveActivityCenterNotification ( notification * ActivityCenterNotification , updateState bool ) ( int64 , error ) {
2021-04-07 12:57:14 +00:00
var tx * sql . Tx
var err error
err = notification . Valid ( )
if err != nil {
2023-06-10 02:00:17 +00:00
return 0 , err
2021-04-07 12:57:14 +00:00
}
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
2023-06-10 02:00:17 +00:00
return 0 , err
2021-04-07 12:57:14 +00:00
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2021-05-29 17:05:25 +00:00
// encode message
var encodedMessage [ ] byte
if notification . Message != nil {
encodedMessage , err = json . Marshal ( notification . Message )
if err != nil {
2023-06-10 02:00:17 +00:00
return 0 , err
2021-05-29 17:05:25 +00:00
}
}
2021-07-15 20:21:44 +00:00
// encode message
var encodedReplyMessage [ ] byte
if notification . ReplyMessage != nil {
encodedReplyMessage , err = json . Marshal ( notification . ReplyMessage )
if err != nil {
2023-06-10 02:00:17 +00:00
return 0 , err
2021-07-15 20:21:44 +00:00
}
}
2023-06-10 02:00:17 +00:00
result , err := tx . Exec ( `
2023-02-24 23:47:04 +00:00
INSERT OR REPLACE
INTO activity_center_notifications (
id ,
timestamp ,
notification_type ,
chat_id ,
community_id ,
membership_status ,
message ,
reply_message ,
author ,
contact_verification_status ,
read ,
accepted ,
dismissed ,
2023-06-10 02:00:17 +00:00
deleted ,
updated_at
2023-02-24 23:47:04 +00:00
)
2023-06-10 02:00:17 +00:00
SELECT ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? WHERE NOT EXISTS ( SELECT 1 FROM activity_center_notifications WHERE id = ? AND updated_at >= ? )
2023-02-24 23:47:04 +00:00
` ,
2023-01-28 09:52:53 +00:00
notification . ID ,
notification . Timestamp ,
notification . Type ,
notification . ChatID ,
notification . CommunityID ,
notification . MembershipStatus ,
encodedMessage ,
encodedReplyMessage ,
notification . Author ,
notification . ContactVerificationStatus ,
notification . Read ,
notification . Accepted ,
notification . Dismissed ,
2023-02-24 23:47:04 +00:00
notification . Deleted ,
2023-06-10 02:00:17 +00:00
notification . UpdatedAt ,
notification . ID ,
notification . UpdatedAt ,
2023-01-28 09:52:53 +00:00
)
2023-06-10 02:00:17 +00:00
if err != nil {
return 0 , err
}
n , err := result . RowsAffected ( )
if err != nil {
return n , err
}
2023-02-17 10:08:08 +00:00
// When we have inserted or updated unread notification - mark whole activity_center_settings as unseen
2023-06-10 02:00:17 +00:00
if updateState && n > 0 && ! notification . Read {
_ , err = tx . Exec ( ` UPDATE activity_center_states SET has_seen = 0, updated_at = ? ` , notification . UpdatedAt )
2023-02-17 10:08:08 +00:00
}
2023-06-10 02:00:17 +00:00
return n , nil
}
func ( db sqlitePersistence ) parseRowFromTableActivityCenterNotification ( rows * sql . Rows , withNotification func ( notification * ActivityCenterNotification ) ) ( [ ] * ActivityCenterNotification , error ) {
var notifications [ ] * ActivityCenterNotification
defer rows . Close ( )
for rows . Next ( ) {
var chatID sql . NullString
var communityID sql . NullString
var messageBytes [ ] byte
var replyMessageBytes [ ] byte
var author sql . NullString
notification := & ActivityCenterNotification { }
err := rows . Scan (
& notification . ID ,
& notification . Timestamp ,
& notification . Type ,
& chatID ,
& notification . Read ,
& notification . Dismissed ,
& notification . Accepted ,
& messageBytes ,
& author ,
& replyMessageBytes ,
& communityID ,
& notification . MembershipStatus ,
& notification . ContactVerificationStatus ,
& notification . Deleted ,
& notification . UpdatedAt ,
)
if err != nil {
return nil , err
}
if chatID . Valid {
notification . ChatID = chatID . String
}
if communityID . Valid {
notification . CommunityID = communityID . String
}
if author . Valid {
notification . Author = author . String
}
if len ( messageBytes ) > 0 {
err = json . Unmarshal ( messageBytes , & notification . Message )
if err != nil {
return nil , err
}
}
if len ( replyMessageBytes ) > 0 {
err = json . Unmarshal ( replyMessageBytes , & notification . ReplyMessage )
if err != nil {
return nil , err
}
}
if withNotification != nil {
withNotification ( notification )
}
notifications = append ( notifications , notification )
}
return notifications , nil
2021-04-07 12:57:14 +00:00
}
2022-01-18 16:31:34 +00:00
func ( db sqlitePersistence ) unmarshalActivityCenterNotificationRow ( row * sql . Row ) ( * ActivityCenterNotification , error ) {
var chatID sql . NullString
2022-10-25 22:06:20 +00:00
var communityID sql . NullString
2022-01-18 16:31:34 +00:00
var lastMessageBytes [ ] byte
var messageBytes [ ] byte
var replyMessageBytes [ ] byte
var name sql . NullString
var author sql . NullString
notification := & ActivityCenterNotification { }
err := row . Scan (
& notification . ID ,
& notification . Timestamp ,
& notification . Type ,
& chatID ,
2022-10-25 22:06:20 +00:00
& communityID ,
& notification . MembershipStatus ,
2022-01-18 16:31:34 +00:00
& notification . Read ,
& notification . Accepted ,
& notification . Dismissed ,
2023-02-24 23:47:04 +00:00
& notification . Deleted ,
2022-01-18 16:31:34 +00:00
& messageBytes ,
& lastMessageBytes ,
& replyMessageBytes ,
2022-10-24 11:33:47 +00:00
& notification . ContactVerificationStatus ,
2022-01-18 16:31:34 +00:00
& name ,
2023-06-10 02:00:17 +00:00
& author ,
& notification . UpdatedAt )
2022-01-18 16:31:34 +00:00
if err != nil {
return nil , err
}
2022-10-25 22:06:20 +00:00
2022-01-18 16:31:34 +00:00
if chatID . Valid {
notification . ChatID = chatID . String
2022-10-25 22:06:20 +00:00
}
2022-01-18 16:31:34 +00:00
2022-10-25 22:06:20 +00:00
if communityID . Valid {
notification . CommunityID = communityID . String
2022-01-18 16:31:34 +00:00
}
if name . Valid {
notification . Name = name . String
}
if author . Valid {
notification . Author = author . String
}
// Restore last message
if lastMessageBytes != nil {
2023-08-18 11:39:59 +00:00
lastMessage := common . NewMessage ( )
2022-01-18 16:31:34 +00:00
if err = json . Unmarshal ( lastMessageBytes , lastMessage ) ; err != nil {
return nil , err
}
notification . LastMessage = lastMessage
}
// Restore message
if messageBytes != nil {
2023-08-18 11:39:59 +00:00
message := common . NewMessage ( )
2022-01-18 16:31:34 +00:00
if err = json . Unmarshal ( messageBytes , message ) ; err != nil {
return nil , err
}
notification . Message = message
}
// Restore reply message
if replyMessageBytes != nil {
2023-08-18 11:39:59 +00:00
replyMessage := common . NewMessage ( )
2022-01-18 16:31:34 +00:00
if err = json . Unmarshal ( replyMessageBytes , replyMessage ) ; err != nil {
return nil , err
}
notification . ReplyMessage = replyMessage
}
return notification , nil
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) unmarshalActivityCenterNotificationRows ( rows * sql . Rows ) ( string , [ ] * ActivityCenterNotification , error ) {
var notifications [ ] * ActivityCenterNotification
latestCursor := ""
for rows . Next ( ) {
var chatID sql . NullString
2022-10-25 22:06:20 +00:00
var communityID sql . NullString
2021-04-07 12:57:14 +00:00
var lastMessageBytes [ ] byte
2021-05-29 17:05:25 +00:00
var messageBytes [ ] byte
2021-07-15 20:21:44 +00:00
var replyMessageBytes [ ] byte
2021-04-07 12:57:14 +00:00
var name sql . NullString
2021-06-17 15:08:28 +00:00
var author sql . NullString
2021-04-07 12:57:14 +00:00
notification := & ActivityCenterNotification { }
err := rows . Scan (
& notification . ID ,
& notification . Timestamp ,
& notification . Type ,
& chatID ,
2022-10-25 22:06:20 +00:00
& communityID ,
& notification . MembershipStatus ,
2021-04-07 12:57:14 +00:00
& notification . Read ,
& notification . Accepted ,
& notification . Dismissed ,
2021-05-29 17:05:25 +00:00
& messageBytes ,
2021-04-07 12:57:14 +00:00
& lastMessageBytes ,
2021-07-15 20:21:44 +00:00
& replyMessageBytes ,
2022-08-31 14:41:58 +00:00
& notification . ContactVerificationStatus ,
2021-04-07 12:57:14 +00:00
& name ,
2021-06-17 15:08:28 +00:00
& author ,
2023-06-10 02:00:17 +00:00
& latestCursor ,
& notification . UpdatedAt )
2021-04-07 12:57:14 +00:00
if err != nil {
return "" , nil , err
}
2022-10-25 22:06:20 +00:00
2021-04-07 12:57:14 +00:00
if chatID . Valid {
notification . ChatID = chatID . String
2022-10-25 22:06:20 +00:00
}
2021-04-07 12:57:14 +00:00
2022-10-25 22:06:20 +00:00
if communityID . Valid {
notification . CommunityID = communityID . String
2021-04-07 12:57:14 +00:00
}
if name . Valid {
notification . Name = name . String
}
2021-06-17 15:08:28 +00:00
if author . Valid {
2021-06-21 15:39:00 +00:00
notification . Author = author . String
2021-06-17 15:08:28 +00:00
}
2021-04-07 12:57:14 +00:00
// Restore last message
if lastMessageBytes != nil {
2023-08-18 11:39:59 +00:00
lastMessage := common . NewMessage ( )
2021-05-29 17:05:25 +00:00
if err = json . Unmarshal ( lastMessageBytes , lastMessage ) ; err != nil {
return "" , nil , err
}
notification . LastMessage = lastMessage
}
// Restore message
if messageBytes != nil {
2023-08-18 11:39:59 +00:00
message := common . NewMessage ( )
2021-05-29 17:05:25 +00:00
if err = json . Unmarshal ( messageBytes , message ) ; err != nil {
2021-04-07 12:57:14 +00:00
return "" , nil , err
}
2021-05-29 17:05:25 +00:00
notification . Message = message
2021-04-07 12:57:14 +00:00
}
2021-07-15 20:21:44 +00:00
// Restore reply message
if replyMessageBytes != nil {
2023-08-18 11:39:59 +00:00
replyMessage := common . NewMessage ( )
2021-07-15 20:21:44 +00:00
if err = json . Unmarshal ( replyMessageBytes , replyMessage ) ; err != nil {
return "" , nil , err
}
notification . ReplyMessage = replyMessage
}
2021-04-07 12:57:14 +00:00
notifications = append ( notifications , notification )
}
return latestCursor , notifications , nil
}
2022-08-31 14:41:58 +00:00
type activityCenterQueryParams struct {
2023-01-20 12:45:32 +00:00
cursor string
limit uint64
ids [ ] types . HexBytes
chatID string
author string
read ActivityCenterQueryParamsRead
accepted bool
activityCenterTypes [ ] ActivityCenterType
2022-08-31 14:41:58 +00:00
}
2023-02-24 16:35:48 +00:00
func ( db sqlitePersistence ) prepareQueryConditionsAndArgs ( params activityCenterQueryParams ) ( [ ] interface { } , string ) {
2021-04-07 12:57:14 +00:00
var args [ ] interface { }
2023-01-28 09:52:53 +00:00
var conditions [ ] string
2022-08-31 14:41:58 +00:00
cursor := params . cursor
ids := params . ids
author := params . author
2023-01-20 12:45:32 +00:00
activityCenterTypes := params . activityCenterTypes
2022-08-31 14:41:58 +00:00
chatID := params . chatID
read := params . read
2023-01-20 12:45:32 +00:00
accepted := params . accepted
2021-11-25 15:21:42 +00:00
2021-04-07 12:57:14 +00:00
if cursor != "" {
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "cursor <= ?" )
2021-04-07 12:57:14 +00:00
args = append ( args , cursor )
}
if len ( ids ) != 0 {
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , fmt . Sprintf ( "a.id IN (%s)" , inVector ) )
2021-04-07 12:57:14 +00:00
for _ , id := range ids {
args = append ( args , id )
}
}
2022-08-31 14:41:58 +00:00
switch read {
2022-11-10 13:18:50 +00:00
case ActivityCenterQueryParamsReadRead :
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "a.read = 1" )
2022-11-10 13:18:50 +00:00
case ActivityCenterQueryParamsReadUnread :
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "NOT a.read" )
2022-08-31 14:41:58 +00:00
}
2023-01-20 12:45:32 +00:00
if ! accepted {
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "NOT a.accepted" )
2023-01-20 12:45:32 +00:00
}
2021-08-23 14:23:55 +00:00
if chatID != "" {
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "a.chat_id = ?" )
2021-08-23 14:23:55 +00:00
args = append ( args , chatID )
}
2021-11-25 15:21:42 +00:00
if author != "" {
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , "a.author = ?" )
2021-11-25 15:21:42 +00:00
args = append ( args , author )
}
2023-01-28 09:52:53 +00:00
if len ( activityCenterTypes ) > 0 {
2023-01-20 12:45:32 +00:00
inVector := strings . Repeat ( "?, " , len ( activityCenterTypes ) - 1 ) + "?"
2023-01-28 09:52:53 +00:00
conditions = append ( conditions , fmt . Sprintf ( "a.notification_type IN (%s)" , inVector ) )
2023-01-20 12:45:32 +00:00
for _ , activityCenterType := range activityCenterTypes {
args = append ( args , activityCenterType )
}
2021-11-25 15:21:42 +00:00
}
2023-02-24 23:47:04 +00:00
conditions = append ( conditions , "NOT a.deleted" )
2023-01-28 09:52:53 +00:00
var conditionsString string
if len ( conditions ) > 0 {
conditionsString = " WHERE " + strings . Join ( conditions , " AND " )
}
2023-02-24 16:35:48 +00:00
return args , conditionsString
}
func ( db sqlitePersistence ) buildActivityCenterQuery ( tx * sql . Tx , params activityCenterQueryParams ) ( string , [ ] * ActivityCenterNotification , error ) {
args , conditionsString := db . prepareQueryConditionsAndArgs ( params )
2021-04-07 12:57:14 +00:00
query := fmt . Sprintf ( // nolint: gosec
`
2023-01-20 12:45:32 +00:00
SELECT
a . id ,
a . timestamp ,
a . notification_type ,
a . chat_id ,
a . community_id ,
a . membership_status ,
a . read ,
a . accepted ,
a . dismissed ,
a . message ,
c . last_message ,
a . reply_message ,
a . contact_verification_status ,
c . name ,
a . author ,
2023-06-10 02:00:17 +00:00
substr ( ' 0000000000000000000000000000000000000000000000000000000000000000 ' || a . timestamp , - 64 , 64 ) || hex ( a . id ) as cursor ,
a . updated_at
2023-01-20 12:45:32 +00:00
FROM activity_center_notifications a
LEFT JOIN chats c
ON
c . id = a . chat_id
% s
2023-01-28 09:52:53 +00:00
ORDER BY cursor DESC ` , conditionsString )
2021-11-25 15:21:42 +00:00
2023-02-24 16:35:48 +00:00
if params . limit != 0 {
args = append ( args , params . limit )
2021-04-07 12:57:14 +00:00
query += ` LIMIT ? `
}
rows , err := tx . Query ( query , args ... )
if err != nil {
return "" , nil , err
}
2023-06-10 02:00:17 +00:00
defer rows . Close ( )
2023-01-28 09:52:53 +00:00
2021-04-07 12:57:14 +00:00
return db . unmarshalActivityCenterNotificationRows ( rows )
}
2023-02-24 16:35:48 +00:00
func ( db sqlitePersistence ) buildActivityCenterNotificationsCountQuery ( isAccepted bool , read ActivityCenterQueryParamsRead , activityCenterTypes [ ] ActivityCenterType ) * sql . Row {
params := activityCenterQueryParams {
accepted : isAccepted ,
read : read ,
activityCenterTypes : activityCenterTypes ,
}
args , conditionsString := db . prepareQueryConditionsAndArgs ( params )
query := fmt . Sprintf ( ` SELECT COUNT(1) FROM activity_center_notifications a %s ` , conditionsString )
return db . db . QueryRow ( query , args ... )
}
2021-12-02 14:23:02 +00:00
func ( db sqlitePersistence ) runActivityCenterIDQuery ( query string ) ( [ ] [ ] byte , error ) {
rows , err := db . db . Query ( query )
if err != nil {
return nil , err
}
var ids [ ] [ ] byte
for rows . Next ( ) {
var id [ ] byte
err = rows . Scan ( & id )
if err != nil {
return nil , err
}
ids = append ( ids , id )
}
return ids , nil
}
func ( db sqlitePersistence ) GetNotReadActivityCenterNotificationIds ( ) ( [ ] [ ] byte , error ) {
2023-06-10 02:00:17 +00:00
return db . runActivityCenterIDQuery ( "SELECT a.id FROM activity_center_notifications a WHERE NOT a.read AND NOT a.deleted" )
2021-12-02 14:23:02 +00:00
}
func ( db sqlitePersistence ) GetToProcessActivityCenterNotificationIds ( ) ( [ ] [ ] byte , error ) {
2023-02-24 23:47:04 +00:00
return db . runActivityCenterIDQuery ( `
SELECT a . id
FROM activity_center_notifications a
2023-06-10 02:00:17 +00:00
WHERE NOT a . dismissed AND NOT a . accepted AND NOT a . deleted
2023-02-24 23:47:04 +00:00
` )
2021-12-02 14:23:02 +00:00
}
2021-12-07 14:34:43 +00:00
func ( db sqlitePersistence ) HasPendingNotificationsForChat ( chatID string ) ( bool , error ) {
2023-02-24 23:47:04 +00:00
rows , err := db . db . Query ( `
SELECT 1 FROM activity_center_notifications a
WHERE a . chat_id = ?
AND NOT a . deleted
AND NOT a . dismissed
AND NOT a . accepted
` , chatID )
2021-12-07 14:34:43 +00:00
if err != nil {
return false , err
}
2022-02-23 11:09:46 +00:00
result := false
if rows . Next ( ) {
result = true
rows . Close ( )
}
2023-02-24 23:47:04 +00:00
err = rows . Err ( )
return result , err
2021-12-07 14:34:43 +00:00
}
2021-12-02 14:23:02 +00:00
func ( db sqlitePersistence ) GetActivityCenterNotificationsByID ( ids [ ] types . HexBytes ) ( [ ] * ActivityCenterNotification , error ) {
2023-10-22 09:41:20 +00:00
if len ( ids ) == 0 {
return emptyNotifications , nil
}
2021-12-02 14:23:02 +00:00
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-11-27 11:22:24 +00:00
// nolint: gosec
rows , err := db . db . Query (
`
SELECT
a . id ,
a . timestamp ,
a . notification_type ,
a . chat_id ,
a . community_id ,
a . membership_status ,
a . read ,
a . accepted ,
a . dismissed ,
a . message ,
c . last_message ,
a . reply_message ,
a . contact_verification_status ,
c . name ,
a . author ,
substr ( ' 0000000000000000000000000000000000000000000000000000000000000000 ' || a . timestamp , - 64 , 64 ) || hex ( a . id ) as cursor ,
a . updated_at
FROM activity_center_notifications a
LEFT JOIN chats c
ON
c . id = a . chat_id
WHERE a . id IN ( ` +inVector+ ` ) AND NOT a . deleted ` , idsArgs ... )
2021-12-02 14:23:02 +00:00
if err != nil {
return nil , err
}
2023-11-27 11:22:24 +00:00
_ , notifications , err := db . unmarshalActivityCenterNotificationRows ( rows )
if err != nil {
return nil , nil
2021-12-02 14:23:02 +00:00
}
return notifications , nil
}
2023-06-10 02:00:17 +00:00
// GetActivityCenterNotificationByID returns a notification by its ID even it's deleted logically
2022-01-18 16:31:34 +00:00
func ( db sqlitePersistence ) GetActivityCenterNotificationByID ( id types . HexBytes ) ( * ActivityCenterNotification , error ) {
row := db . db . QueryRow ( `
2023-01-20 12:45:32 +00:00
SELECT
a . id ,
a . timestamp ,
a . notification_type ,
a . chat_id ,
a . community_id ,
a . membership_status ,
a . read ,
a . accepted ,
a . dismissed ,
2023-02-24 23:47:04 +00:00
a . deleted ,
2023-01-20 12:45:32 +00:00
a . message ,
c . last_message ,
a . reply_message ,
a . contact_verification_status ,
c . name ,
2023-06-10 02:00:17 +00:00
a . author ,
a . updated_at
2023-01-20 12:45:32 +00:00
FROM activity_center_notifications a
LEFT JOIN chats c
ON
c . id = a . chat_id
WHERE a . id = ? ` , id )
2022-06-13 10:57:51 +00:00
notification , err := db . unmarshalActivityCenterNotificationRow ( row )
if err == sql . ErrNoRows {
return nil , nil
}
return notification , err
2022-01-18 16:31:34 +00:00
}
2022-08-31 14:41:58 +00:00
func ( db sqlitePersistence ) activityCenterNotifications ( params activityCenterQueryParams ) ( string , [ ] * ActivityCenterNotification , error ) {
2021-04-07 12:57:14 +00:00
var tx * sql . Tx
var err error
// We fetch limit + 1 to check for pagination
2022-08-31 14:41:58 +00:00
nonIncrementedLimit := params . limit
incrementedLimit := int ( params . limit ) + 1
2021-04-07 12:57:14 +00:00
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return "" , nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2022-08-31 14:41:58 +00:00
params . limit = uint64 ( incrementedLimit )
latestCursor , notifications , err := db . buildActivityCenterQuery ( tx , params )
2021-04-07 12:57:14 +00:00
if err != nil {
return "" , nil , err
}
if len ( notifications ) == incrementedLimit {
2022-08-31 14:41:58 +00:00
notifications = notifications [ 0 : nonIncrementedLimit ]
2021-04-07 12:57:14 +00:00
} else {
latestCursor = ""
}
return latestCursor , notifications , nil
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotifications ( updatedAt uint64 ) error {
_ , err := db . db . Exec ( ` UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE NOT dismissed AND NOT accepted AND NOT deleted ` , updatedAt )
2021-04-07 12:57:14 +00:00
return err
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromUser ( userPublicKey string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-06-10 02:00:17 +00:00
query := fmt . Sprintf ( ` SELECT % s FROM activity_center_notifications WHERE
author = ? AND
NOT deleted AND
NOT dismissed AND
NOT accepted ` , allFieldsForTableActivityCenterNotification )
2023-10-22 09:41:20 +00:00
rows , err := tx . Query ( query , userPublicKey )
2023-06-10 02:00:17 +00:00
if err != nil {
return nil , err
}
var notifications [ ] * ActivityCenterNotification
notifications , err = db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Read = true
notification . Dismissed = true
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( `
2023-02-24 23:47:04 +00:00
UPDATE activity_center_notifications
2023-06-10 02:00:17 +00:00
SET read = 1 , dismissed = 1 , updated_at = ?
2023-02-24 23:47:04 +00:00
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
` ,
2023-06-10 02:00:17 +00:00
updatedAt , userPublicKey )
2023-10-22 09:41:20 +00:00
if err != nil {
return nil , err
}
return notifications , updateActivityCenterState ( tx , updatedAt )
2023-02-24 23:47:04 +00:00
}
2023-10-22 09:41:20 +00:00
func ( db sqlitePersistence ) MarkActivityCenterNotificationsDeleted ( ids [ ] types . HexBytes , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2023-02-24 23:47:04 +00:00
if len ( ids ) == 0 {
2023-10-22 09:41:20 +00:00
return emptyNotifications , nil
2023-02-24 23:47:04 +00:00
}
2023-06-10 02:00:17 +00:00
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
2023-02-24 23:47:04 +00:00
for _ , id := range ids {
2023-06-10 02:00:17 +00:00
args = append ( args , id )
2023-02-24 23:47:04 +00:00
}
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-06-10 02:00:17 +00:00
// nolint: gosec
query := fmt . Sprintf ( ` SELECT %s FROM activity_center_notifications WHERE id IN (%s) AND NOT deleted ` ,
allFieldsForTableActivityCenterNotification ,
inVector )
2023-10-22 09:41:20 +00:00
rows , err := tx . Query ( query , args [ 1 : ] ... )
2023-06-10 02:00:17 +00:00
if err != nil {
return nil , err
}
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Deleted = true
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
2023-02-24 23:47:04 +00:00
2023-06-10 02:00:17 +00:00
update := "UPDATE activity_center_notifications SET deleted = 1, updated_at = ? WHERE id IN (" + inVector + ") AND NOT deleted"
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( update , args ... )
if err != nil {
return nil , err
}
2023-06-10 02:00:17 +00:00
2023-10-22 09:41:20 +00:00
return notifications , updateActivityCenterState ( tx , updatedAt )
2021-12-06 12:44:40 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DismissActivityCenterNotifications ( ids [ ] types . HexBytes , updatedAt uint64 ) error {
2023-02-24 23:47:04 +00:00
if len ( ids ) == 0 {
return nil
}
2021-04-07 12:57:14 +00:00
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
2021-04-07 12:57:14 +00:00
for _ , id := range ids {
2023-06-10 02:00:17 +00:00
args = append ( args , id )
2021-04-07 12:57:14 +00:00
}
2023-06-10 02:00:17 +00:00
args = append ( args , updatedAt )
2021-04-07 12:57:14 +00:00
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2021-04-07 12:57:14 +00:00
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-06-10 02:00:17 +00:00
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE id IN (" + inVector + ") AND not deleted AND updated_at < ?" // nolint: gosec
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( query , args ... )
if err != nil {
return err
}
return updateActivityCenterState ( tx , updatedAt )
2021-04-07 12:57:14 +00:00
}
2023-12-04 11:48:28 +00:00
func ( db sqlitePersistence ) DismissActivityCenterNotificationsByCommunity ( communityID string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE community_id = ? AND notification_type IN (?, ?) AND NOT deleted" // nolint: gosec
_ , err = tx . Exec ( query , updatedAt , communityID , ActivityCenterNotificationTypeCommunityRequest , ActivityCenterNotificationTypeCommunityKicked )
if err != nil {
return nil , err
}
_ , notifications , err := db . buildActivityCenterQuery ( tx , activityCenterQueryParams { } )
if err != nil {
return nil , err
}
return notifications , updateActivityCenterState ( tx , updatedAt )
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromCommunity ( communityID string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
2022-04-04 01:02:40 +00:00
2023-10-22 09:41:20 +00:00
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
chatIDs , err := db . AllChatIDsByCommunity ( tx , communityID )
2022-04-04 01:02:40 +00:00
if err != nil {
2023-06-10 02:00:17 +00:00
return nil , err
2022-04-04 01:02:40 +00:00
}
chatIDsCount := len ( chatIDs )
if chatIDsCount == 0 {
2023-06-10 02:00:17 +00:00
return nil , nil
2022-04-04 01:02:40 +00:00
}
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , chatIDsCount + 1 )
args = append ( args , updatedAt )
2022-04-04 01:02:40 +00:00
for _ , chatID := range chatIDs {
2023-06-10 02:00:17 +00:00
args = append ( args , chatID )
2022-04-04 01:02:40 +00:00
}
inVector := strings . Repeat ( "?, " , chatIDsCount - 1 ) + "?"
2023-10-22 09:41:20 +00:00
2023-06-10 02:00:17 +00:00
// nolint: gosec
query := fmt . Sprintf ( ` SELECT %s FROM activity_center_notifications WHERE chat_id IN (%s) AND NOT deleted ` , allFieldsForTableActivityCenterNotification , inVector )
2023-10-22 09:41:20 +00:00
rows , err := tx . Query ( query , args [ 1 : ] ... )
2023-06-10 02:00:17 +00:00
if err != nil {
return nil , err
}
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Read = true
notification . Dismissed = true
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
2022-04-04 01:02:40 +00:00
2023-06-10 02:00:17 +00:00
query = "UPDATE activity_center_notifications SET read = 1, dismissed = 1, updated_at = ? WHERE chat_id IN (" + inVector + ") AND NOT deleted" // nolint: gosec
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( query , args ... )
if err != nil {
return nil , err
}
return notifications , updateActivityCenterState ( tx , updatedAt )
2022-04-04 01:02:40 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromChatID ( chatID string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-06-10 02:00:17 +00:00
query := fmt . Sprintf ( ` SELECT % s FROM activity_center_notifications
WHERE chat_id = ?
AND NOT deleted
AND NOT accepted
AND notification_type != ? ` , allFieldsForTableActivityCenterNotification )
2023-10-22 09:41:20 +00:00
rows , err := tx . Query ( query , chatID , ActivityCenterNotificationTypeContactRequest )
2023-06-10 02:00:17 +00:00
if err != nil {
return nil , err
}
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Read = true
notification . Dismissed = true
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
2023-02-24 23:47:04 +00:00
// We exclude notifications related to contacts, since those we don't want to
// be cleared.
2023-06-10 02:00:17 +00:00
query = `
2023-02-24 23:47:04 +00:00
UPDATE activity_center_notifications
2023-06-10 02:00:17 +00:00
SET read = 1 , dismissed = 1 , updated_at = ?
WHERE chat_id = ?
AND NOT deleted
2023-02-24 23:47:04 +00:00
AND NOT accepted
AND notification_type != ?
`
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( query , updatedAt , chatID , ActivityCenterNotificationTypeContactRequest )
if err != nil {
return nil , err
}
return notifications , updateActivityCenterState ( tx , updatedAt )
2022-04-06 17:01:24 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) AcceptAllActivityCenterNotifications ( updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2021-04-07 12:57:14 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-01-20 12:45:32 +00:00
_ , notifications , err := db . buildActivityCenterQuery ( tx , activityCenterQueryParams { } )
2021-04-07 12:57:14 +00:00
if err != nil {
return nil , err
}
2023-06-10 02:00:17 +00:00
_ , err = tx . Exec ( ` UPDATE activity_center_notifications SET read = 1, accepted = 1, updated_at = ? WHERE NOT dismissed AND NOT accepted AND NOT deleted ` , updatedAt )
return notifications , err
2021-04-07 12:57:14 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) AcceptActivityCenterNotifications ( ids [ ] types . HexBytes , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2023-10-22 09:41:20 +00:00
if len ( ids ) == 0 {
return emptyNotifications , nil
}
2021-04-07 12:57:14 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
for _ , id := range ids {
args = append ( args , id )
}
args = append ( args , updatedAt )
2022-08-31 14:41:58 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
ids : ids ,
2022-08-31 14:41:58 +00:00
}
_ , notifications , err := db . buildActivityCenterQuery ( tx , params )
2021-04-07 12:57:14 +00:00
if err != nil {
return nil , err
}
2023-06-10 02:00:17 +00:00
var updateNotifications [ ] * ActivityCenterNotification
for _ , n := range notifications {
if n . UpdatedAt >= updatedAt {
continue
}
n . Read = true
n . Accepted = true
n . UpdatedAt = updatedAt
updateNotifications = append ( updateNotifications , n )
2021-04-07 12:57:14 +00:00
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-06-10 02:00:17 +00:00
query := "UPDATE activity_center_notifications SET read = 1, accepted = 1, updated_at = ? WHERE id IN (" + inVector + ") AND NOT deleted AND updated_at < ?" // nolint: gosec
_ , err = tx . Exec ( query , args ... )
2023-10-22 09:41:20 +00:00
if err != nil {
return nil , err
}
return updateNotifications , updateActivityCenterState ( tx , updatedAt )
2021-04-07 12:57:14 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) AcceptActivityCenterNotificationsForInvitesFromUser ( userPublicKey string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
2021-11-25 15:21:42 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2023-06-10 02:00:17 +00:00
query := fmt . Sprintf ( ` SELECT % s FROM activity_center_notifications
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
AND notification_type = ? ` , allFieldsForTableActivityCenterNotification )
rows , err := tx . Query ( query , userPublicKey , ActivityCenterNotificationTypeNewPrivateGroupChat )
if err != nil {
return nil , err
2022-08-31 14:41:58 +00:00
}
2023-06-10 02:00:17 +00:00
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Read = true
notification . Accepted = true
notification . UpdatedAt = updatedAt
} )
2021-11-25 15:21:42 +00:00
if err != nil {
return nil , err
}
2023-02-24 23:47:04 +00:00
_ , err = tx . Exec ( `
UPDATE activity_center_notifications
2023-06-10 02:00:17 +00:00
SET read = 1 , accepted = 1 , updated_at = ?
WHERE author = ?
2023-02-24 23:47:04 +00:00
AND NOT deleted
2023-06-10 02:00:17 +00:00
AND NOT dismissed
AND NOT accepted
2023-02-24 23:47:04 +00:00
AND notification_type = ?
` ,
2023-06-10 02:00:17 +00:00
updatedAt , userPublicKey , ActivityCenterNotificationTypeNewPrivateGroupChat )
2021-11-25 15:21:42 +00:00
if err != nil {
return nil , err
}
2023-10-22 09:41:20 +00:00
return notifications , updateActivityCenterState ( tx , updatedAt )
2021-11-25 15:21:42 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) MarkAllActivityCenterNotificationsRead ( updatedAt uint64 ) error {
2023-10-22 09:41:20 +00:00
tx , err := db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
_ , err = tx . Exec ( ` UPDATE activity_center_notifications SET read = 1, updated_at = ? WHERE NOT read AND NOT deleted ` , updatedAt )
if err != nil {
return err
}
_ , err = tx . Exec ( ` UPDATE activity_center_states SET has_seen = 1, updated_at = ? ` , updatedAt )
2021-04-07 12:57:14 +00:00
return err
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) MarkActivityCenterNotificationsRead ( ids [ ] types . HexBytes , updatedAt uint64 ) error {
2023-10-22 09:41:20 +00:00
if len ( ids ) == 0 {
return nil
}
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
2021-06-11 16:47:53 +00:00
for _ , id := range ids {
2023-06-10 02:00:17 +00:00
args = append ( args , id )
2021-06-11 16:47:53 +00:00
}
2023-06-10 02:00:17 +00:00
args = append ( args , updatedAt )
2021-06-11 16:47:53 +00:00
2023-10-22 09:41:20 +00:00
var tx * sql . Tx
var err error
tx , err = db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
2021-06-11 16:47:53 +00:00
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-06-10 02:00:17 +00:00
query := "UPDATE activity_center_notifications SET read = 1, updated_at = ? WHERE id IN (" + inVector + ") AND NOT deleted AND updated_at < ?" // nolint: gosec
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( query , args ... )
if err != nil {
return err
}
return updateActivityCenterState ( tx , updatedAt )
2021-06-11 16:47:53 +00:00
}
2023-10-22 09:41:20 +00:00
func updateActivityCenterState ( tx * sql . Tx , updatedAt uint64 ) error {
var unreadCount int
err := tx . QueryRow ( "SELECT COUNT(1) FROM activity_center_notifications WHERE read = 0 AND deleted = 0" ) . Scan ( & unreadCount )
if err != nil {
return err
}
var hasSeen int
if unreadCount == 0 {
hasSeen = 1
}
_ , err = tx . Exec ( ` UPDATE activity_center_states SET has_seen = ?, updated_at = ? ` , hasSeen , updatedAt )
return err
}
2021-09-24 10:57:15 +00:00
2023-10-22 09:41:20 +00:00
func ( db sqlitePersistence ) MarkActivityCenterNotificationsUnread ( ids [ ] types . HexBytes , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
if len ( ids ) == 0 {
return emptyNotifications , nil
}
2023-06-10 02:00:17 +00:00
args := make ( [ ] interface { } , 0 , len ( ids ) + 1 )
args = append ( args , updatedAt )
2021-09-24 10:57:15 +00:00
for _ , id := range ids {
2023-06-10 02:00:17 +00:00
args = append ( args , id )
2021-09-24 10:57:15 +00:00
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-06-10 02:00:17 +00:00
// nolint: gosec
query := fmt . Sprintf ( "SELECT %s FROM activity_center_notifications WHERE id IN (%s) AND NOT deleted" , allFieldsForTableActivityCenterNotification , inVector )
2023-10-22 09:41:20 +00:00
tx , err := db . db . BeginTx ( context . Background ( ) , & sql . TxOptions { } )
if err != nil {
return nil , err
}
defer func ( ) {
if err == nil {
err = tx . Commit ( )
return
}
// don't shadow original error
_ = tx . Rollback ( )
} ( )
rows , err := tx . Query ( query , args [ 1 : ] ... )
2023-06-10 02:00:17 +00:00
if err != nil {
return nil , err
}
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Read = false
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
2023-10-22 09:41:20 +00:00
if len ( notifications ) == 0 {
return notifications , nil
}
2023-06-10 02:00:17 +00:00
query = "UPDATE activity_center_notifications SET read = 0, updated_at = ? WHERE id IN (" + inVector + ") AND NOT deleted" // nolint: gosec
2023-10-22 09:41:20 +00:00
_ , err = tx . Exec ( query , args ... )
if err != nil {
return nil , err
}
_ , err = tx . Exec ( ` UPDATE activity_center_states SET has_seen = 0, updated_at = ? ` , updatedAt )
2023-06-10 02:00:17 +00:00
return notifications , err
2021-09-24 10:57:15 +00:00
}
2023-03-03 14:31:48 +00:00
func ( db sqlitePersistence ) ActivityCenterNotifications ( cursor string , limit uint64 , activityTypes [ ] ActivityCenterType , readType ActivityCenterQueryParamsRead , accepted bool ) ( string , [ ] * ActivityCenterNotification , error ) {
params := activityCenterQueryParams {
activityCenterTypes : activityTypes ,
cursor : cursor ,
limit : limit ,
read : readType ,
accepted : accepted ,
}
2023-01-20 12:45:32 +00:00
2023-03-03 14:31:48 +00:00
return db . activityCenterNotifications ( params )
2023-02-24 16:35:48 +00:00
}
2023-03-03 14:31:48 +00:00
func ( db sqlitePersistence ) ActivityCenterNotificationsCount ( activityTypes [ ] ActivityCenterType , readType ActivityCenterQueryParamsRead , accepted bool ) ( uint64 , error ) {
2023-02-24 16:35:48 +00:00
var count uint64
err := db . buildActivityCenterNotificationsCountQuery ( accepted , readType , activityTypes ) . Scan ( & count )
2021-04-07 12:57:14 +00:00
return count , err
}
2022-06-13 10:57:51 +00:00
func ( db sqlitePersistence ) ActiveContactRequestNotification ( contactID string ) ( * ActivityCenterNotification , error ) {
2023-02-24 23:47:04 +00:00
// QueryRow expects a query that returns at most one row. In theory the query
// wouldn't even need the ORDER + LIMIT 1 because we expect only one active
// contact request per contact, but to avoid relying on the unpredictable
// behavior of the DB engine for sorting, we sort by notification.Timestamp
// DESC.
query := `
2023-01-20 12:45:32 +00:00
SELECT
2023-02-24 23:47:04 +00:00
a . id ,
a . timestamp ,
a . notification_type ,
a . chat_id ,
a . community_id ,
a . membership_status ,
a . read ,
a . accepted ,
a . dismissed ,
a . deleted ,
a . message ,
c . last_message ,
a . reply_message ,
a . contact_verification_status ,
c . name ,
2023-06-10 02:00:17 +00:00
a . author ,
a . updated_at
2023-01-20 12:45:32 +00:00
FROM activity_center_notifications a
2023-02-24 23:47:04 +00:00
LEFT JOIN chats c ON c . id = a . chat_id
2023-06-10 02:00:17 +00:00
WHERE a . author = ?
AND NOT a . deleted
2023-02-24 23:47:04 +00:00
AND NOT a . dismissed
AND NOT a . accepted
AND a . notification_type = ?
ORDER BY a . timestamp DESC
LIMIT 1
`
2023-06-10 02:00:17 +00:00
row := db . db . QueryRow ( query , contactID , ActivityCenterNotificationTypeContactRequest )
2022-06-13 10:57:51 +00:00
notification , err := db . unmarshalActivityCenterNotificationRow ( row )
if err == sql . ErrNoRows {
return nil , nil
}
return notification , err
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) DeleteChatContactRequestActivityCenterNotifications ( chatID string , updatedAt uint64 ) ( [ ] * ActivityCenterNotification , error ) {
query := fmt . Sprintf ( ` SELECT %s FROM activity_center_notifications WHERE chat_id = ? AND NOT deleted AND notification_type = ? ` , allFieldsForTableActivityCenterNotification )
rows , err := db . db . Query ( query , chatID , ActivityCenterNotificationTypeContactRequest )
if err != nil {
return nil , err
}
notifications , err := db . parseRowFromTableActivityCenterNotification ( rows , func ( notification * ActivityCenterNotification ) {
notification . Deleted = true
notification . UpdatedAt = updatedAt
} )
if err != nil {
return nil , err
}
_ , err = db . db . Exec ( `
UPDATE activity_center_notifications SET deleted = 1 , updated_at = ?
2023-02-24 23:47:04 +00:00
WHERE
chat_id = ?
2023-06-10 02:00:17 +00:00
AND NOT deleted
2023-02-24 23:47:04 +00:00
AND notification_type = ?
2023-06-10 02:00:17 +00:00
` , updatedAt , chatID , ActivityCenterNotificationTypeContactRequest )
return notifications , err
2022-06-13 10:57:51 +00:00
}
2023-02-17 10:08:08 +00:00
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) HasUnseenActivityCenterNotifications ( ) ( bool , uint64 , error ) {
row := db . db . QueryRow ( ` SELECT has_seen, updated_at FROM activity_center_states ` )
2023-02-17 10:08:08 +00:00
hasSeen := true
2023-06-10 02:00:17 +00:00
updatedAt := uint64 ( 0 )
err := row . Scan ( & hasSeen , & updatedAt )
return ! hasSeen , updatedAt , err
2023-02-17 10:08:08 +00:00
}
2023-06-10 02:00:17 +00:00
func ( db sqlitePersistence ) UpdateActivityCenterNotificationState ( state * ActivityCenterState ) ( int64 , error ) {
result , err := db . db . Exec ( ` UPDATE activity_center_states SET has_seen = ?, updated_at = ? WHERE updated_at < ? ` , state . HasSeen , state . UpdatedAt , state . UpdatedAt )
if err != nil {
return 0 , err
}
return result . RowsAffected ( )
2023-02-17 10:08:08 +00:00
}
func ( db sqlitePersistence ) GetActivityCenterState ( ) ( * ActivityCenterState , error ) {
2023-06-10 02:00:17 +00:00
unseen , updatedAt , err := db . HasUnseenActivityCenterNotifications ( )
2023-02-17 10:08:08 +00:00
if err != nil {
return nil , err
}
state := & ActivityCenterState {
2023-06-10 02:00:17 +00:00
HasSeen : ! unseen ,
UpdatedAt : updatedAt ,
2023-02-17 10:08:08 +00:00
}
return state , nil
}
2023-10-26 04:17:18 +00:00
func ( db sqlitePersistence ) UpdateActivityCenterState ( updatedAt uint64 ) ( * ActivityCenterState , error ) {
var unreadCount int
err := db . db . QueryRow ( "SELECT COUNT(1) FROM activity_center_notifications WHERE read = 0 AND deleted = 0" ) . Scan ( & unreadCount )
if err != nil {
return nil , err
}
var hasSeen int
if unreadCount == 0 {
hasSeen = 1
}
_ , err = db . db . Exec ( ` UPDATE activity_center_states SET has_seen = ?, updated_at = ? ` , hasSeen , updatedAt )
return & ActivityCenterState { HasSeen : hasSeen == 1 , UpdatedAt : updatedAt } , err
}