Add channel & user filters to the app

This commit is contained in:
chylex 2021-11-29 15:16:35 +01:00
parent c0123b9f91
commit 96e125b812
No known key found for this signature in database
GPG Key ID: 4DE42C8F19A80548
13 changed files with 404 additions and 95 deletions

View File

@ -8,6 +8,7 @@
<entry key="Desktop/Dialogs/MessageDialog.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Dialogs/ProgressDialog.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Main/AboutWindow.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Main/Controls/FilterPanel.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Main/Controls/StatusBar.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Main/MainContentScreen.axaml" value="Desktop/Desktop.csproj" />
<entry key="Desktop/Main/MainWindow.axaml" value="Desktop/Desktop.csproj" />

View File

@ -0,0 +1,60 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:DHT.Desktop.Main.Controls"
mc:Ignorable="d"
x:Class="DHT.Desktop.Main.Controls.FilterPanel">
<Design.DataContext>
<controls:FilterPanelModel />
</Design.DataContext>
<UserControl.Styles>
<Style Selector="WrapPanel">
<Setter Property="Background" Value="#FFFFFF" />
</Style>
<Style Selector="WrapPanel > StackPanel">
<Setter Property="Margin" Value="0 20 40 0" />
<Setter Property="Spacing" Value="4" />
</Style>
<Style Selector="Grid > Label">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style Selector="Grid > CalendarDatePicker">
<Setter Property="CornerRadius" Value="0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="IsTodayHighlighted" Value="True" />
<Setter Property="SelectedDateFormat" Value="Short" />
</Style>
<Style Selector="Button">
<Setter Property="Margin" Value="0 0 0 8" />
</Style>
</UserControl.Styles>
<WrapPanel>
<StackPanel>
<CheckBox IsChecked="{Binding FilterByDate}">Filter by Date</CheckBox>
<Grid ColumnDefinitions="Auto, 4, 140" RowDefinitions="Auto, 4, Auto" Margin="4 0">
<Label Grid.Row="0" Grid.Column="0">From:</Label>
<CalendarDatePicker Grid.Row="0" Grid.Column="2" x:Name="StartDatePicker" IsEnabled="{Binding FilterByDate}" SelectedDateChanged="CalendarDatePicker_OnSelectedDateChanged" />
<Label Grid.Row="2" Grid.Column="0">To:</Label>
<CalendarDatePicker Grid.Row="2" Grid.Column="2" x:Name="EndDatePicker" IsEnabled="{Binding FilterByDate}" SelectedDateChanged="CalendarDatePicker_OnSelectedDateChanged" />
</Grid>
</StackPanel>
<StackPanel>
<CheckBox IsChecked="{Binding FilterByChannel}">Filter by Channel</CheckBox>
<Button Command="{Binding OpenChannelFilterDialog}" IsEnabled="{Binding FilterByChannel}">Select Channels...</Button>
<TextBlock Text="{Binding ChannelFilterLabel}" />
</StackPanel>
<StackPanel>
<CheckBox IsChecked="{Binding FilterByUser}">Filter by User</CheckBox>
<Button Command="{Binding OpenUserFilterDialog}" IsEnabled="{Binding FilterByUser}">Select Users...</Button>
<TextBlock Text="{Binding UserFilterLabel}" />
</StackPanel>
</WrapPanel>
</UserControl>

View File

@ -0,0 +1,21 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace DHT.Desktop.Main.Controls {
public class FilterPanel : UserControl {
public FilterPanel() {
InitializeComponent();
}
private void InitializeComponent() {
AvaloniaXamlLoader.Load(this);
}
public void CalendarDatePicker_OnSelectedDateChanged(object? sender, SelectionChangedEventArgs e) {
if (DataContext is FilterPanelModel model) {
model.StartDate = this.FindControl<CalendarDatePicker>("StartDatePicker").SelectedDate;
model.EndDate = this.FindControl<CalendarDatePicker>("EndDatePicker").SelectedDate;
}
}
}
}

View File

