add endpoint for getting emojis

This commit is contained in:
Andrea Maria Piana 2020-07-27 17:57:01 +02:00
parent 3e4e1ff663
commit 37a2073008
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
6 changed files with 166 additions and 10 deletions

View File

@ -47,15 +47,20 @@ func (e *EmojiReaction) SetMessageType(messageType protobuf.MessageType) {
e.MessageType = messageType e.MessageType = messageType
} }
func (e *EmojiReaction) MarshalJSON() ([]byte, error) { func (e EmojiReaction) MarshalJSON() ([]byte, error) {
type EmojiAlias EmojiReaction type EmojiAlias EmojiReaction
item := struct { item := struct {
*EmojiAlias EmojiAlias
ID string `json:"id"` ID string `json:"id"`
EmojiID protobuf.EmojiReaction_Type `json:"emojiId"`
}{ }{
EmojiAlias: (*EmojiAlias)(e), EmojiAlias: (EmojiAlias)(e),
ID: e.ID(), ID: e.ID(),
EmojiID: e.Type,
} }
// cleanup type
item.Type = 0
return json.Marshal(item) return json.Marshal(item)
} }

View File

@ -489,6 +489,64 @@ func (db sqlitePersistence) MessageByChatID(chatID string, currCursor string, li
return result, newCursor, nil return result, newCursor, nil
} }
// EmojiReactionsByChatID returns the emoji reactions for the queried messages, up to a maximum of 100, as it's a potentially unbound number.
// NOTE: This is not completely accurate, as the messages in the database might have change since the last call to `MessageByChatID`.
func (db sqlitePersistence) EmojiReactionsByChatID(chatID string, currCursor string, limit int) ([]*EmojiReaction, error) {
cursorWhere := ""
if currCursor != "" {
cursorWhere = "AND substr('0000000000000000000000000000000000000000000000000000000000000000' || m.clock_value, -64, 64) <= ?"
}
args := []interface{}{chatID}
if currCursor != "" {
args = append(args, currCursor)
}
// Build a new column `cursor` at the query time by having a fixed-sized clock value at the beginning
// concatenated with message ID. Results are sorted using this new column.
// This new column values can also be returned as a cursor for subsequent requests.
rows, err := db.db.Query(
fmt.Sprintf(`
SELECT
e.clock_value,
e.source,
e.emoji_id,
e.message_id,
e.chat_id,
e.retracted
FROM
emoji_reactions e
WHERE NOT(e.retracted)
AND
e.message_id IN
(SELECT id FROM user_messages m WHERE NOT(m.hide) AND m.local_chat_id = ? %s
ORDER BY substr('0000000000000000000000000000000000000000000000000000000000000000' || m.clock_value, -64, 64) || m.id DESC LIMIT ?)
LIMIT 100
`, cursorWhere),
append(args, limit)...,
)
if err != nil {
return nil, err
}
defer rows.Close()
var result []*EmojiReaction
for rows.Next() {
var emojiReaction EmojiReaction
err := rows.Scan(&emojiReaction.Clock,
&emojiReaction.From,
&emojiReaction.Type,
&emojiReaction.MessageId,
&emojiReaction.ChatId,
&emojiReaction.Retracted)
if err != nil {
return nil, err
}
result = append(result, &emojiReaction)
}
return result, nil
}
func (db sqlitePersistence) SaveMessages(messages []*Message) (err error) { func (db sqlitePersistence) SaveMessages(messages []*Message) (err error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{}) tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil { if err != nil {

View File

@ -279,7 +279,7 @@ func (s *MessageValidatorSuite) TestValidatePlainTextMessage() {
Timestamp: 3, Timestamp: 3,
ResponseTo: "", ResponseTo: "",
EnsName: "", EnsName: "",
MessageType: protobuf.ChatMessage_ONE_TO_ONE, MessageType: protobuf.MessageType_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_EMOJI, ContentType: protobuf.ChatMessage_EMOJI,
}, },
} }
@ -419,7 +419,7 @@ func (s *MessageValidatorSuite) TestValidatePlainTextMessage() {
Payload: []byte("some-payload"), Payload: []byte("some-payload"),
}, },
}, },
MessageType: protobuf.ChatMessage_ONE_TO_ONE, MessageType: protobuf.MessageType_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_AUDIO, ContentType: protobuf.ChatMessage_AUDIO,
}, },
}, },
@ -440,7 +440,7 @@ func (s *MessageValidatorSuite) TestValidatePlainTextMessage() {
Payload: []byte("some-payload"), Payload: []byte("some-payload"),
}, },
}, },
MessageType: protobuf.ChatMessage_ONE_TO_ONE, MessageType: protobuf.MessageType_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_STICKER, ContentType: protobuf.ChatMessage_STICKER,
}, },
}, },
@ -460,7 +460,7 @@ func (s *MessageValidatorSuite) TestValidatePlainTextMessage() {
Type: 1, Type: 1,
}, },
}, },
MessageType: protobuf.ChatMessage_ONE_TO_ONE, MessageType: protobuf.MessageType_ONE_TO_ONE,
ContentType: protobuf.ChatMessage_AUDIO, ContentType: protobuf.ChatMessage_AUDIO,
}, },
}, },

