Suppress pushes for outgoing preview echoes
This commit is contained in:
@@ -604,6 +604,68 @@ public sealed class ApiSmokeTests : IDisposable
|
||||
Assert.Equal("hello ????", MessageTextSanitizer.CleanChatPreview("hello ????"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SyncDoesNotPushListPreviewEchoOfOwnOutgoingMessage()
|
||||
{
|
||||
var pushNotifications = new RecordingPushNotificationService();
|
||||
var bridge = new OutgoingPreviewEchoMaxBridgeClient(
|
||||
$"mock-self-echo-chat-{Guid.NewGuid():N}",
|
||||
"message from me");
|
||||
using var factory = _factory.WithWebHostBuilder(builder =>
|
||||
{
|
||||
builder.ConfigureTestServices(services =>
|
||||
{
|
||||
services.RemoveAll<IHostedService>();
|
||||
services.RemoveAll<IMaxBridgeClient>();
|
||||
services.RemoveAll<IPushNotificationService>();
|
||||
services.AddSingleton<IMaxBridgeClient>(bridge);
|
||||
services.AddSingleton<IPushNotificationService>(pushNotifications);
|
||||
});
|
||||
});
|
||||
using var client = factory.CreateClient();
|
||||
await LoginAsync(client);
|
||||
|
||||
Guid chatId;
|
||||
var sentAt = DateTimeOffset.UtcNow.AddSeconds(-20);
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<QMaxDbContext>();
|
||||
var chat = new Chat
|
||||
{
|
||||
ExternalId = bridge.ChatExternalId,
|
||||
Title = "Self Echo",
|
||||
LastMessagePreview = bridge.PreviewText,
|
||||
LastMessageAt = sentAt,
|
||||
UnreadCount = 0
|
||||
};
|
||||
db.Chats.Add(chat);
|
||||
db.Messages.Add(new Message
|
||||
{
|
||||
Chat = chat,
|
||||
ExternalId = "self-echo-message",
|
||||
Direction = MessageDirection.Outgoing,
|
||||
Text = bridge.PreviewText,
|
||||
SentAt = sentAt,
|
||||
DeliveryState = MessageDeliveryState.Sent
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
chatId = chat.Id;
|
||||
}
|
||||
|
||||
var sync = await client.PostAsync("/api/max/sync", null);
|
||||
await AssertStatusAsync(HttpStatusCode.OK, sync);
|
||||
|
||||
Assert.Empty(pushNotifications.SentMessages);
|
||||
using (var scope = factory.Services.CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<QMaxDbContext>();
|
||||
var chat = await db.Chats.FindAsync(chatId);
|
||||
Assert.NotNull(chat);
|
||||
Assert.Equal(0, chat!.UnreadCount);
|
||||
Assert.Equal(bridge.PreviewText, chat.LastMessagePreview);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FirebasePushSkipsOutgoingMessages()
|
||||
{
|
||||
@@ -749,6 +811,111 @@ public sealed class ApiSmokeTests : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class RecordingPushNotificationService : IPushNotificationService
|
||||
{
|
||||
public List<(Chat Chat, Message Message)> SentMessages { get; } = [];
|
||||
|
||||
public Task SendNewMessageAsync(Chat chat, Message message, CancellationToken cancellationToken)
|
||||
{
|
||||
SentMessages.Add((chat, message));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class OutgoingPreviewEchoMaxBridgeClient : IMaxBridgeClient
|
||||
{
|
||||
public OutgoingPreviewEchoMaxBridgeClient(string chatExternalId, string previewText)
|
||||
{
|
||||
ChatExternalId = chatExternalId;
|
||||
PreviewText = previewText;
|
||||
}
|
||||
|
||||
public string ChatExternalId { get; }
|
||||
public string PreviewText { get; }
|
||||
|
||||
public Task<MaxBridgeStatus> GetStatusAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxBridgeStatus("Test", true, "Authorized", "Ready", null, "Test", null, DateTimeOffset.UtcNow));
|
||||
}
|
||||
|
||||
public Task<MaxBridgeStatus> BeginPhoneLoginAsync(string phoneNumber, CancellationToken cancellationToken)
|
||||
{
|
||||
return GetStatusAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public Task<MaxBridgeStatus> SubmitLoginCodeAsync(string code, CancellationToken cancellationToken)
|
||||
{
|
||||
return GetStatusAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public Task<MaxBrowserSnapshot> GetSnapshotAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxBrowserSnapshot(null, "Test", "", "", DateTimeOffset.UtcNow));
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<MaxChatUpdate>> FetchUpdatesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<IReadOnlyList<MaxChatUpdate>>(
|
||||
[
|
||||
new MaxChatUpdate(
|
||||
ChatExternalId,
|
||||
"Self Echo",
|
||||
null,
|
||||
DateTimeOffset.UtcNow,
|
||||
[],
|
||||
PreviewText,
|
||||
null,
|
||||
null,
|
||||
DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(3)).ToString("HH:mm"))
|
||||
]);
|
||||
}
|
||||
|
||||
public Task<MaxChatUpdate?> FetchChatHistoryAsync(string externalChatId, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<MaxChatUpdate?>(null);
|
||||
}
|
||||
|
||||
public Task<MaxChatPresence?> FetchChatPresenceAsync(string externalChatId, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<MaxChatPresence?>(null);
|
||||
}
|
||||
|
||||
public Task<MaxSendResult> SendTextAsync(string externalChatId, string text, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxSendResult(true, $"external-{Guid.NewGuid():N}", null));
|
||||
}
|
||||
|
||||
public Task<MaxSendResult> SendAttachmentAsync(string externalChatId, string path, string caption, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxSendResult(true, $"external-file-{Guid.NewGuid():N}", null));
|
||||
}
|
||||
|
||||
public Task<MaxActionResult> EditMessageAsync(string externalChatId, string externalMessageId, string? currentText, string text, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxActionResult(true, null));
|
||||
}
|
||||
|
||||
public Task<MaxActionResult> DeleteMessageAsync(string externalChatId, string externalMessageId, string? currentText, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxActionResult(true, null));
|
||||
}
|
||||
|
||||
public Task<MaxActionResult> SetReactionAsync(string externalChatId, string externalMessageId, string? currentText, string emoji, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxActionResult(true, null));
|
||||
}
|
||||
|
||||
public Task<MaxActionResult> ClearReactionAsync(string externalChatId, string externalMessageId, string? currentText, string emoji, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(new MaxActionResult(true, null));
|
||||
}
|
||||
|
||||
public Task<MaxMediaDownload?> DownloadMediaAsync(string remoteUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<MaxMediaDownload?>(null);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FailingActionMaxBridgeClient : IMaxBridgeClient
|
||||
{
|
||||
public Task<MaxBridgeStatus> GetStatusAsync(CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user