@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using DHT.Desktop.Dialogs;
using DHT.Desktop.Models;
using DHT.Server.Data;
using DHT.Server.Data.Filters;
using DHT.Server.Database;
namespace DHT.Desktop.Main.Controls {
public class FilterPanelModel : BaseModel {
private static readonly HashSet<string> FilterProperties = new () {
nameof(FilterByDate),
nameof(StartDate),
nameof(EndDate),
nameof(FilterByChannel),
nameof(IncludedChannels),
nameof(FilterByUser),
nameof(IncludedUsers)
};
public event PropertyChangedEventHandler? FilterPropertyChanged;
private bool filterByDate = false;
private DateTime? startDate = null;
private DateTime? endDate = null;
private bool filterByChannel = false;
private HashSet<ulong>? includedChannels = null;
private bool filterByUser = false;
private HashSet<ulong>? includedUsers = null;
public bool FilterByDate {
get => filterByDate;
set => Change(ref filterByDate, value);
}
public DateTime? StartDate {
get => startDate;
set => Change(ref startDate, value);
}
public DateTime? EndDate {
get => endDate;
set => Change(ref endDate, value);
}
public bool FilterByChannel {
get => filterByChannel;
set => Change(ref filterByChannel, value);
}
public HashSet<ulong> IncludedChannels {
get => includedChannels ?? db.GetAllChannels().Select(channel => channel.Id).ToHashSet();
set => Change(ref includedChannels, value);
}
public bool FilterByUser {
get => filterByUser;
set => Change(ref filterByUser, value);
}
public HashSet<ulong> IncludedUsers {
get => includedUsers ?? db.GetAllUsers().Select(user => user.Id).ToHashSet();
set => Change(ref includedUsers, value);
}
private string channelFilterLabel = "";
public string ChannelFilterLabel {
get => channelFilterLabel;
set => Change(ref channelFilterLabel, value);
}
private string userFilterLabel = "";
public string UserFilterLabel {
get => userFilterLabel;
set => Change(ref userFilterLabel, value);
}
private readonly Window window;
private readonly IDatabaseFile db;
[Obsolete("Designer")]
public FilterPanelModel() : this(null!, DummyDatabaseFile.Instance) {}
public FilterPanelModel(Window window, IDatabaseFile db) {
this.window = window;
this.db = db;
UpdateChannelFilterLabel();
UpdateUserFilterLabel();
PropertyChanged += OnPropertyChanged;
db.Statistics.PropertyChanged += OnDbStatisticsChanged;
}
private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) {
if (e.PropertyName != null && FilterProperties.Contains(e.PropertyName)) {
FilterPropertyChanged?.Invoke(sender, e);
}
if (e.PropertyName is nameof(FilterByChannel) or nameof(IncludedChannels)) {
UpdateChannelFilterLabel();
}
else if (e.PropertyName is nameof(FilterByUser) or nameof(IncludedUsers)) {
UpdateUserFilterLabel();
}
}
private void OnDbStatisticsChanged(object? sender, PropertyChangedEventArgs e) {
if (e.PropertyName == nameof(DatabaseStatistics.TotalChannels)) {
UpdateChannelFilterLabel();
}
else if (e.PropertyName == nameof(DatabaseStatistics.TotalUsers)) {
UpdateUserFilterLabel();
}
}
public async void OpenChannelFilterDialog() {
var servers = db.GetAllServers().ToDictionary(server => server.Id);
var items = new List<CheckBoxItem<ulong>>();
var included = IncludedChannels;
foreach (var channel in db.GetAllChannels()) {
var channelId = channel.Id;
var channelName = channel.Name;
string title;
if (servers.TryGetValue(channel.Server, out var server)) {
var titleBuilder = new StringBuilder();
var serverType = server.Type;
titleBuilder.Append('[')
.Append(ServerTypes.ToString(serverType))
.Append("] ");
if (serverType == ServerType.DirectMessage) {
titleBuilder.Append(channelName);
}
else {
titleBuilder.Append(server.Name)
.Append(" - ")
.Append(channelName);
}
title = titleBuilder.ToString();
}
else {
title = channelName;
}
items.Add(new CheckBoxItem<ulong>(channelId) {
Title = title,
Checked = included.Contains(channelId)
});
}
var result = await OpenIdFilterDialog(window, "Included Channels", items);
if (result != null) {
IncludedChannels = result;
}
}
public async void OpenUserFilterDialog() {
var items = new List<CheckBoxItem<ulong>>();
var included = IncludedUsers;
foreach (var user in db.GetAllUsers()) {
var name = user.Name;
var discriminator = user.Discriminator;
items.Add(new CheckBoxItem<ulong>(user.Id) {
Title = discriminator == null ? name : name + " #" + discriminator,
Checked = included.Contains(user.Id)
});
}
var result = await OpenIdFilterDialog(window, "Included Users", items);
if (result != null) {
IncludedUsers = result;
}
}
private void UpdateChannelFilterLabel() {
long total = db.Statistics.TotalChannels;
long included = FilterByChannel ? IncludedChannels.Count : total;
ChannelFilterLabel = "Selected " + included + " / " + total + (total == 1 ? " channel." : " channels.");
}
private void UpdateUserFilterLabel() {
long total = db.Statistics.TotalUsers;
long included = FilterByUser ? IncludedUsers.Count : total;
UserFilterLabel = "Selected " + included + " / " + total + (total == 1 ? " user." : " users.");
}
public MessageFilter CreateFilter() {
MessageFilter filter = new();
if (FilterByDate) {
filter.StartDate = StartDate;
filter.EndDate = EndDate;
}
if (FilterByChannel) {
filter.ChannelIds = new HashSet<ulong>(IncludedChannels);
}
if (FilterByUser) {
filter.UserIds = new HashSet<ulong>(IncludedUsers);
}
return filter;
}
private static async Task<HashSet<ulong>?> OpenIdFilterDialog(Window window, string title, List<CheckBoxItem<ulong>> items) {
items.Sort((item1, item2) => item1.Title.CompareTo(item2.Title));
var model = new CheckBoxDialogModel<ulong>(items) {
Title = title
};
var dialog = new CheckBoxDialog { DataContext = model };
var result = await dialog.ShowDialog<DialogResult.OkCancel>(window);
return result == DialogResult.OkCancel.Ok ? model.SelectedItems.Select(item => item.Item).ToHashSet() : null;
}
}
}