View File

@ -1410,8 +1410,6 @@ func (m *Messenger) SendChatMessage(ctx context.Context, message *Message) (*Mes
} }
} }
logger := m.logger.With(zap.String("site", "Send"), zap.String("chatID", message.ChatId))
var response MessengerResponse var response MessengerResponse
// A valid added chat is required. // A valid added chat is required.
@ -3277,6 +3275,10 @@ func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID str
return &response, nil return &response, nil
} }
func (m *Messenger) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*EmojiReaction, error) {
return m.persistence.EmojiReactionsByChatID(chatID, cursor, limit)
}
func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) { func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()

View File

@ -2,6 +2,7 @@ package protocol
import ( import (
"database/sql" "database/sql"
"fmt"
"io/ioutil" "io/ioutil"
"math" "math"
"sort" "sort"
@ -375,6 +376,92 @@ func TestUpdateMessageOutgoingStatus(t *testing.T) {
require.Equal(t, "new-status", m.OutgoingStatus) require.Equal(t, "new-status", m.OutgoingStatus)
} }
func TestPersistenceEmojiReactions(t *testing.T) {
db, err := openTestDB()
require.NoError(t, err)
p := sqlitePersistence{db: db}
// reverse order as we use DESC
id1 := "1"
id2 := "2"
id3 := "3"
from1 := "from-1"
from2 := "from-2"
from3 := "from-3"
chatID := "chat-id"
err = insertMinimalMessage(p, id1)
require.NoError(t, err)
err = insertMinimalMessage(p, id2)
require.NoError(t, err)
err = insertMinimalMessage(p, id3)
require.NoError(t, err)
// Insert normal emoji reaction
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
EmojiReaction: protobuf.EmojiReaction{
Clock: 1,
MessageId: id3,
ChatId: chatID,
Type: protobuf.EmojiReaction_SAD,
},
From: from1,
}))
// Insert retracted emoji reaction
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
EmojiReaction: protobuf.EmojiReaction{
Clock: 1,
MessageId: id3,
ChatId: chatID,
Type: protobuf.EmojiReaction_SAD,
Retracted: true,
},
From: from2,
}))
// Insert retracted emoji reaction out of pagination
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
EmojiReaction: protobuf.EmojiReaction{
Clock: 1,
MessageId: id1,
ChatId: chatID,
Type: protobuf.EmojiReaction_SAD,
},
From: from2,
}))
// Insert retracted emoji reaction out of pagination
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
EmojiReaction: protobuf.EmojiReaction{
Clock: 1,
MessageId: id1,
ChatId: chatID,
Type: protobuf.EmojiReaction_SAD,
},
From: from3,
}))
reactions, err := p.EmojiReactionsByChatID(chatID, "", 1)
require.NoError(t, err)
require.Len(t, reactions, 1)
require.Equal(t, id3, reactions[0].MessageId)
// Try with a cursor
_, cursor, err := p.MessageByChatID(chatID, "", 1)
require.NoError(t, err)
fmt.Println("CURSOR", cursor)
reactions, err = p.EmojiReactionsByChatID(chatID, cursor, 2)
require.NoError(t, err)
require.Len(t, reactions, 2)
require.Equal(t, id1, reactions[0].MessageId)
require.Equal(t, id1, reactions[1].MessageId)
}
func openTestDB() (*sql.DB, error) { func openTestDB() (*sql.DB, error) {
dbPath, err := ioutil.TempFile("", "") dbPath, err := ioutil.TempFile("", "")
if err != nil { if err != nil {

View File

@ -522,6 +522,10 @@ func (api *PublicAPI) SendEmojiReactionRetraction(ctx context.Context, emojiReac
return api.service.messenger.SendEmojiReactionRetraction(ctx, emojiReactionID) return api.service.messenger.SendEmojiReactionRetraction(ctx, emojiReactionID)
} }
func (api *PublicAPI) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*protocol.EmojiReaction, error) {
return api.service.messenger.EmojiReactionsByChatID(chatID, cursor, limit)
}
// Echo is a method for testing purposes. // Echo is a method for testing purposes.
func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) { func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) {
return message, nil return message, nil