2022-12-10 03:38:48 +01:00
package models
import (
"crypto/sha512"
"encoding/hex"
"fmt"
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
"strconv"
"strings"
"time"
)
type MessageFilter struct {
ConfirmedSubscriptionBy * UserID
2024-09-20 20:37:55 +02:00
SearchStringFTS * [ ] string
SearchStringPlain * [ ] string
2022-12-10 03:38:48 +01:00
Sender * [ ] UserID
ChannelNameCS * [ ] string // case-sensitive
ChannelNameCI * [ ] string // case-insensitive
ChannelID * [ ] ChannelID
SenderNameCS * [ ] string // case-sensitive
SenderNameCI * [ ] string // case-insensitive
2024-09-20 15:36:16 +02:00
HasSenderName * bool
2022-12-10 03:38:48 +01:00
SenderIP * [ ] string
TimestampCoalesce * time . Time
TimestampCoalesceAfter * time . Time
TimestampCoalesceBefore * time . Time
TimestampReal * time . Time
TimestampRealAfter * time . Time
TimestampRealBefore * time . Time
TimestampClient * time . Time
TimestampClientAfter * time . Time
TimestampClientBefore * time . Time
TitleCS * string // case-sensitive
TitleCI * string // case-insensitive
Priority * [ ] int
UserMessageID * [ ] string
2022-12-14 12:29:55 +01:00
OnlyDeleted bool
IncludeDeleted bool
2023-02-03 22:51:03 +01:00
CompatAcknowledged * bool
2023-05-27 18:51:20 +02:00
UsedKeyID * [ ] KeyTokenID
2022-12-10 03:38:48 +01:00
}
func ( f MessageFilter ) SQL ( ) ( string , string , sq . PP , error ) {
joinClause := ""
if f . ConfirmedSubscriptionBy != nil {
2022-12-21 18:14:13 +01:00
joinClause += " LEFT JOIN subscriptions AS subs on messages.channel_id = subs.channel_id "
2022-12-10 03:38:48 +01:00
}
2024-09-20 20:37:55 +02:00
if f . SearchStringFTS != nil {
2023-01-14 00:48:51 +01:00
joinClause += " JOIN messages_fts AS mfts on (mfts.rowid = messages.rowid) "
2022-12-10 03:38:48 +01:00
}
sqlClauses := make ( [ ] string , 0 )
params := sq . PP { }
2022-12-14 12:29:55 +01:00
if f . OnlyDeleted {
sqlClauses = append ( sqlClauses , "(deleted=1)" )
} else if f . IncludeDeleted {
// nothing, return all
} else {
sqlClauses = append ( sqlClauses , "(deleted=0)" ) // default
}
2022-12-10 03:38:48 +01:00
if f . ConfirmedSubscriptionBy != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(subs.subscriber_user_id = :%s AND subs.confirmed = 1)" , params . Add ( * f . ConfirmedSubscriptionBy ) ) )
2022-12-10 03:38:48 +01:00
}
if f . Sender != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . Sender {
filter = append ( filter , fmt . Sprintf ( "(sender_user_id = :%s)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . ChannelNameCI != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . ChannelNameCI {
filter = append ( filter , fmt . Sprintf ( "(messages.channel_internal_name = :%s COLLATE NOCASE)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . ChannelNameCS != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . ChannelNameCS {
filter = append ( filter , fmt . Sprintf ( "(messages.channel_internal_name = :%s COLLATE BINARY)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . ChannelID != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . ChannelID {
filter = append ( filter , fmt . Sprintf ( "(messages.channel_id = :%s)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . SenderNameCI != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . SenderNameCI {
filter = append ( filter , fmt . Sprintf ( "(sender_name = :%s COLLATE NOCASE)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(sender_name IS NOT NULL AND (" + strings . Join ( filter , " OR " ) + "))" )
}
if f . SenderNameCS != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . SenderNameCS {
filter = append ( filter , fmt . Sprintf ( "(sender_name = :%s COLLATE BINARY)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(sender_name IS NOT NULL AND (" + strings . Join ( filter , " OR " ) + "))" )
}
2024-09-20 15:36:16 +02:00
if f . HasSenderName != nil {
if * f . HasSenderName {
sqlClauses = append ( sqlClauses , "(sender_name IS NOT NULL)" )
} else {
sqlClauses = append ( sqlClauses , "(sender_name IS NULL)" )
}
}
2022-12-10 03:38:48 +01:00
if f . SenderIP != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . SenderIP {
filter = append ( filter , fmt . Sprintf ( "(sender_ip = :%s)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . TimestampCoalesce != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(COALESCE(timestamp_client, timestamp_real) = :%s)" , params . Add ( ( * f . TimestampCoalesce ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampCoalesceAfter != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(COALESCE(timestamp_client, timestamp_real) > :%s)" , params . Add ( ( * f . TimestampCoalesceAfter ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampCoalesceBefore != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(COALESCE(timestamp_client, timestamp_real) < :%s)" , params . Add ( ( * f . TimestampCoalesceBefore ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampReal != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_real = :%s)" , params . Add ( ( * f . TimestampRealAfter ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampRealAfter != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_real > :%s)" , params . Add ( ( * f . TimestampRealAfter ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampRealBefore != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_real < :%s)" , params . Add ( ( * f . TimestampRealBefore ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampClient != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_client IS NOT NULL AND timestamp_client = :%s)" , params . Add ( ( * f . TimestampClient ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampClientAfter != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_client IS NOT NULL AND timestamp_client > :%s)" , params . Add ( ( * f . TimestampClientAfter ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TimestampClientBefore != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(timestamp_client IS NOT NULL AND timestamp_client < :%s)" , params . Add ( ( * f . TimestampClientBefore ) . UnixMilli ( ) ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TitleCI != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(title = :%s COLLATE NOCASE)" , params . Add ( * f . TitleCI ) ) )
2022-12-10 03:38:48 +01:00
}
if f . TitleCS != nil {
2024-09-20 20:37:55 +02:00
sqlClauses = append ( sqlClauses , fmt . Sprintf ( "(title = :%s COLLATE BINARY)" , params . Add ( * f . TitleCI ) ) )
2022-12-10 03:38:48 +01:00
}
if f . Priority != nil {
prioList := "(" + strings . Join ( langext . ArrMap ( * f . Priority , func ( p int ) string { return strconv . Itoa ( p ) } ) , ", " ) + ")"
sqlClauses = append ( sqlClauses , "(priority IN " + prioList + ")" )
}
if f . UserMessageID != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . UserMessageID {
filter = append ( filter , fmt . Sprintf ( "(usr_message_id = :%s)" , params . Add ( v ) ) )
2022-12-10 03:38:48 +01:00
}
sqlClauses = append ( sqlClauses , "(usr_message_id IS NOT NULL AND (" + strings . Join ( filter , " OR " ) + "))" )
}
2023-02-03 22:51:03 +01:00
if f . CompatAcknowledged != nil {
joinClause += " LEFT JOIN compat_acks AS filter_compatack_compat_acks on messages.message_id = filter_compatack_compat_acks.message_id "
if * f . CompatAcknowledged {
sqlClauses = append ( sqlClauses , "(filter_compatack_compat_acks.message_id IS NOT NULL)" )
} else {
sqlClauses = append ( sqlClauses , "(filter_compatack_compat_acks.message_id IS NULL)" )
}
}
2023-05-27 18:51:20 +02:00
if f . UsedKeyID != nil {
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . UsedKeyID {
filter = append ( filter , fmt . Sprintf ( "(used_key_id = :%s)" , params . Add ( v ) ) )
2023-05-27 18:51:20 +02:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
2024-09-20 20:37:55 +02:00
if f . SearchStringFTS != nil {
2022-12-11 02:47:23 +01:00
filter := make ( [ ] string , 0 )
2024-09-20 20:37:55 +02:00
for _ , v := range * f . SearchStringFTS {
filter = append ( filter , fmt . Sprintf ( "(messages_fts match :%s)" , params . Add ( v ) ) )
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
if f . SearchStringPlain != nil {
filter := make ( [ ] string , 0 )
for _ , v := range * f . SearchStringPlain {
filter = append ( filter , fmt . Sprintf ( "instr(lower(messages.channel_internal_name), lower(:%s))" , params . Add ( v ) ) )
filter = append ( filter , fmt . Sprintf ( "instr(lower(messages.sender_name), lower(:%s))" , params . Add ( v ) ) )
filter = append ( filter , fmt . Sprintf ( "instr(lower(messages.title), lower(:%s))" , params . Add ( v ) ) )
filter = append ( filter , fmt . Sprintf ( "instr(lower(messages.content), lower(:%s))" , params . Add ( v ) ) )
2022-12-11 02:47:23 +01:00
}
sqlClauses = append ( sqlClauses , "(" + strings . Join ( filter , " OR " ) + ")" )
}
2022-12-10 03:38:48 +01:00
sqlClause := ""
if len ( sqlClauses ) > 0 {
sqlClause = strings . Join ( sqlClauses , " AND " )
2022-12-11 02:47:23 +01:00
} else {
sqlClause = "1=1"
2022-12-10 03:38:48 +01:00
}
return sqlClause , joinClause , params , nil
}
func ( f MessageFilter ) Hash ( ) string {
bh , err := dataext . StructHash ( f , dataext . StructHashOptions { HashAlgo : sha512 . New ( ) } )
if err != nil {
return "00000000"
}
str := hex . EncodeToString ( bh )
return str [ 0 : mathext . Min ( 8 , len ( bh ) ) ]
}