View File

@ -3,6 +3,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pages="clr-namespace:DHT.Desktop.Main.Pages"
xmlns:controls="clr-namespace:DHT.Desktop.Main.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="DHT.Desktop.Main.Pages.ViewerPage">
@ -10,36 +11,13 @@
<pages:ViewerPageModel />
</Design.DataContext>
<UserControl.Styles>
<Style Selector="Grid > Label">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style Selector="Grid > CalendarDatePicker">
<Setter Property="CornerRadius" Value="0" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="IsTodayHighlighted" Value="True" />
<Setter Property="SelectedDateFormat" Value="Short" />
</Style>
</UserControl.Styles>
<StackPanel Orientation="Vertical" Spacing="20">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Button Command="{Binding OnClickOpenViewer}" Margin="0 0 5 0">Open Viewer</Button>
<Button Command="{Binding OnClickSaveViewer}" Margin="5 0 0 0">Save Viewer</Button>
</StackPanel>
<TextBlock Text="{Binding ExportedMessageText}" />
<StackPanel>
<CheckBox IsChecked="{Binding FilterByDate}">Filter by Date</CheckBox>
<Grid ColumnDefinitions="Auto, 4, 140" RowDefinitions="Auto, 4, Auto" Margin="4">
<Label Grid.Row="0" Grid.Column="0">From:</Label>
<CalendarDatePicker Grid.Row="0" Grid.Column="2" x:Name="StartDatePicker" IsEnabled="{Binding FilterByDate}" SelectedDateChanged="CalendarDatePicker_OnSelectedDateChanged" />
<Label Grid.Row="2" Grid.Column="0">To:</Label>
<CalendarDatePicker Grid.Row="2" Grid.Column="2" x:Name="EndDatePicker" IsEnabled="{Binding FilterByDate}" SelectedDateChanged="CalendarDatePicker_OnSelectedDateChanged" />
</Grid>
</StackPanel>
<TextBlock Text="{Binding ExportedMessageText}" Margin="0 20 0 0" />
<controls:FilterPanel DataContext="{Binding FilterModel}" />
</StackPanel>
</UserControl>

