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"
)
func ( db sqlitePersistence ) DeleteActivityCenterNotification ( id [ ] byte ) error {
_ , err := db . db . Exec ( ` DELETE FROM activity_center_notifications WHERE id = ? ` , id )
return err
}
2021-08-23 14:23:55 +00:00
func ( db sqlitePersistence ) DeleteActivityCenterNotificationForMessage ( chatID string , messageID string ) error {
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 ( )
} ( )
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 {
return err
}
var ids [ ] types . HexBytes
for _ , notification := range notifications {
2022-09-12 13:39:07 +00:00
if notification . LastMessage != nil && notification . LastMessage . ID == messageID {
ids = append ( ids , notification . ID )
}
2021-08-23 14:23:55 +00:00
if notification . Message != nil && notification . Message . ID == messageID {
ids = append ( ids , notification . ID )
}
}
if len ( ids ) > 0 {
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2023-02-24 23:47:04 +00:00
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1, deleted = 1 WHERE id IN (" + inVector + ")" // nolint: gosec
2021-08-23 14:23:55 +00:00
_ , err = tx . Exec ( query , idsArgs ... )
return err
}
return nil
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) SaveActivityCenterNotification ( notification * ActivityCenterNotification ) error {
var tx * sql . Tx
var err error
err = notification . Valid ( )
if err != nil {
return err
}
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-11-19 14:32:04 +00:00
if notification . Type == ActivityCenterNotificationTypeNewOneToOne ||
notification . Type == ActivityCenterNotificationTypeNewPrivateGroupChat {
2023-02-21 18:08:11 +00:00
// Delete other notifications, so it pops us again if it was not dismissed
2021-06-29 08:27:11 +00:00
_ , err = tx . Exec ( ` DELETE FROM activity_center_notifications WHERE id = ? AND (dismissed OR accepted) ` , notification . ID )
2021-04-07 12:57:14 +00:00
if err != nil {
return err
}
}
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 {
return err
}
}
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 {
return err
}
}
2023-02-24 23:47:04 +00:00
_ , err = tx . Exec ( `
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 ,
deleted
)
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )
` ,
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-01-28 09:52:53 +00:00
)
2023-02-17 10:08:08 +00:00
// When we have inserted or updated unread notification - mark whole activity_center_settings as unseen
if err == nil && ! notification . Read {
_ , err = tx . Exec ( ` UPDATE activity_center_states SET has_seen = 0 ` )
}
2021-04-07 12:57:14 +00:00
return err
}
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 ,
& author )
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 {
lastMessage := & common . Message { }
if err = json . Unmarshal ( lastMessageBytes , lastMessage ) ; err != nil {
return nil , err
}
notification . LastMessage = lastMessage
}
// Restore message
if messageBytes != nil {
message := & common . Message { }
if err = json . Unmarshal ( messageBytes , message ) ; err != nil {
return nil , err
}
notification . Message = message
}
// Restore reply message
if replyMessageBytes != nil {
replyMessage := & common . Message { }
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 ,
2021-04-07 12:57:14 +00:00
& latestCursor )
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 {
2021-05-29 17:05:25 +00:00
lastMessage := & common . Message { }
if err = json . Unmarshal ( lastMessageBytes , lastMessage ) ; err != nil {
return "" , nil , err
}
notification . LastMessage = lastMessage
}
// Restore message
if messageBytes != nil {
2021-04-07 12:57:14 +00:00
message := & common . Message { }
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 {
replyMessage := & common . Message { }
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
2022-11-10 13:18:50 +00:00
type ActivityCenterQueryParamsRead uint
2022-08-31 14:41:58 +00:00
const (
2022-11-10 13:18:50 +00:00
ActivityCenterQueryParamsReadRead = iota + 1
ActivityCenterQueryParamsReadUnread
ActivityCenterQueryParamsReadAll
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-01-26 15:32:15 +00:00
substr ( ' 0000000000000000000000000000000000000000000000000000000000000000 ' || a . timestamp , - 64 , 64 ) || hex ( a . id ) as cursor
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-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 ) {
return db . runActivityCenterIDQuery ( "SELECT a.id FROM activity_center_notifications a WHERE NOT a.read" )
}
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
WHERE NOT a . deleted AND NOT a . dismissed AND NOT a . accepted
` )
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 ) {
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
rows , err := db . db . Query ( "SELECT a.id, a.read, a.accepted, a.dismissed FROM activity_center_notifications a WHERE a.id IN (" + inVector + ")" , idsArgs ... ) // nolint: gosec
if err != nil {
return nil , err
}
var notifications [ ] * ActivityCenterNotification
for rows . Next ( ) {
notification := & ActivityCenterNotification { }
err := rows . Scan (
& notification . ID ,
& notification . Read ,
& notification . Accepted ,
& notification . Dismissed )
if err != nil {
return nil , err
}
notifications = append ( notifications , notification )
}
return notifications , nil
}
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 ,
a . author
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
}
2023-01-20 12:45:32 +00:00
func ( db sqlitePersistence ) UnreadActivityCenterNotifications ( cursor string , limit uint64 , activityTypes [ ] ActivityCenterType ) ( string , [ ] * ActivityCenterNotification , error ) {
2022-08-31 14:41:58 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
activityCenterTypes : activityTypes ,
cursor : cursor ,
limit : limit ,
read : ActivityCenterQueryParamsReadUnread ,
2022-08-31 14:41:58 +00:00
}
return db . activityCenterNotifications ( params )
}
2023-01-20 12:45:32 +00:00
func ( db sqlitePersistence ) ReadActivityCenterNotifications ( cursor string , limit uint64 , activityTypes [ ] ActivityCenterType ) ( string , [ ] * ActivityCenterNotification , error ) {
2022-08-31 14:41:58 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
activityCenterTypes : activityTypes ,
cursor : cursor ,
limit : limit ,
read : ActivityCenterQueryParamsReadRead ,
2022-11-10 13:18:50 +00:00
}
return db . activityCenterNotifications ( params )
}
2023-01-20 12:45:32 +00:00
func ( db sqlitePersistence ) ActivityCenterNotificationsBy ( cursor string , limit uint64 , activityTypes [ ] ActivityCenterType , readType ActivityCenterQueryParamsRead , accepted bool ) ( string , [ ] * ActivityCenterNotification , error ) {
2022-11-10 13:18:50 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
activityCenterTypes : activityTypes ,
cursor : cursor ,
limit : limit ,
read : readType ,
accepted : accepted ,
2022-08-31 14:41:58 +00:00
}
return db . activityCenterNotifications ( params )
}
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
}
2022-08-31 14:41:58 +00:00
func ( db sqlitePersistence ) ActivityCenterNotifications ( currCursor string , limit uint64 ) ( string , [ ] * ActivityCenterNotification , error ) {
params := activityCenterQueryParams {
cursor : currCursor ,
limit : limit ,
}
return db . activityCenterNotifications ( params )
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotifications ( ) error {
2021-12-07 14:34:43 +00:00
_ , err := db . db . Exec ( ` UPDATE activity_center_notifications SET read = 1, dismissed = 1 WHERE NOT dismissed AND NOT accepted ` )
2021-04-07 12:57:14 +00:00
return err
}
2021-12-06 12:44:40 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromUser ( userPublicKey string ) error {
2023-02-24 23:47:04 +00:00
_ , err := db . db . Exec ( `
UPDATE activity_center_notifications
SET read = 1 , dismissed = 1
WHERE author = ?
AND NOT deleted
AND NOT dismissed
AND NOT accepted
` ,
userPublicKey )
return err
}
func ( db sqlitePersistence ) DeleteActivityCenterNotifications ( ids [ ] types . HexBytes ) error {
if len ( ids ) == 0 {
return nil
}
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
query := "UPDATE activity_center_notifications SET deleted = 1 WHERE id IN (" + inVector + ")"
_ , err := db . db . Exec ( query , idsArgs ... )
2021-12-06 12:44:40 +00:00
return err
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) DismissActivityCenterNotifications ( ids [ ] types . HexBytes ) error {
2023-02-24 23:47:04 +00:00
if len ( ids ) == 0 {
return nil
}
2021-04-07 12:57:14 +00:00
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2021-12-07 14:34:43 +00:00
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1 WHERE id IN (" + inVector + ")" // nolint: gosec
2021-04-07 12:57:14 +00:00
_ , err := db . db . Exec ( query , idsArgs ... )
return err
}
2022-04-04 01:02:40 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromCommunity ( communityID string ) error {
chatIDs , err := db . AllChatIDsByCommunity ( communityID )
if err != nil {
return err
}
chatIDsCount := len ( chatIDs )
if chatIDsCount == 0 {
return nil
}
chatIDsArgs := make ( [ ] interface { } , 0 , chatIDsCount )
for _ , chatID := range chatIDs {
chatIDsArgs = append ( chatIDsArgs , chatID )
}
inVector := strings . Repeat ( "?, " , chatIDsCount - 1 ) + "?"
query := "UPDATE activity_center_notifications SET read = 1, dismissed = 1 WHERE chat_id IN (" + inVector + ")" // nolint: gosec
_ , err = db . db . Exec ( query , chatIDsArgs ... )
return err
}
2022-04-06 17:01:24 +00:00
func ( db sqlitePersistence ) DismissAllActivityCenterNotificationsFromChatID ( chatID string ) error {
2023-02-24 23:47:04 +00:00
// We exclude notifications related to contacts, since those we don't want to
// be cleared.
query := `
UPDATE activity_center_notifications
SET read = 1 , dismissed = 1
WHERE NOT deleted
AND NOT accepted
AND chat_id = ?
AND notification_type != ?
`
_ , err := db . db . Exec ( query , chatID , ActivityCenterNotificationTypeContactRequest )
2022-04-06 17:01:24 +00:00
return err
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) AcceptAllActivityCenterNotifications ( ) ( [ ] * 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 ( )
} ( )
2023-01-20 12:45:32 +00:00
_ , notifications , err := db . buildActivityCenterQuery ( tx , activityCenterQueryParams { } )
2021-04-07 12:57:14 +00:00
2021-12-07 14:34:43 +00:00
_ , err = tx . Exec ( ` UPDATE activity_center_notifications SET read = 1, accepted = 1 WHERE NOT accepted AND NOT dismissed ` )
2021-04-07 12:57:14 +00:00
if err != nil {
return nil , err
}
return notifications , nil
}
func ( db sqlitePersistence ) AcceptActivityCenterNotifications ( ids [ ] types . HexBytes ) ( [ ] * 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 ( )
} ( )
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
}
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
2021-12-07 14:34:43 +00:00
query := "UPDATE activity_center_notifications SET read = 1, accepted = 1 WHERE id IN (" + inVector + ")" // nolint: gosec
2021-04-07 12:57:14 +00:00
_ , err = tx . Exec ( query , idsArgs ... )
return notifications , err
}
2021-11-25 15:21:42 +00:00
func ( db sqlitePersistence ) AcceptActivityCenterNotificationsForInvitesFromUser ( userPublicKey string ) ( [ ] * 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 ( )
} ( )
2022-08-31 14:41:58 +00:00
params := activityCenterQueryParams {
2023-01-20 12:45:32 +00:00
author : userPublicKey ,
activityCenterTypes : [ ] ActivityCenterType { ActivityCenterNotificationTypeNewPrivateGroupChat } ,
2022-08-31 14:41:58 +00:00
}
_ , notifications , err := db . buildActivityCenterQuery ( tx , params )
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
SET read = 1 , accepted = 1
WHERE NOT accepted
AND NOT dismissed
AND NOT deleted
AND author = ?
AND notification_type = ?
` ,
userPublicKey , ActivityCenterNotificationTypeNewPrivateGroupChat )
2021-11-25 15:21:42 +00:00
if err != nil {
return nil , err
}
return notifications , nil
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) MarkAllActivityCenterNotificationsRead ( ) error {
_ , err := db . db . Exec ( ` UPDATE activity_center_notifications SET read = 1 WHERE NOT read ` )
return err
}
2021-06-11 16:47:53 +00:00
func ( db sqlitePersistence ) MarkActivityCenterNotificationsRead ( ids [ ] types . HexBytes ) error {
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
query := "UPDATE activity_center_notifications SET read = 1 WHERE id IN (" + inVector + ")" // nolint: gosec
_ , err := db . db . Exec ( query , idsArgs ... )
return err
}
2021-09-24 10:57:15 +00:00
func ( db sqlitePersistence ) MarkActivityCenterNotificationsUnread ( ids [ ] types . HexBytes ) error {
idsArgs := make ( [ ] interface { } , 0 , len ( ids ) )
for _ , id := range ids {
idsArgs = append ( idsArgs , id )
}
inVector := strings . Repeat ( "?, " , len ( ids ) - 1 ) + "?"
query := "UPDATE activity_center_notifications SET read = 0 WHERE id IN (" + inVector + ")" // nolint: gosec
_ , err := db . db . Exec ( query , idsArgs ... )
return err
}
2021-04-07 12:57:14 +00:00
func ( db sqlitePersistence ) UnreadActivityCenterNotificationsCount ( ) ( uint64 , error ) {
var count uint64
2023-02-24 16:35:48 +00:00
err := db . buildActivityCenterNotificationsCountQuery ( true , ActivityCenterQueryParamsReadUnread , [ ] ActivityCenterType { } ) . Scan ( & count )
2023-01-20 12:45:32 +00:00
return count , err
}
2023-01-30 19:43:13 +00:00
func ( db sqlitePersistence ) UnreadAndAcceptedActivityCenterNotificationsCount ( activityTypes [ ] ActivityCenterType ) ( uint64 , error ) {
2023-01-20 12:45:32 +00:00
var count uint64
2023-02-24 23:47:04 +00:00
err := db . buildActivityCenterNotificationsCountQuery ( true , ActivityCenterQueryParamsReadUnread , activityTypes ) . Scan ( & count )
2023-02-24 16:35:48 +00:00
return count , err
}
func ( db sqlitePersistence ) ActivityCenterNotificationsCountBy ( activityTypes [ ] ActivityCenterType , readType ActivityCenterQueryParamsRead , accepted bool ) ( uint64 , error ) {
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 ,
a . author
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
WHERE NOT a . deleted
AND NOT a . dismissed
AND NOT a . accepted
AND a . notification_type = ?
AND a . author = ?
ORDER BY a . timestamp DESC
LIMIT 1
`
row := db . db . QueryRow ( query , ActivityCenterNotificationTypeContactRequest , contactID )
2022-06-13 10:57:51 +00:00
notification , err := db . unmarshalActivityCenterNotificationRow ( row )
if err == sql . ErrNoRows {
return nil , nil
}
return notification , err
}
2023-02-24 23:47:04 +00:00
func ( db sqlitePersistence ) HardDeleteChatContactRequestActivityCenterNotifications ( chatID string ) error {
_ , err := db . db . Exec ( `
DELETE FROM activity_center_notifications
WHERE
chat_id = ?
AND notification_type = ?
` , chatID , ActivityCenterNotificationTypeContactRequest )
2022-06-13 10:57:51 +00:00
return err
}
2023-02-17 10:08:08 +00:00
func ( db sqlitePersistence ) HasUnseenActivityCenterNotifications ( ) ( bool , error ) {
row := db . db . QueryRow ( ` SELECT has_seen FROM activity_center_states ` )
hasSeen := true
err := row . Scan ( & hasSeen )
return ! hasSeen , err
}
func ( db sqlitePersistence ) MarkAsSeenActivityCenterNotifications ( ) error {
_ , err := db . db . Exec ( ` UPDATE activity_center_states SET has_seen = 1 ` )
return err
}
func ( db sqlitePersistence ) GetActivityCenterState ( ) ( * ActivityCenterState , error ) {
unseen , err := db . HasUnseenActivityCenterNotifications ( )
if err != nil {
return nil , err
}
state := & ActivityCenterState {
HasSeen : ! unseen ,
}
return state , nil
}