add endpoint for getting emojis
This commit is contained in:
parent
3e4e1ff663
commit
37a2073008
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue