Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions go/chat/localizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,8 +845,9 @@ func (s *localizerPipeline) localizeConversation(ctx context.Context, uid gregor
var maxValidID chat1.MessageID
s.Debug(ctx, "localizing %d max msgs", len(maxMsgs))
for _, mm := range maxMsgs {
if mm.IsValid() &&
utils.IsSnippetChatMessageType(mm.GetMessageType()) &&
isValidSnippet := mm.IsValid() && utils.IsSnippetChatMessageType(mm.GetMessageType())
isEphemeralErr := mm.IsError() && mm.Error().IsEphemeral
if (isValidSnippet || isEphemeralErr) &&
(conversationLocal.Info.SnippetMsg == nil ||
conversationLocal.Info.SnippetMsg.GetMessageID() < mm.GetMessageID()) {
conversationLocal.Info.SnippetMsg = new(chat1.MessageUnboxed)
Expand Down
19 changes: 14 additions & 5 deletions go/chat/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -1116,10 +1116,13 @@ func formatDuration(dur time.Duration) string {

func getMsgSnippetDecoration(msg chat1.MessageUnboxed) chat1.SnippetDecoration {
var msgBody chat1.MessageBody
if msg.IsValid() {
switch {
case msg.IsValid():
msgBody = msg.Valid().MessageBody
} else {
case msg.IsOutbox():
msgBody = msg.Outbox().Msg.MessageBody
default:
return chat1.SnippetDecoration_NONE
}
switch msg.GetMessageType() {
case chat1.MessageType_ATTACHMENT:
Expand Down Expand Up @@ -1220,14 +1223,20 @@ func GetMsgSnippetBody(ctx context.Context, g *globals.Context, uid gregor1.UID,
func GetMsgSnippet(ctx context.Context, g *globals.Context, uid gregor1.UID, msg chat1.MessageUnboxed,
conv chat1.ConversationLocal, currentUsername string,
) (decoration chat1.SnippetDecoration, snippet string, snippetDecorated string) {
if !msg.IsValid() && !msg.IsOutbox() {
return chat1.SnippetDecoration_NONE, "", ""
}
defer func() {
if len(snippetDecorated) == 0 {
snippetDecorated = snippet
}
}()
if !msg.IsValid() && !msg.IsOutbox() {
if msg.IsError() && msg.Error().IsEphemeral {
if msg.Error().IsEphemeralExpired(time.Now()) {
return chat1.SnippetDecoration_EXPLODED_MESSAGE, "Message exploded.", ""
}
return chat1.SnippetDecoration_EXPLODING_MESSAGE, msg.Error().ErrMsg, ""
}
return chat1.SnippetDecoration_NONE, "", ""
}

var senderUsername string
if msg.IsValid() {
Expand Down
30 changes: 30 additions & 0 deletions go/chat/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,36 @@ func TestSearchableRemoteConversationName(t *testing.T) {
searchableRemoteConversationNameFromStr("joshblum,zoommikem,mikem,zoomua,mikem", "mikem"))
}

func TestGetMsgSnippetEphemeralError(t *testing.T) {
ctx := context.Background()
conv := chat1.ConversationLocal{}
errMsg := "This exploding message is not available because this device was created after the message was sent"

// Non-expired ephemeral error: should surface the error message with EXPLODING_MESSAGE decoration.
msg := chat1.NewMessageUnboxedWithError(chat1.MessageUnboxedError{
ErrType: chat1.MessageUnboxedErrorType_EPHEMERAL,
ErrMsg: errMsg,
IsEphemeral: true,
Etime: gregor1.ToTime(time.Now().Add(time.Hour)),
MessageType: chat1.MessageType_TEXT,
})
decoration, snippet, _ := GetMsgSnippet(ctx, nil, gregor1.UID{}, msg, conv, "alice")
require.Equal(t, chat1.SnippetDecoration_EXPLODING_MESSAGE, decoration)
require.Equal(t, errMsg, snippet)

// Expired ephemeral error: should show "Message exploded." with EXPLODED_MESSAGE decoration.
msg = chat1.NewMessageUnboxedWithError(chat1.MessageUnboxedError{
ErrType: chat1.MessageUnboxedErrorType_EPHEMERAL,
ErrMsg: errMsg,
IsEphemeral: true,
Etime: gregor1.ToTime(time.Now().Add(-time.Hour)),
MessageType: chat1.MessageType_TEXT,
})
decoration, snippet, _ = GetMsgSnippet(ctx, nil, gregor1.UID{}, msg, conv, "alice")
require.Equal(t, chat1.SnippetDecoration_EXPLODED_MESSAGE, decoration)
require.Equal(t, "Message exploded.", snippet)
}

func TestStripUsernameFromConvName(t *testing.T) {
// Only the username as a complete segment is removed; "mikem" inside "zoommikem" must not be stripped
require.Equal(t, "joshblum,zoommikem,zoomua",
Expand Down
5 changes: 4 additions & 1 deletion go/ephemeral/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ func TestEphemeralPluralization(t *testing.T) {
require.Equal(t, humanMsg, pluralized)

pluralized = PluralizeErrorMessage(humanMsg, 2)
require.Equal(t, "2 exploding messages are not available, because this device was created after it was sent", pluralized)
require.Equal(t, "2 exploding messages are not available because this device was created after the messages were sent", pluralized)

pluralized = PluralizeErrorMessage(humanMsgWithPrefix(MemberAfterEKErrMsg), 3)
require.Equal(t, "3 exploding messages are not available because you joined the team after the messages were sent", pluralized)

pluralized = PluralizeErrorMessage(DefaultHumanErrMsg, 2)
require.Equal(t, "2 exploding messages are not available", pluralized)
Expand Down
10 changes: 5 additions & 5 deletions go/ephemeral/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ func newTransientEphemeralKeyError(err EphemeralKeyError) EphemeralKeyError {
const (
DefaultHumanErrMsg = "This exploding message is not available"
DefaultPluralHumanErrMsg = "%d exploding messages are not available"
DeviceCloneErrMsg = "cloned devices do not support exploding messages"
DeviceCloneWithOneshotErrMsg = "to support exploding messages in `oneshot` mode, you need a separate paper key for each running instance"
DeviceAfterEKErrMsg = "because this device was created after it was sent"
MemberAfterEKErrMsg = "because you joined the team after it was sent"
DeviceCloneErrMsg = "because this device has been cloned"
DeviceCloneWithOneshotErrMsg = "because this device is running in `oneshot` mode; to support exploding messages in `oneshot` mode, you need a separate paper key for each running instance"
DeviceAfterEKErrMsg = "because this device was created after the message was sent"
MemberAfterEKErrMsg = "because you joined the team after the message was sent"
DeviceStaleErrMsg = "because this device wasn't online to generate an exploding key"
UserStaleErrMsg = "because you weren't online to generate new exploding keys"
)
Expand Down Expand Up @@ -159,7 +159,7 @@ func humanMsgWithPrefix(humanMsg string) string {
if humanMsg == "" {
humanMsg = DefaultHumanErrMsg
} else if !strings.Contains(humanMsg, DefaultHumanErrMsg) {
humanMsg = fmt.Sprintf("%s, %s", DefaultHumanErrMsg, humanMsg)
humanMsg = fmt.Sprintf("%s %s", DefaultHumanErrMsg, humanMsg)
}
return humanMsg
}
Expand Down