View File

@ -10,12 +10,5 @@ namespace DHT.Desktop.Main.Pages {
private void InitializeComponent() {
AvaloniaXamlLoader.Load(this);
}
public void CalendarDatePicker_OnSelectedDateChanged(object? sender, SelectionChangedEventArgs e) {
if (DataContext is ViewerPageModel model) {
model.StartDate = this.FindControl<CalendarDatePicker>("StartDatePicker").SelectedDate;
model.EndDate = this.FindControl<CalendarDatePicker>("EndDatePicker").SelectedDate;
}
}
}
}

View File

@ -6,9 +6,9 @@ using System.IO;
using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using DHT.Desktop.Main.Controls;
using DHT.Desktop.Models;
using DHT.Desktop.Resources;
using DHT.Server.Data.Filters;
using DHT.Server.Database;
using DHT.Server.Database.Export;
@ -16,26 +16,7 @@ namespace DHT.Desktop.Main.Pages {
public class ViewerPageModel : BaseModel {
public string ExportedMessageText { get; private set; } = "";
private bool filterByDate = false;
public bool FilterByDate {
get => filterByDate;
set => Change(ref filterByDate, value);
}
private DateTime? startDate = null;
public DateTime? StartDate {
get => startDate;
set => Change(ref startDate, value);
}
private DateTime? endDate = null;
public DateTime? EndDate {
get => endDate;
set => Change(ref endDate, value);
}
private FilterPanelModel FilterModel { get; }
private readonly Window window;
private readonly IDatabaseFile db;
@ -47,15 +28,14 @@ namespace DHT.Desktop.Main.Pages {
this.window = window;
this.db = db;
this.PropertyChanged += OnPropertyChanged;
this.FilterModel = new FilterPanelModel(window, db);
this.FilterModel.FilterPropertyChanged += OnFilterPropertyChanged;
this.db.Statistics.PropertyChanged += OnDbStatisticsChanged;
UpdateStatistics();
}
private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) {
if (e.PropertyName is nameof(FilterByDate) or nameof(StartDate) or nameof(EndDate)) {
UpdateStatistics();
}
private void OnFilterPropertyChanged(object? sender, PropertyChangedEventArgs e) {
UpdateStatistics();
}
private void OnDbStatisticsChanged(object? sender, PropertyChangedEventArgs e) {
@ -64,24 +44,13 @@ namespace DHT.Desktop.Main.Pages {
}
}
private MessageFilter CreateFilter() {
MessageFilter filter = new();
if (FilterByDate) {
filter.StartDate = StartDate;
filter.EndDate = EndDate;
}
return filter;
}
private void UpdateStatistics() {
ExportedMessageText = "Will export " + db.CountMessages(CreateFilter()) + " out of " + db.Statistics.TotalMessages + " message(s).";
ExportedMessageText = "Will export " + db.CountMessages(FilterModel.CreateFilter()) + " out of " + db.Statistics.TotalMessages + " message(s).";
OnPropertyChanged(nameof(ExportedMessageText));
}
private async Task<string> GenerateViewerContents() {
string json = ViewerJsonExport.Generate(db, CreateFilter());
string json = ViewerJsonExport.Generate(db, FilterModel.CreateFilter());
string index = await ResourceLoader.ReadTextAsync("Viewer/index.html");
string viewer = index.Replace("/*[JS]*/", await ResourceLoader.ReadJoinedAsync("Viewer/scripts/", '\n'))

View File

@ -6,6 +6,8 @@ namespace DHT.Server.Data.Filters {
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public HashSet<ulong> MessageIds { get; } = new();
public HashSet<ulong>? ChannelIds { get; set; } = null;
public HashSet<ulong>? UserIds { get; set; } = null;
public HashSet<ulong>? MessageIds { get; set; } = null;
}
}

View File

@ -5,6 +5,7 @@ namespace DHT.Server.Database {
public class DatabaseStatistics : INotifyPropertyChanged {
private long totalServers;
private long totalChannels;
private long totalUsers;
private long totalMessages;
public long TotalServers {
@ -17,6 +18,11 @@ namespace DHT.Server.Database {
internal set => Change(out totalChannels, value);
}
public long TotalUsers {
get => totalUsers;
internal set => Change(out totalUsers, value);
}
public long TotalMessages {
get => totalMessages;
internal set => Change(out totalMessages, value);
@ -33,6 +39,7 @@ namespace DHT.Server.Database {
return new DatabaseStatistics {
totalServers = totalServers,
totalChannels = totalChannels,
totalUsers = TotalUsers,
totalMessages = totalMessages
};
}

View File

@ -8,26 +8,48 @@ using DHT.Server.Data.Filters;
namespace DHT.Server.Database.Export {
public static class ViewerJsonExport {
public static string Generate(IDatabaseFile db, MessageFilter? filter = null) {
JsonSerializerOptions opts = new();
var includedUserIds = new HashSet<ulong>();
var includedChannelIds = new HashSet<ulong>();
var includedServerIds = new HashSet<ulong>();
var includedMessages = db.GetMessages(filter);
var includedChannels = new List<Channel>();
foreach (var message in includedMessages) {
includedUserIds.Add(message.Sender);
includedChannelIds.Add(message.Channel);
}
foreach (var channel in db.GetAllChannels()) {
if (includedChannelIds.Contains(channel.Id)) {
includedChannels.Add(channel);
includedServerIds.Add(channel.Server);
}
}
var opts = new JsonSerializerOptions();
opts.Converters.Add(new ViewerJsonSnowflakeSerializer());
var users = GenerateUserList(db, out var userindex, out var userIndices);
var servers = GenerateServerList(db, out var serverindex);
var channels = GenerateChannelList(db, serverindex);
var users = GenerateUserList(db, includedUserIds, out var userindex, out var userIndices);
var servers = GenerateServerList(db, includedServerIds, out var serverindex);
var channels = GenerateChannelList(includedChannels, serverindex);
return JsonSerializer.Serialize(new {
meta = new { users, userindex, servers, channels },
data = GenerateMessageList(db, filter, userIndices)
data = GenerateMessageList(includedMessages, userIndices)
}, opts);
}
private static dynamic GenerateUserList(IDatabaseFile db, out List<string> userindex, out Dictionary<ulong, int> userIndices) {
private static dynamic GenerateUserList(IDatabaseFile db, HashSet<ulong> userIds, out List<string> userindex, out Dictionary<ulong, int> userIndices) {
var users = new Dictionary<string, dynamic>();
userindex = new List<string>();
userIndices = new Dictionary<ulong, int>();
foreach (var user in db.GetAllUsers()) {
var id = user.Id.ToString();
var id = user.Id;
if (!userIds.Contains(id)) {
continue;
}
dynamic obj = new ExpandoObject();
obj.name = user.Name;
@ -40,20 +62,26 @@ namespace DHT.Server.Database.Export {
obj.tag = user.Discriminator;
}
userIndices[user.Id] = users.Count;
userindex.Add(id);
users[id] = obj;
var idStr = id.ToString();
userIndices[id] = users.Count;
userindex.Add(idStr);
users[idStr] = obj;
}
return users;
}
private static dynamic GenerateServerList(IDatabaseFile db, out Dictionary<ulong, int> serverIndices) {
private static dynamic GenerateServerList(IDatabaseFile db, HashSet<ulong> serverIds, out Dictionary<ulong, int> serverIndices) {
var servers = new List<dynamic>();
serverIndices = new Dictionary<ulong, int>();
foreach (var server in db.GetAllServers()) {
serverIndices[server.Id] = servers.Count;
var id = server.Id;
if (!serverIds.Contains(id)) {
continue;
}
serverIndices[id] = servers.Count;
servers.Add(new {
name = server.Name,
type = ServerTypes.ToJsonViewerString(server.Type)
@ -63,10 +91,10 @@ namespace DHT.Server.Database.Export {
return servers;
}
private static dynamic GenerateChannelList(IDatabaseFile db, Dictionary<ulong, int> serverIndices) {
private static dynamic GenerateChannelList(List<Channel> includedChannels, Dictionary<ulong, int> serverIndices) {
var channels = new Dictionary<string, dynamic>();
foreach (var channel in db.GetAllChannels()) {
foreach (var channel in includedChannels) {
dynamic obj = new ExpandoObject();
obj.server = serverIndices[channel.Server];
obj.name = channel.Name;
@ -93,10 +121,10 @@ namespace DHT.Server.Database.Export {
return channels;
}
private static dynamic GenerateMessageList(IDatabaseFile db, MessageFilter? filter, Dictionary<ulong, int> userIndices) {
private static dynamic GenerateMessageList(List<Message> includedMessages, Dictionary<ulong, int> userIndices) {
var data = new Dictionary<string, Dictionary<string, dynamic>>();
foreach (var grouping in db.GetMessages(filter).GroupBy(message => message.Channel)) {
foreach (var grouping in includedMessages.GroupBy(message => message.Channel)) {
var channel = grouping.Key.ToString();
var channelData = new Dictionary<string, dynamic>();

View File

@ -32,6 +32,7 @@ namespace DHT.Server.Database.Sqlite {
this.Statistics = new DatabaseStatistics();
UpdateServerStatistics();
UpdateChannelStatistics();
UpdateUserStatistics();
UpdateMessageStatistics();
}
@ -129,6 +130,7 @@ namespace DHT.Server.Database.Sqlite {
}
tx.Commit();
UpdateUserStatistics();
}
public List<User> GetAllUsers() {
@ -369,6 +371,11 @@ namespace DHT.Server.Database.Sqlite {
Statistics.TotalChannels = cmd.ExecuteScalar() as long? ?? 0;
}
private void UpdateUserStatistics() {
using var cmd = conn.Command("SELECT COUNT(*) FROM users");
Statistics.TotalUsers = cmd.ExecuteScalar() as long? ?? 0;
}
private void UpdateMessageStatistics() {
using var cmd = conn.Command("SELECT COUNT(*) FROM messages");
Statistics.TotalMessages = cmd.ExecuteScalar() as long? ?? 0L;

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DHT.Server.Data.Filters;
namespace DHT.Server.Database.Sqlite {
@ -20,8 +19,16 @@ namespace DHT.Server.Database.Sqlite {
conditions.Add("timestamp <= " + new DateTimeOffset(filter.EndDate.Value).ToUnixTimeMilliseconds());
}
if (filter.MessageIds.Count > 0) {
conditions.Add("(" + string.Join(" OR ", filter.MessageIds.Select(id => "message_id = " + id)) + ")");
if (filter.ChannelIds != null) {
conditions.Add("channel_id IN (" + string.Join(",", filter.ChannelIds) + ")");
}
if (filter.UserIds != null) {
conditions.Add("sender_id IN (" + string.Join(",", filter.UserIds) + ")");
}
if (filter.MessageIds != null) {
conditions.Add("message_id IN (" + string.Join(",", filter.MessageIds) + ")");
}
return conditions.Count == 0 ? "" : " WHERE " + string.Join(" AND ", conditions);

View File

@ -22,17 +22,19 @@ namespace DHT.Server.Endpoints {
throw new HttpException(HttpStatusCode.BadRequest, "Expected root element to be an array.");
}
var addedMessageIdFilter = new MessageFilter();
var addedMessageIds = new HashSet<ulong>();
var messages = new Message[root.GetArrayLength()];
int i = 0;
foreach (JsonElement ele in root.EnumerateArray()) {
var message = ReadMessage(ele, "message");
messages[i++] = message;
addedMessageIdFilter.MessageIds.Add(message.Id);
addedMessageIds.Add(message.Id);
}
bool anyNewMessages = Db.CountMessages(addedMessageIdFilter) < messages.Length;
var addedMessageFilter = new MessageFilter { MessageIds = addedMessageIds };
bool anyNewMessages = Db.CountMessages(addedMessageFilter) < messages.Length;
Db.AddMessages(messages);
return (HttpStatusCode.OK, anyNewMessages ? 1 : 0);