mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-08 05:47:07 +09:00
GO-5344: Fix reading/un-reading
This commit is contained in:
parent
13ef3c7998
commit
b64be942db
6 changed files with 1540 additions and 1378 deletions
|
@ -56,9 +56,8 @@ func (d *ChatHandler) BeforeCreate(ctx context.Context, ch storestate.ChangeOp)
|
|||
msg.MentionRead = false
|
||||
} else {
|
||||
if ch.Change.Creator == d.currentIdentity {
|
||||
// TODO Return to true
|
||||
msg.Read = false
|
||||
msg.MentionRead = false
|
||||
msg.Read = true
|
||||
msg.MentionRead = true
|
||||
} else {
|
||||
msg.Read = false
|
||||
msg.MentionRead = false
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/anyproto/anytype-heart/core/block/editor/storestate"
|
||||
"github.com/anyproto/anytype-heart/core/block/source"
|
||||
"github.com/anyproto/anytype-heart/core/block/source/mock_source"
|
||||
"github.com/anyproto/anytype-heart/core/domain"
|
||||
"github.com/anyproto/anytype-heart/core/event/mock_event"
|
||||
"github.com/anyproto/anytype-heart/core/session"
|
||||
"github.com/anyproto/anytype-heart/pb"
|
||||
|
@ -25,6 +26,10 @@ import (
|
|||
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
|
||||
)
|
||||
|
||||
const (
|
||||
testSpaceId = "spaceId1"
|
||||
)
|
||||
|
||||
type accountServiceStub struct {
|
||||
accountId string
|
||||
}
|
||||
|
@ -86,7 +91,7 @@ func newFixture(t *testing.T) *fixture {
|
|||
|
||||
source := mock_source.NewMockStore(t)
|
||||
source.EXPECT().Id().Return("chatId1")
|
||||
source.EXPECT().SpaceID().Return("space1")
|
||||
source.EXPECT().SpaceID().Return(testSpaceId)
|
||||
source.EXPECT().ReadStoreDoc(ctx, mock.Anything, mock.Anything).Return(nil)
|
||||
source.EXPECT().PushStoreChange(mock.Anything, mock.Anything).RunAndReturn(fx.applyToStore).Maybe()
|
||||
|
||||
|
@ -400,13 +405,32 @@ func TestReadMessages(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
// All messages forced as not read
|
||||
messagesResp := fx.assertReadStatus(t, ctx, "", "", false)
|
||||
messagesResp := fx.assertReadStatus(t, ctx, "", "", false, false)
|
||||
|
||||
err := fx.MarkReadMessages(ctx, "", messagesResp.Messages[2].OrderId, messagesResp.ChatState.DbTimestamp, CounterTypeMessage)
|
||||
require.NoError(t, err)
|
||||
|
||||
fx.assertReadStatus(t, ctx, "", messagesResp.Messages[2].OrderId, true)
|
||||
fx.assertReadStatus(t, ctx, messagesResp.Messages[3].OrderId, "", false)
|
||||
fx.assertReadStatus(t, ctx, "", messagesResp.Messages[2].OrderId, true, false)
|
||||
fx.assertReadStatus(t, ctx, messagesResp.Messages[3].OrderId, "", false, false)
|
||||
}
|
||||
|
||||
func TestReadMentions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fx := newFixture(t)
|
||||
fx.chatHandler.forceNotRead = true
|
||||
const n = 10
|
||||
for i := 0; i < n; i++ {
|
||||
_, err := fx.AddMessage(ctx, nil, givenMessageWithMention(fmt.Sprintf("message %d", i+1)))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
// All messages forced as not read
|
||||
messagesResp := fx.assertReadStatus(t, ctx, "", "", false, false)
|
||||
|
||||
err := fx.MarkReadMessages(ctx, "", messagesResp.Messages[2].OrderId, messagesResp.ChatState.DbTimestamp, CounterTypeMention)
|
||||
require.NoError(t, err)
|
||||
|
||||
fx.assertReadStatus(t, ctx, "", messagesResp.Messages[2].OrderId, false, true)
|
||||
fx.assertReadStatus(t, ctx, messagesResp.Messages[3].OrderId, "", false, false)
|
||||
}
|
||||
|
||||
func TestMarkMessagesAsNotRead(t *testing.T) {
|
||||
|
@ -419,15 +443,33 @@ func TestMarkMessagesAsNotRead(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
// All messages added by myself are read
|
||||
fx.assertReadStatus(t, ctx, "", "", true)
|
||||
fx.assertReadStatus(t, ctx, "", "", true, true)
|
||||
|
||||
err := fx.MarkMessagesAsUnread(ctx, "", CounterTypeMessage)
|
||||
require.NoError(t, err)
|
||||
|
||||
fx.assertReadStatus(t, ctx, "", "", false)
|
||||
fx.assertReadStatus(t, ctx, "", "", false, true)
|
||||
}
|
||||
|
||||
func (fx *fixture) assertReadStatus(t *testing.T, ctx context.Context, afterOrderId string, beforeOrderId string, isRead bool) *GetMessagesResponse {
|
||||
func TestMarkMentionsAsNotRead(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fx := newFixture(t)
|
||||
|
||||
const n = 10
|
||||
for i := 0; i < n; i++ {
|
||||
_, err := fx.AddMessage(ctx, nil, givenMessageWithMention(fmt.Sprintf("message %d", i+1)))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
// All messages added by myself are read
|
||||
fx.assertReadStatus(t, ctx, "", "", true, true)
|
||||
|
||||
err := fx.MarkMessagesAsUnread(ctx, "", CounterTypeMention)
|
||||
require.NoError(t, err)
|
||||
|
||||
fx.assertReadStatus(t, ctx, "", "", true, false)
|
||||
}
|
||||
|
||||
func (fx *fixture) assertReadStatus(t *testing.T, ctx context.Context, afterOrderId string, beforeOrderId string, isRead bool, isMentionRead bool) *GetMessagesResponse {
|
||||
messageResp, err := fx.GetMessages(ctx, GetMessagesRequest{
|
||||
AfterOrderId: afterOrderId,
|
||||
BeforeOrderId: beforeOrderId,
|
||||
|
@ -438,6 +480,7 @@ func (fx *fixture) assertReadStatus(t *testing.T, ctx context.Context, afterOrde
|
|||
|
||||
for _, m := range messageResp.Messages {
|
||||
assert.Equal(t, isRead, m.Read)
|
||||
assert.Equal(t, isMentionRead, m.MentionRead)
|
||||
}
|
||||
return messageResp
|
||||
}
|
||||
|
@ -483,6 +526,29 @@ func givenSimpleMessage(text string) *Message {
|
|||
}
|
||||
}
|
||||
|
||||
func givenMessageWithMention(text string) *Message {
|
||||
return &Message{
|
||||
ChatMessage: &model.ChatMessage{
|
||||
Id: "",
|
||||
OrderId: "",
|
||||
Creator: "",
|
||||
Read: true,
|
||||
MentionRead: true,
|
||||
Message: &model.ChatMessageMessageContent{
|
||||
Text: text,
|
||||
Style: model.BlockContentText_Paragraph,
|
||||
Marks: []*model.BlockContentTextMark{
|
||||
{
|
||||
Type: model.BlockContentTextMark_Mention,
|
||||
Param: domain.NewParticipantId(testSpaceId, testCreator),
|
||||
Range: &model.Range{From: 0, To: 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func givenComplexMessage() *Message {
|
||||
return &Message{
|
||||
ChatMessage: &model.ChatMessage{
|
||||
|
|
|
@ -27,7 +27,8 @@ type counterOptions struct {
|
|||
readKey string
|
||||
messagesFilter query.Filter
|
||||
|
||||
readMessages func(newOldestOrderId string, idsModified []string)
|
||||
readMessages func(newOldestOrderId string, idsModified []string)
|
||||
unreadMessages func(newOldestOrderId string, lastAddedAt int64, msgIds []string)
|
||||
}
|
||||
|
||||
func (o *counterOptions) readModifier(value bool) query.Modifier {
|
||||
|
@ -55,6 +56,15 @@ func newCounterOptions(counterType CounterType, subscription *subscription) *cou
|
|||
})
|
||||
subscription.updateMessageRead(idsModified, true)
|
||||
}
|
||||
|
||||
opts.unreadMessages = func(newOldestOrderId string, lastAddedAt int64, msgIds []string) {
|
||||
subscription.updateChatState(func(state *model.ChatState) {
|
||||
state.Messages.OldestOrderId = newOldestOrderId
|
||||
state.DbTimestamp = int64(lastAddedAt)
|
||||
})
|
||||
subscription.updateMessageRead(msgIds, false)
|
||||
}
|
||||
|
||||
case CounterTypeMention:
|
||||
opts.unreadFilter = query.And{
|
||||
query.Key{Path: []string{hasMentionKey}, Filter: query.NewComp(query.CompOpEq, true)},
|
||||
|
@ -70,6 +80,14 @@ func newCounterOptions(counterType CounterType, subscription *subscription) *cou
|
|||
})
|
||||
subscription.updateMentionRead(idsModified, true)
|
||||
}
|
||||
|
||||
opts.unreadMessages = func(newOldestOrderId string, lastAddedAt int64, msgIds []string) {
|
||||
subscription.updateChatState(func(state *model.ChatState) {
|
||||
state.Mentions.OldestOrderId = newOldestOrderId
|
||||
state.DbTimestamp = int64(lastAddedAt)
|
||||
})
|
||||
subscription.updateMentionRead(msgIds, false)
|
||||
}
|
||||
default:
|
||||
panic("unknown counter type")
|
||||
}
|
||||
|
@ -127,11 +145,7 @@ func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId str
|
|||
return fmt.Errorf("get last added date: %w", err)
|
||||
}
|
||||
|
||||
s.subscription.updateChatState(func(state *model.ChatState) {
|
||||
state.Messages.OldestOrderId = newOldestOrderId
|
||||
state.DbTimestamp = int64(lastAdded)
|
||||
})
|
||||
s.subscription.updateMessageRead(msgs, false)
|
||||
opts.unreadMessages(newOldestOrderId, lastAdded, msgs)
|
||||
s.subscription.flush()
|
||||
|
||||
seenHeads, err := s.seenHeadsCollector.collectSeenHeads(ctx, afterOrderId)
|
||||
|
@ -286,7 +300,7 @@ func (s *storeObject) countUnreadMessages(txn anystore.ReadTx, opts *counterOpti
|
|||
return unreadQuery.Limit(1).Count(txn.Context())
|
||||
}
|
||||
|
||||
func (s *storeObject) getLastAddedDate(txn anystore.ReadTx) (int, error) {
|
||||
func (s *storeObject) getLastAddedDate(txn anystore.ReadTx) (int64, error) {
|
||||
lastAddedDate := s.collection.Find(nil).Sort(descAdded).Limit(1)
|
||||
iter, err := lastAddedDate.Iter(txn.Context())
|
||||
if err != nil {
|
||||
|
@ -303,7 +317,7 @@ func (s *storeObject) getLastAddedDate(txn anystore.ReadTx) (int, error) {
|
|||
if err != nil {
|
||||
return 0, fmt.Errorf("unmarshal message: %w", err)
|
||||
}
|
||||
return int(msg.AddedAt), nil
|
||||
return msg.AddedAt, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
|
|
@ -1476,6 +1476,7 @@
|
|||
- [Rpc.Chat.SubscribeLastMessages.Response.Error.Code](#anytype-Rpc-Chat-SubscribeLastMessages-Response-Error-Code)
|
||||
- [Rpc.Chat.SubscribeToMessagePreviews.Response.Error.Code](#anytype-Rpc-Chat-SubscribeToMessagePreviews-Response-Error-Code)
|
||||
- [Rpc.Chat.ToggleMessageReaction.Response.Error.Code](#anytype-Rpc-Chat-ToggleMessageReaction-Response-Error-Code)
|
||||
- [Rpc.Chat.Unread.ReadType](#anytype-Rpc-Chat-Unread-ReadType)
|
||||
- [Rpc.Chat.Unread.Response.Error.Code](#anytype-Rpc-Chat-Unread-Response-Error-Code)
|
||||
- [Rpc.Chat.Unsubscribe.Response.Error.Code](#anytype-Rpc-Chat-Unsubscribe-Response-Error-Code)
|
||||
- [Rpc.Chat.UnsubscribeFromMessagePreviews.Response.Error.Code](#anytype-Rpc-Chat-UnsubscribeFromMessagePreviews-Response-Error-Code)
|
||||
|
@ -11080,7 +11081,8 @@ Get marks list in the selected range in text block.
|
|||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| chatObjectId | [string](#string) | | id of the chat object |
|
||||
| type | [Rpc.Chat.Unread.ReadType](#anytype-Rpc-Chat-Unread-ReadType) | | |
|
||||
| chatObjectId | [string](#string) | | |
|
||||
| afterOrderId | [string](#string) | | |
|
||||
|
||||
|
||||
|
@ -23598,8 +23600,8 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er
|
|||
|
||||
| Name | Number | Description |
|
||||
| ---- | ------ | ----------- |
|
||||
| messages | 0 | |
|
||||
| replies | 1 | |
|
||||
| Messages | 0 | |
|
||||
| Mentions | 1 | |
|
||||
|
||||
|
||||
|
||||
|
@ -23656,6 +23658,18 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er
|
|||
|
||||
|
||||
|
||||
<a name="anytype-Rpc-Chat-Unread-ReadType"></a>
|
||||
|
||||
### Rpc.Chat.Unread.ReadType
|
||||
|
||||
|
||||
| Name | Number | Description |
|
||||
| ---- | ------ | ----------- |
|
||||
| Messages | 0 | |
|
||||
| Mentions | 1 | |
|
||||
|
||||
|
||||
|
||||
<a name="anytype-Rpc-Chat-Unread-Response-Error-Code"></a>
|
||||
|
||||
### Rpc.Chat.Unread.Response.Error.Code
|
||||
|
|
2770
pb/commands.pb.go
2770
pb/commands.pb.go
File diff suppressed because it is too large
Load diff
|
@ -8283,9 +8283,10 @@ message Rpc {
|
|||
|
||||
message ReadMessages {
|
||||
enum ReadType {
|
||||
messages = 0;
|
||||
replies = 1;
|
||||
Messages = 0;
|
||||
Mentions = 1;
|
||||
}
|
||||
|
||||
message Request {
|
||||
ReadType type = 1;
|
||||
string chatObjectId = 2; // id of the chat object
|
||||
|
@ -8314,8 +8315,14 @@ message Rpc {
|
|||
}
|
||||
|
||||
message Unread {
|
||||
enum ReadType {
|
||||
Messages = 0;
|
||||
Mentions = 1;
|
||||
}
|
||||
|
||||
message Request {
|
||||
string chatObjectId = 2; // id of the chat object
|
||||
ReadType type = 1;
|
||||
string chatObjectId = 2;
|
||||
string afterOrderId = 3;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue