Some item templates and removal of sqlkata.
This commit is contained in:
@@ -46,7 +46,6 @@
|
||||
<PackageVersion Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="3.119.1" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.10.196-beta" />
|
||||
<PackageVersion Include="SqlKata" Version="4.0.1" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="10.0.0" />
|
||||
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.10" />
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
<PackageReference Include="NodaTime" />
|
||||
<PackageReference Include="Sentry.Serilog" />
|
||||
<PackageReference Include="SkiaSharp" />
|
||||
<PackageReference Include="SqlKata" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -32,9 +32,15 @@
|
||||
<ComboBox
|
||||
x:Name="MailOperationComboBox"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind AvailableMailOperations}"
|
||||
SelectedItem="{x:Bind SelectedMailOperation, Mode=TwoWay}" />
|
||||
SelectedItem="{x:Bind SelectedMailOperation, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
|
||||
<DataTemplate x:DataType="data:MailOperationViewModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Key Input -->
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<Identity
|
||||
Name="58272BurakKSE.WinoMailPreview"
|
||||
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
|
||||
Version="0.0.8.0" />
|
||||
Version="2.0.13.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="3879fcfb-a561-4599-9103-e0c9b35a271f" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
xmlns:data="using:Wino.Core.ViewModels.Data"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:interfaces="using:Wino.Core.Domain.Interfaces"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:selectors="using:Wino.Selectors"
|
||||
@@ -194,9 +195,14 @@
|
||||
<winuiControls:SettingsCard Description="{x:Bind domain:Translator.SettingsStartupItem_Description}" Header="{x:Bind domain:Translator.SettingsStartupItem_Title}">
|
||||
<ComboBox
|
||||
MinWidth="150"
|
||||
DisplayMemberPath="StartupEntityTitle"
|
||||
ItemsSource="{x:Bind ViewModel.Accounts, Mode=OneTime}"
|
||||
SelectedItem="{x:Bind ViewModel.StartupAccount, Mode=TwoWay}" />
|
||||
SelectedItem="{x:Bind ViewModel.StartupAccount, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="interfaces:IAccountProviderDetailViewModel">
|
||||
<TextBlock Text="{x:Bind StartupEntityTitle}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<winuiControls:SettingsCard.HeaderIcon>
|
||||
<SymbolIcon Symbol="Account" />
|
||||
</winuiControls:SettingsCard.HeaderIcon>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:entities="using:Wino.Core.Domain.Entities.Shared"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mail="using:Wino.Core.Domain.Entities.Mail"
|
||||
xmlns:mailkit="using:MimeKit"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
@@ -470,10 +471,15 @@
|
||||
<ComboBox
|
||||
x:Name="AccountsComboBox"
|
||||
Grid.Column="1"
|
||||
DisplayMemberPath="AliasAddress"
|
||||
IsEditable="False"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableAliases, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedAlias, Mode=TwoWay}" />
|
||||
SelectedItem="{x:Bind ViewModel.SelectedAlias, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="mail:MailAccountAlias">
|
||||
<TextBlock Text="{x:Bind AliasAddress}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<!-- To -->
|
||||
<TextBlock
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
x:Class="Wino.Views.ImapSetup.AdvancedImapSetupPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:accounts="using:Wino.Core.Domain.Models.Accounts"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
@@ -101,9 +102,14 @@
|
||||
<ComboBox
|
||||
x:Name="IncomingConnectionSecurity"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind AvailableConnectionSecurities}"
|
||||
SelectedIndex="0" />
|
||||
SelectedIndex="0">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapConnectionSecurityModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Authentication -->
|
||||
@@ -115,9 +121,14 @@
|
||||
<ComboBox
|
||||
x:Name="IncomingAuthenticationMethod"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind AvailableAuthenticationMethods}"
|
||||
SelectedIndex="0" />
|
||||
SelectedIndex="0">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapAuthenticationMethodModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -174,9 +185,15 @@
|
||||
<ComboBox
|
||||
x:Name="OutgoingConnectionSecurity"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind AvailableConnectionSecurities}"
|
||||
SelectedIndex="0" />
|
||||
SelectedIndex="0">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapConnectionSecurityModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- Authentication -->
|
||||
@@ -185,9 +202,14 @@
|
||||
<ComboBox
|
||||
x:Name="OutgoingAuthenticationMethod"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind AvailableAuthenticationMethods}"
|
||||
SelectedIndex="0" />
|
||||
SelectedIndex="0">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapAuthenticationMethodModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:accounts="using:Wino.Core.Domain.Models.Accounts"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converters="using:Wino.Core.WinUI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -138,18 +139,28 @@
|
||||
<ComboBox
|
||||
Grid.Row="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Header="{x:Bind domain:Translator.ImapAdvancedSetupDialog_ConnectionSecurity}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableConnectionSecurities}"
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedIncomingServerConnectionSecurityIndex, Mode=TwoWay}" />
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedIncomingServerConnectionSecurityIndex, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapConnectionSecurityModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox
|
||||
Grid.Row="6"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Header="{x:Bind domain:Translator.ImapAdvancedSetupDialog_AuthenticationMethod}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableAuthenticationMethods}"
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedIncomingServerAuthenticationMethodIndex, Mode=TwoWay}" />
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedIncomingServerAuthenticationMethodIndex, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapAuthenticationMethodModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Border
|
||||
Grid.RowSpan="6"
|
||||
@@ -193,19 +204,29 @@
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Header="{x:Bind domain:Translator.ImapAdvancedSetupDialog_ConnectionSecurity}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableConnectionSecurities}"
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedOutgoingServerConnectionSecurityIndex, Mode=TwoWay}" />
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedOutgoingServerConnectionSecurityIndex, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapConnectionSecurityModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox
|
||||
Grid.Row="6"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
DisplayMemberPath="DisplayName"
|
||||
Header="{x:Bind domain:Translator.ImapAdvancedSetupDialog_AuthenticationMethod}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableAuthenticationMethods}"
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedOutgoingServerAuthenticationMethodIndex, Mode=TwoWay}" />
|
||||
SelectedIndex="{x:Bind ViewModel.SelectedOutgoingServerAuthenticationMethodIndex, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="accounts:ImapAuthenticationMethodModel">
|
||||
<TextBlock Text="{x:Bind DisplayName}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="7"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -105,10 +105,15 @@
|
||||
</controls:SettingsCard.HeaderIcon>
|
||||
<controls:SettingsCard.Content>
|
||||
<ComboBox
|
||||
DisplayMemberPath="Title"
|
||||
IsEnabled="{x:Bind ViewModel.CanSelectElementTheme, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.ElementThemes}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedElementTheme, Mode=TwoWay}" />
|
||||
SelectedItem="{x:Bind ViewModel.SelectedElementTheme, Mode=TwoWay}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="personalization1:ElementThemeContainer">
|
||||
<TextBlock Text="{x:Bind Title}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</controls:SettingsCard.Content>
|
||||
</controls:SettingsCard>
|
||||
|
||||
|
||||
@@ -15,13 +15,20 @@
|
||||
<!-- AOT / Trimming -->
|
||||
<PublishAot Condition="'$(Configuration)' == 'Debug'">False</PublishAot>
|
||||
<PublishAot Condition="'$(Configuration)' != 'Debug'">True</PublishAot>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
|
||||
<!-- Trimming -->
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
|
||||
|
||||
<!-- Single instancing -->
|
||||
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\BadgeLogo.scale-100.png" />
|
||||
<Content Remove="Assets\BadgeLogo.scale-125.png" />
|
||||
@@ -269,13 +276,6 @@
|
||||
|
||||
<!-- Publish Properties -->
|
||||
<PropertyGroup>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
|
||||
<!-- Trimming -->
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
|
||||
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
|
||||
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
|
||||
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
|
||||
using CommunityToolkit.Diagnostics;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Serilog;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
@@ -55,14 +54,13 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
await Connection.ExecuteAsync("UPDATE MailAccount SET MergedInboxId = NULL WHERE MergedInboxId = ?", mergedInboxId);
|
||||
|
||||
// Then, add new accounts to merged inbox.
|
||||
var query = new Query("MailAccount")
|
||||
.WhereIn("Id", linkedAccountIds)
|
||||
.AsUpdate(new
|
||||
{
|
||||
MergedInboxId = mergedInboxId
|
||||
});
|
||||
var accountIdList = linkedAccountIds.ToList();
|
||||
var placeholders = string.Join(",", accountIdList.Select(_ => "?"));
|
||||
var sql = $"UPDATE MailAccount SET MergedInboxId = ? WHERE Id IN ({placeholders})";
|
||||
var parameters = new List<object> { mergedInboxId };
|
||||
parameters.AddRange(accountIdList.Cast<object>());
|
||||
|
||||
await Connection.ExecuteAsync(query.GetRawQuery());
|
||||
await Connection.ExecuteAsync(sql, parameters.ToArray());
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new AccountsMenuRefreshRequested());
|
||||
}
|
||||
@@ -84,14 +82,7 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
return;
|
||||
}
|
||||
|
||||
var query = new Query("MailAccount")
|
||||
.Where("MergedInboxId", mergedInboxId)
|
||||
.AsUpdate(new
|
||||
{
|
||||
MergedInboxId = (Guid?)null
|
||||
});
|
||||
|
||||
await Connection.ExecuteAsync(query.GetRawQuery()).ConfigureAwait(false);
|
||||
await Connection.ExecuteAsync("UPDATE MailAccount SET MergedInboxId = NULL WHERE MergedInboxId = ?", mergedInboxId).ConfigureAwait(false);
|
||||
await Connection.DeleteAsync<MergedInbox>(mergedInbox).ConfigureAwait(false);
|
||||
|
||||
// Change the startup entity id if it was the merged inbox.
|
||||
@@ -191,14 +182,7 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
public async Task RenameMergedAccountAsync(Guid mergedInboxId, string newName)
|
||||
{
|
||||
var query = new Query("MergedInbox")
|
||||
.Where("Id", mergedInboxId)
|
||||
.AsUpdate(new
|
||||
{
|
||||
Name = newName
|
||||
});
|
||||
|
||||
await Connection.ExecuteAsync(query.GetRawQuery());
|
||||
await Connection.ExecuteAsync("UPDATE MergedInbox SET Name = ? WHERE Id = ?", newName, mergedInboxId);
|
||||
|
||||
ReportUIChange(new MergedInboxRenamed(mergedInboxId, newName));
|
||||
}
|
||||
@@ -261,11 +245,9 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
public async Task<List<MailAccountAlias>> GetAccountAliasesAsync(Guid accountId)
|
||||
{
|
||||
var query = new Query(nameof(MailAccountAlias))
|
||||
.Where(nameof(MailAccountAlias.AccountId), accountId)
|
||||
.OrderByDesc(nameof(MailAccountAlias.IsRootAlias));
|
||||
|
||||
return await Connection.QueryAsync<MailAccountAlias>(query.GetRawQuery()).ConfigureAwait(false);
|
||||
return await Connection.QueryAsync<MailAccountAlias>(
|
||||
"SELECT * FROM MailAccountAlias WHERE AccountId = ? ORDER BY IsRootAlias DESC",
|
||||
accountId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private Task<MergedInbox> GetMergedInboxInformationAsync(Guid mergedInboxId)
|
||||
@@ -273,17 +255,9 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
|
||||
public async Task DeleteAccountMailCacheAsync(Guid accountId, AccountCacheResetReason accountCacheResetReason)
|
||||
{
|
||||
var deleteQuery = new Query("MailCopy")
|
||||
.WhereIn("Id", q => q
|
||||
.From("MailCopy")
|
||||
.Select("Id")
|
||||
.WhereIn("FolderId", q2 => q2
|
||||
.From("MailItemFolder")
|
||||
.Select("Id")
|
||||
.Where("MailAccountId", accountId)
|
||||
)).AsDelete();
|
||||
|
||||
await Connection.ExecuteAsync(deleteQuery.GetRawQuery());
|
||||
await Connection.ExecuteAsync(
|
||||
"DELETE FROM MailCopy WHERE Id IN (SELECT Id FROM MailCopy WHERE FolderId IN (SELECT Id FROM MailItemFolder WHERE MailAccountId = ?))",
|
||||
accountId);
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new AccountCacheResetMessage(accountId, accountCacheResetReason));
|
||||
}
|
||||
@@ -306,14 +280,9 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
// There will be only one account in the merged inbox. Remove the link for the other account as well.
|
||||
if (mergedInboxAccountCount == 2)
|
||||
{
|
||||
var query = new Query("MailAccount")
|
||||
.Where("MergedInboxId", account.MergedInboxId.Value)
|
||||
.AsUpdate(new
|
||||
{
|
||||
MergedInboxId = (Guid?)null
|
||||
});
|
||||
|
||||
await Connection.ExecuteAsync(query.GetRawQuery()).ConfigureAwait(false);
|
||||
await Connection.ExecuteAsync(
|
||||
"UPDATE MailAccount SET MergedInboxId = NULL WHERE MergedInboxId = ?",
|
||||
account.MergedInboxId.Value).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,11 +463,7 @@ public class AccountService : BaseDatabaseService, IAccountService
|
||||
{
|
||||
// Create query to delete alias.
|
||||
|
||||
var query = new Query("MailAccountAlias")
|
||||
.Where("Id", aliasId)
|
||||
.AsDelete();
|
||||
|
||||
await Connection.ExecuteAsync(query.GetRawQuery()).ConfigureAwait(false);
|
||||
await Connection.ExecuteAsync("DELETE FROM MailAccountAlias WHERE Id = ?", aliasId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task CreateAccountAsync(MailAccount account, CustomServerInformation customServerInformation)
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Ical.Net.CalendarComponents;
|
||||
using Ical.Net.DataTypes;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Calendar;
|
||||
using Wino.Core.Domain.Enums;
|
||||
@@ -43,14 +42,9 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
||||
|
||||
public async Task DeleteAccountCalendarAsync(AccountCalendar accountCalendar)
|
||||
{
|
||||
var deleteCalendarItemsQuery = new Query()
|
||||
.From(nameof(CalendarItem))
|
||||
.Where(nameof(CalendarItem.CalendarId), accountCalendar.Id)
|
||||
.Where(nameof(AccountCalendar.AccountId), accountCalendar.AccountId);
|
||||
|
||||
var rawQuery = deleteCalendarItemsQuery.GetRawQuery();
|
||||
|
||||
await Connection.ExecuteAsync(rawQuery);
|
||||
await Connection.ExecuteAsync(
|
||||
"DELETE FROM CalendarItem WHERE CalendarId = ? AND AccountId = ?",
|
||||
accountCalendar.Id, accountCalendar.AccountId);
|
||||
await Connection.DeleteAsync<AccountCalendar>(accountCalendar);
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new CalendarListDeleted(accountCalendar));
|
||||
@@ -182,24 +176,16 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
||||
|
||||
public Task<CalendarItem> GetCalendarItemAsync(Guid id)
|
||||
{
|
||||
var query = new Query()
|
||||
.From(nameof(CalendarItem))
|
||||
.Where(nameof(CalendarItem.Id), id);
|
||||
|
||||
var rawQuery = query.GetRawQuery();
|
||||
return Connection.FindWithQueryAsync<CalendarItem>(rawQuery);
|
||||
return Connection.FindWithQueryAsync<CalendarItem>(
|
||||
"SELECT * FROM CalendarItem WHERE Id = ?",
|
||||
id);
|
||||
}
|
||||
|
||||
public async Task<CalendarItem> GetCalendarItemAsync(Guid accountCalendarId, string remoteEventId)
|
||||
{
|
||||
var query = new Query()
|
||||
.From(nameof(CalendarItem))
|
||||
.Where(nameof(CalendarItem.CalendarId), accountCalendarId)
|
||||
.Where(nameof(CalendarItem.RemoteEventId), remoteEventId);
|
||||
|
||||
var rawQuery = query.GetRawQuery();
|
||||
|
||||
var calendarItem = await Connection.FindWithQueryAsync<CalendarItem>(rawQuery);
|
||||
var calendarItem = await Connection.FindWithQueryAsync<CalendarItem>(
|
||||
"SELECT * FROM CalendarItem WHERE CalendarId = ? AND RemoteEventId = ?",
|
||||
accountCalendarId, remoteEventId);
|
||||
|
||||
// Load assigned calendar.
|
||||
if (calendarItem != null)
|
||||
@@ -212,12 +198,9 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
||||
|
||||
public Task UpdateCalendarDeltaSynchronizationToken(Guid calendarId, string deltaToken)
|
||||
{
|
||||
var query = new Query()
|
||||
.From(nameof(AccountCalendar))
|
||||
.Where(nameof(AccountCalendar.Id), calendarId)
|
||||
.AsUpdate(new { SynchronizationDeltaToken = deltaToken });
|
||||
|
||||
return Connection.ExecuteAsync(query.GetRawQuery());
|
||||
return Connection.ExecuteAsync(
|
||||
"UPDATE AccountCalendar SET SynchronizationDeltaToken = ? WHERE Id = ?",
|
||||
deltaToken, calendarId);
|
||||
}
|
||||
|
||||
public Task<List<CalendarEventAttendee>> GetAttendeesAsync(Guid calendarEventTrackingId)
|
||||
@@ -228,12 +211,9 @@ public class CalendarService : BaseDatabaseService, ICalendarService
|
||||
await Connection.RunInTransactionAsync((connection) =>
|
||||
{
|
||||
// Clear all attendees.
|
||||
var query = new Query()
|
||||
.From(nameof(CalendarEventAttendee))
|
||||
.Where(nameof(CalendarEventAttendee.CalendarItemId), calendarItemId)
|
||||
.AsDelete();
|
||||
|
||||
connection.Execute(query.GetRawQuery());
|
||||
connection.Execute(
|
||||
"DELETE FROM CalendarEventAttendee WHERE CalendarItemId = ?",
|
||||
calendarItemId);
|
||||
|
||||
// Insert new attendees.
|
||||
connection.InsertAll(allAttendees, typeof(CalendarEventAttendee));
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MimeKit;
|
||||
using Serilog;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Services.Extensions;
|
||||
@@ -29,13 +28,9 @@ public class ContactService : BaseDatabaseService, IContactService
|
||||
if (queryText == null || queryText.Length < 2)
|
||||
return Task.FromResult<List<AccountContact>>(null);
|
||||
|
||||
var query = new Query(nameof(AccountContact));
|
||||
query.WhereContains("Address", queryText);
|
||||
query.OrWhereContains("Name", queryText);
|
||||
|
||||
var rawLikeQuery = query.GetRawQuery();
|
||||
|
||||
return Connection.QueryAsync<AccountContact>(rawLikeQuery);
|
||||
const string query = "SELECT * FROM AccountContact WHERE Address LIKE ? OR Name LIKE ?";
|
||||
var pattern = $"%{queryText}%";
|
||||
return Connection.QueryAsync<AccountContact>(query, pattern, pattern);
|
||||
}
|
||||
|
||||
public Task<AccountContact> GetAddressInformationByAddressAsync(string address)
|
||||
@@ -81,13 +76,9 @@ public class ContactService : BaseDatabaseService, IContactService
|
||||
if (string.IsNullOrWhiteSpace(searchQuery))
|
||||
return GetAllContactsAsync();
|
||||
|
||||
var query = new Query(nameof(AccountContact));
|
||||
query.WhereContains("Address", searchQuery.Trim());
|
||||
query.OrWhereContains("Name", searchQuery.Trim());
|
||||
|
||||
var rawLikeQuery = query.GetRawQuery();
|
||||
|
||||
return Connection.QueryAsync<AccountContact>(rawLikeQuery);
|
||||
const string query = "SELECT * FROM AccountContact WHERE Address LIKE ? OR Name LIKE ?";
|
||||
var pattern = $"%{searchQuery.Trim()}%";
|
||||
return Connection.QueryAsync<AccountContact>(query, pattern, pattern);
|
||||
}
|
||||
|
||||
public async Task<AccountContact> UpdateContactAsync(AccountContact contact)
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using SqlKata;
|
||||
using SqlKata.Compilers;
|
||||
|
||||
namespace Wino.Services.Extensions;
|
||||
|
||||
public static class SqlKataExtensions
|
||||
{
|
||||
private static SqliteCompiler Compiler = new SqliteCompiler();
|
||||
|
||||
public static string GetRawQuery(this Query query)
|
||||
{
|
||||
return Compiler.Compile(query).ToString();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Serilog;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
@@ -53,23 +52,38 @@ public class FolderService : BaseDatabaseService, IFolderService
|
||||
|
||||
if (account == null) return default;
|
||||
|
||||
var query = new Query("MailCopy")
|
||||
.Where("FolderId", folderId)
|
||||
.SelectRaw("count (DISTINCT Id)");
|
||||
// Convert to raw SQL
|
||||
string sqlQuery;
|
||||
object[] parameters;
|
||||
|
||||
// If focused inbox is enabled, we need to check if this is the inbox folder.
|
||||
if (account.Preferences.IsFocusedInboxEnabled.GetValueOrDefault() && folder.SpecialFolderType == SpecialFolderType.Inbox)
|
||||
{
|
||||
query.Where("IsFocused", 1);
|
||||
}
|
||||
|
||||
// Draft and Junk folders are not counted as unread. They must return the item count instead.
|
||||
if (folder.SpecialFolderType != SpecialFolderType.Draft && folder.SpecialFolderType != SpecialFolderType.Junk)
|
||||
{
|
||||
query.Where("IsRead", 0);
|
||||
sqlQuery = "SELECT COUNT(*) FROM MailCopy WHERE FolderId = ? AND IsFocused = ? AND IsRead = ?";
|
||||
parameters = new object[] { folderId, 1, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlQuery = "SELECT COUNT(*) FROM MailCopy WHERE FolderId = ? AND IsFocused = ?";
|
||||
parameters = new object[] { folderId, 1 };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (folder.SpecialFolderType != SpecialFolderType.Draft && folder.SpecialFolderType != SpecialFolderType.Junk)
|
||||
{
|
||||
sqlQuery = "SELECT COUNT(*) FROM MailCopy WHERE FolderId = ? AND IsRead = ?";
|
||||
parameters = new object[] { folderId, 0 };
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlQuery = "SELECT COUNT(*) FROM MailCopy WHERE FolderId = ?";
|
||||
parameters = new object[] { folderId };
|
||||
}
|
||||
}
|
||||
|
||||
return await Connection.ExecuteScalarAsync<int>(query.GetRawQuery());
|
||||
return await Connection.ExecuteScalarAsync<int>(sqlQuery, parameters);
|
||||
}
|
||||
|
||||
public async Task<AccountFolderTree> GetFolderStructureForAccountAsync(Guid accountId, bool includeHiddenFolders)
|
||||
@@ -186,13 +200,10 @@ public class FolderService : BaseDatabaseService, IFolderService
|
||||
// Localize category folder name.
|
||||
if (parentFolder.SpecialFolderType == SpecialFolderType.Category) parentFolder.FolderName = Translator.CategoriesFolderNameOverride;
|
||||
|
||||
var query = new Query(nameof(MailItemFolder))
|
||||
.Where(nameof(MailItemFolder.ParentRemoteFolderId), parentFolder.RemoteFolderId)
|
||||
.Where(nameof(MailItemFolder.MailAccountId), parentFolder.MailAccountId);
|
||||
|
||||
const string query = "SELECT * FROM MailItemFolder WHERE ParentRemoteFolderId = ? AND MailAccountId = ?";
|
||||
var preparedFolder = new FolderMenuItem(parentFolder, account, parentMenuItem);
|
||||
|
||||
var childFolders = await Connection.QueryAsync<MailItemFolder>(query.GetRawQuery()).ConfigureAwait(false);
|
||||
var childFolders = await Connection.QueryAsync<MailItemFolder>(query, parentFolder.RemoteFolderId, parentFolder.MailAccountId).ConfigureAwait(false);
|
||||
|
||||
if (childFolders.Any())
|
||||
{
|
||||
@@ -348,21 +359,14 @@ public class FolderService : BaseDatabaseService, IFolderService
|
||||
|
||||
public Task<List<MailItemFolder>> GetFoldersAsync(Guid accountId)
|
||||
{
|
||||
var query = new Query(nameof(MailItemFolder))
|
||||
.Where(nameof(MailItemFolder.MailAccountId), accountId)
|
||||
.OrderBy(nameof(MailItemFolder.SpecialFolderType));
|
||||
|
||||
return Connection.QueryAsync<MailItemFolder>(query.GetRawQuery());
|
||||
const string query = "SELECT * FROM MailItemFolder WHERE MailAccountId = ? ORDER BY SpecialFolderType";
|
||||
return Connection.QueryAsync<MailItemFolder>(query, accountId);
|
||||
}
|
||||
|
||||
public Task<List<MailItemFolder>> GetVisibleFoldersAsync(Guid accountId)
|
||||
{
|
||||
var query = new Query(nameof(MailItemFolder))
|
||||
.Where(nameof(MailItemFolder.MailAccountId), accountId)
|
||||
.Where(nameof(MailItemFolder.IsHidden), false)
|
||||
.OrderBy(nameof(MailItemFolder.SpecialFolderType));
|
||||
|
||||
return Connection.QueryAsync<MailItemFolder>(query.GetRawQuery());
|
||||
const string query = "SELECT * FROM MailItemFolder WHERE MailAccountId = ? AND IsHidden = ? ORDER BY SpecialFolderType";
|
||||
return Connection.QueryAsync<MailItemFolder>(query, accountId, 0);
|
||||
}
|
||||
|
||||
public async Task<IList<uint>> GetKnownUidsForFolderAsync(Guid folderId)
|
||||
@@ -516,25 +520,18 @@ public class FolderService : BaseDatabaseService, IFolderService
|
||||
|
||||
private Task<List<string>> GetMailCopyIdsByFolderIdAsync(Guid folderId)
|
||||
{
|
||||
var query = new Query("MailCopy")
|
||||
.Where("FolderId", folderId)
|
||||
.Select("Id");
|
||||
|
||||
return Connection.QueryScalarsAsync<string>(query.GetRawQuery());
|
||||
const string query = "SELECT Id FROM MailCopy WHERE FolderId = ?";
|
||||
return Connection.QueryScalarsAsync<string>(query, folderId);
|
||||
}
|
||||
|
||||
public async Task<List<MailFolderPairMetadata>> GetMailFolderPairMetadatasAsync(IEnumerable<string> mailCopyIds)
|
||||
{
|
||||
// Get all assignments for all items.
|
||||
var query = new Query(nameof(MailCopy))
|
||||
.Join(nameof(MailItemFolder), $"{nameof(MailCopy)}.FolderId", $"{nameof(MailItemFolder)}.Id")
|
||||
.WhereIn($"{nameof(MailCopy)}.Id", mailCopyIds)
|
||||
.SelectRaw($"{nameof(MailCopy)}.Id as MailCopyId, {nameof(MailItemFolder)}.Id as FolderId, {nameof(MailItemFolder)}.RemoteFolderId as RemoteFolderId")
|
||||
.Distinct();
|
||||
var mailCopyIdList = mailCopyIds.ToList();
|
||||
var placeholders = string.Join(",", mailCopyIdList.Select(_ => "?"));
|
||||
var query = $"SELECT DISTINCT MailCopy.Id as MailCopyId, MailItemFolder.Id as FolderId, MailItemFolder.RemoteFolderId as RemoteFolderId FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.Id IN ({placeholders})";
|
||||
var parameters = mailCopyIdList.Cast<object>().ToArray();
|
||||
|
||||
var rowQuery = query.GetRawQuery();
|
||||
|
||||
return await Connection.QueryAsync<MailFolderPairMetadata>(rowQuery);
|
||||
return await Connection.QueryAsync<MailFolderPairMetadata>(query, parameters);
|
||||
}
|
||||
|
||||
public Task<List<MailFolderPairMetadata>> GetMailFolderPairMetadatasAsync(string mailCopyId)
|
||||
@@ -687,14 +684,11 @@ public class FolderService : BaseDatabaseService, IFolderService
|
||||
|
||||
public Task<List<UnreadItemCountResult>> GetUnreadItemCountResultsAsync(IEnumerable<Guid> accountIds)
|
||||
{
|
||||
var query = new Query(nameof(MailCopy))
|
||||
.Join(nameof(MailItemFolder), $"{nameof(MailCopy)}.FolderId", $"{nameof(MailItemFolder)}.Id")
|
||||
.WhereIn($"{nameof(MailItemFolder)}.MailAccountId", accountIds)
|
||||
.Where($"{nameof(MailCopy)}.IsRead", 0)
|
||||
.Where($"{nameof(MailItemFolder)}.ShowUnreadCount", 1)
|
||||
.SelectRaw($"{nameof(MailItemFolder)}.Id as FolderId, {nameof(MailItemFolder)}.SpecialFolderType as SpecialFolderType, count (DISTINCT {nameof(MailCopy)}.Id) as UnreadItemCount, {nameof(MailItemFolder)}.MailAccountId as AccountId")
|
||||
.GroupBy($"{nameof(MailItemFolder)}.Id");
|
||||
var accountIdList = accountIds.ToList();
|
||||
var placeholders = string.Join(",", accountIdList.Select(_ => "?"));
|
||||
var query = $"SELECT MailItemFolder.Id as FolderId, MailItemFolder.SpecialFolderType as SpecialFolderType, count(DISTINCT MailCopy.Id) as UnreadItemCount, MailItemFolder.MailAccountId as AccountId FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailItemFolder.MailAccountId IN ({placeholders}) AND MailCopy.IsRead = ? AND MailItemFolder.ShowUnreadCount = ? GROUP BY MailItemFolder.Id";
|
||||
var parameters = accountIdList.Cast<object>().Concat(new object[] { 0, 1 }).ToArray();
|
||||
|
||||
return Connection.QueryAsync<UnreadItemCountResult>(query.GetRawQuery());
|
||||
return Connection.QueryAsync<UnreadItemCountResult>(query, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
@@ -24,10 +23,8 @@ public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutSer
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<KeyboardShortcut>> GetKeyboardShortcutsAsync()
|
||||
{
|
||||
var query = new Query(nameof(KeyboardShortcut))
|
||||
.OrderBy(nameof(KeyboardShortcut.MailOperation));
|
||||
|
||||
return await Connection.QueryAsync<KeyboardShortcut>(query.GetRawQuery());
|
||||
return await Connection.QueryAsync<KeyboardShortcut>(
|
||||
"SELECT * FROM KeyboardShortcut ORDER BY MailOperation");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,11 +32,9 @@ public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutSer
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<KeyboardShortcut>> GetEnabledKeyboardShortcutsAsync()
|
||||
{
|
||||
var query = new Query(nameof(KeyboardShortcut))
|
||||
.Where(nameof(KeyboardShortcut.IsEnabled), true)
|
||||
.OrderBy(nameof(KeyboardShortcut.MailOperation));
|
||||
|
||||
return await Connection.QueryAsync<KeyboardShortcut>(query.GetRawQuery());
|
||||
return await Connection.QueryAsync<KeyboardShortcut>(
|
||||
"SELECT * FROM KeyboardShortcut WHERE IsEnabled = ? ORDER BY MailOperation",
|
||||
true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,9 +61,6 @@ public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutSer
|
||||
/// </summary>
|
||||
public async Task DeleteKeyboardShortcutAsync(Guid shortcutId)
|
||||
{
|
||||
var query = new Query(nameof(KeyboardShortcut))
|
||||
.Where(nameof(KeyboardShortcut.Id), shortcutId);
|
||||
|
||||
await Connection.ExecuteAsync($"DELETE FROM {nameof(KeyboardShortcut)} WHERE {nameof(KeyboardShortcut.Id)} = ?", shortcutId);
|
||||
}
|
||||
|
||||
@@ -77,12 +69,8 @@ public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutSer
|
||||
/// </summary>
|
||||
public async Task<MailOperation?> GetMailOperationForKeyAsync(string key, ModifierKeys modifierKeys)
|
||||
{
|
||||
var query = new Query(nameof(KeyboardShortcut))
|
||||
.Where(nameof(KeyboardShortcut.Key), key)
|
||||
.Where(nameof(KeyboardShortcut.ModifierKeys), (int)modifierKeys)
|
||||
.Where(nameof(KeyboardShortcut.IsEnabled), true);
|
||||
|
||||
var shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query.GetRawQuery());
|
||||
const string query = "SELECT * FROM KeyboardShortcut WHERE Key = ? AND ModifierKeys = ? AND IsEnabled = ? LIMIT 1";
|
||||
var shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query, key, (int)modifierKeys, 1);
|
||||
return shortcut?.MailOperation;
|
||||
}
|
||||
|
||||
@@ -91,16 +79,20 @@ public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutSer
|
||||
/// </summary>
|
||||
public async Task<bool> IsKeyCombinationInUseAsync(string key, ModifierKeys modifierKeys, Guid? excludeShortcutId = null)
|
||||
{
|
||||
var query = new Query(nameof(KeyboardShortcut))
|
||||
.Where(nameof(KeyboardShortcut.Key), key)
|
||||
.Where(nameof(KeyboardShortcut.ModifierKeys), (int)modifierKeys);
|
||||
string query;
|
||||
KeyboardShortcut shortcut;
|
||||
|
||||
if (excludeShortcutId.HasValue)
|
||||
{
|
||||
query = query.WhereNot(nameof(KeyboardShortcut.Id), excludeShortcutId.Value);
|
||||
query = "SELECT * FROM KeyboardShortcut WHERE Key = ? AND ModifierKeys = ? AND Id != ? LIMIT 1";
|
||||
shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query, key, (int)modifierKeys, excludeShortcutId.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "SELECT * FROM KeyboardShortcut WHERE Key = ? AND ModifierKeys = ? LIMIT 1";
|
||||
shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query, key, (int)modifierKeys);
|
||||
}
|
||||
|
||||
var shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query.GetRawQuery());
|
||||
return shortcut != null;
|
||||
}
|
||||
|
||||
|
||||
+92
-110
@@ -2,12 +2,12 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using MimeKit;
|
||||
using Serilog;
|
||||
using SqlKata;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities.Mail;
|
||||
using Wino.Core.Domain.Entities.Shared;
|
||||
@@ -144,74 +144,80 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
return unreadMails;
|
||||
}
|
||||
|
||||
private static string BuildMailFetchQuery(MailListInitializationOptions options)
|
||||
private static (string Query, object[] Parameters) BuildMailFetchQuery(MailListInitializationOptions options)
|
||||
{
|
||||
// If the search query is there, we should ignore some properties and trim it.
|
||||
//if (!string.IsNullOrEmpty(options.SearchQuery))
|
||||
//{
|
||||
// options.IsFocusedOnly = null;
|
||||
// filterType = FilterOptionType.All;
|
||||
var sql = new StringBuilder();
|
||||
sql.Append("SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id");
|
||||
|
||||
// searchQuery = searchQuery.Trim();
|
||||
//}
|
||||
var whereClauses = new List<string>();
|
||||
var parameters = new List<object>();
|
||||
|
||||
// SQLite PCL doesn't support joins.
|
||||
// We make the query using SqlKata and execute it directly on SQLite-PCL.
|
||||
// Folder filter
|
||||
var folderPlaceholders = string.Join(",", options.Folders.Select(_ => "?"));
|
||||
whereClauses.Add($"MailCopy.FolderId IN ({folderPlaceholders})");
|
||||
parameters.AddRange(options.Folders.Select(f => (object)f.Id));
|
||||
|
||||
var query = new Query("MailCopy")
|
||||
.Join("MailItemFolder", "MailCopy.FolderId", "MailItemFolder.Id")
|
||||
.WhereIn("MailCopy.FolderId", options.Folders.Select(a => a.Id))
|
||||
.Take(ItemLoadCount)
|
||||
.SelectRaw("MailCopy.*");
|
||||
|
||||
if (options.SortingOptionType == SortingOptionType.ReceiveDate)
|
||||
query.OrderByDesc("CreationDate");
|
||||
else if (options.SortingOptionType == SortingOptionType.Sender)
|
||||
query.OrderBy("FromName");
|
||||
|
||||
// Conditional where.
|
||||
// Filter type
|
||||
switch (options.FilterType)
|
||||
{
|
||||
case FilterOptionType.Unread:
|
||||
query.Where("MailCopy.IsRead", false);
|
||||
whereClauses.Add("MailCopy.IsRead = 0");
|
||||
break;
|
||||
case FilterOptionType.Flagged:
|
||||
query.Where("MailCopy.IsFlagged", true);
|
||||
whereClauses.Add("MailCopy.IsFlagged = 1");
|
||||
break;
|
||||
case FilterOptionType.Files:
|
||||
query.Where("MailCopy.HasAttachments", true);
|
||||
whereClauses.Add("MailCopy.HasAttachments = 1");
|
||||
break;
|
||||
}
|
||||
|
||||
// Focused filter
|
||||
if (options.IsFocusedOnly != null)
|
||||
query.Where("MailCopy.IsFocused", options.IsFocusedOnly.Value);
|
||||
{
|
||||
whereClauses.Add($"MailCopy.IsFocused = {(options.IsFocusedOnly.Value ? "1" : "0")}");
|
||||
}
|
||||
|
||||
// Search query
|
||||
if (!string.IsNullOrEmpty(options.SearchQuery))
|
||||
query.Where(a =>
|
||||
a.OrWhereContains("MailCopy.PreviewText", options.SearchQuery)
|
||||
.OrWhereContains("MailCopy.Subject", options.SearchQuery)
|
||||
.OrWhereContains("MailCopy.FromName", options.SearchQuery)
|
||||
.OrWhereContains("MailCopy.FromAddress", options.SearchQuery));
|
||||
{
|
||||
whereClauses.Add("(MailCopy.PreviewText LIKE ? OR MailCopy.Subject LIKE ? OR MailCopy.FromName LIKE ? OR MailCopy.FromAddress LIKE ?)");
|
||||
var searchPattern = $"%{options.SearchQuery}%";
|
||||
parameters.Add(searchPattern);
|
||||
parameters.Add(searchPattern);
|
||||
parameters.Add(searchPattern);
|
||||
parameters.Add(searchPattern);
|
||||
}
|
||||
|
||||
// Support pagination by excluding already fetched items
|
||||
// Exclude existing items
|
||||
if (options.ExistingUniqueIds?.Any() ?? false)
|
||||
{
|
||||
query.WhereNotIn("MailCopy.UniqueId", options.ExistingUniqueIds);
|
||||
var excludePlaceholders = string.Join(",", options.ExistingUniqueIds.Select(_ => "?"));
|
||||
whereClauses.Add($"MailCopy.UniqueId NOT IN ({excludePlaceholders})");
|
||||
parameters.AddRange(options.ExistingUniqueIds.Select(id => (object)id));
|
||||
}
|
||||
|
||||
// Support skip for pagination
|
||||
if (whereClauses.Any())
|
||||
{
|
||||
sql.Append(" WHERE ");
|
||||
sql.Append(string.Join(" AND ", whereClauses));
|
||||
}
|
||||
|
||||
// Sorting
|
||||
if (options.SortingOptionType == SortingOptionType.ReceiveDate)
|
||||
sql.Append(" ORDER BY CreationDate DESC");
|
||||
else if (options.SortingOptionType == SortingOptionType.Sender)
|
||||
sql.Append(" ORDER BY FromName ASC");
|
||||
|
||||
// Pagination
|
||||
var limit = options.Take > 0 ? options.Take : ItemLoadCount;
|
||||
sql.Append($" LIMIT {limit}");
|
||||
|
||||
if (options.Skip > 0)
|
||||
{
|
||||
query.Skip(options.Skip);
|
||||
sql.Append($" OFFSET {options.Skip}");
|
||||
}
|
||||
|
||||
// Support custom take count for pagination
|
||||
if (options.Take > 0)
|
||||
{
|
||||
query.Take(options.Take);
|
||||
}
|
||||
|
||||
return query.GetRawQuery();
|
||||
return (sql.ToString(), parameters.ToArray());
|
||||
}
|
||||
|
||||
public async Task<List<MailCopy>> FetchMailsAsync(MailListInitializationOptions options, CancellationToken cancellationToken = default)
|
||||
@@ -226,8 +232,8 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
else
|
||||
{
|
||||
// If not just do the query.
|
||||
var query = BuildMailFetchQuery(options);
|
||||
mails = await Connection.QueryAsync<MailCopy>(query);
|
||||
var (query, parameters) = BuildMailFetchQuery(options);
|
||||
mails = await Connection.QueryAsync<MailCopy>(query, parameters);
|
||||
}
|
||||
|
||||
ConcurrentDictionary<Guid, MailItemFolder> folderCache = new();
|
||||
@@ -295,13 +301,12 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
if (string.IsNullOrEmpty(threadId))
|
||||
return [];
|
||||
|
||||
var query = new Query("MailCopy")
|
||||
.Where("ThreadId", threadId)
|
||||
.WhereNotIn("Id", excludeMailIds)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
var placeholders = string.Join(",", excludeMailIds.Select(_ => "?"));
|
||||
var sql = $"SELECT MailCopy.* FROM MailCopy WHERE ThreadId = ? AND Id NOT IN ({placeholders})";
|
||||
var parameters = new List<object> { threadId };
|
||||
parameters.AddRange(excludeMailIds.Cast<object>());
|
||||
|
||||
return await Connection.QueryAsync<MailCopy>(query);
|
||||
return await Connection.QueryAsync<MailCopy>(sql, parameters.ToArray());
|
||||
}
|
||||
|
||||
private async Task<List<MailCopy>> GetMailsByThreadIdsAsync(List<string> threadIds, HashSet<string> excludeMailIds)
|
||||
@@ -309,13 +314,14 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
if (threadIds?.Count == 0)
|
||||
return [];
|
||||
|
||||
var query = new Query("MailCopy")
|
||||
.WhereIn("ThreadId", threadIds)
|
||||
.WhereNotIn("Id", excludeMailIds)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
var threadPlaceholders = string.Join(",", threadIds.Select(_ => "?"));
|
||||
var excludePlaceholders = string.Join(",", excludeMailIds.Select(_ => "?"));
|
||||
var sql = $"SELECT MailCopy.* FROM MailCopy WHERE ThreadId IN ({threadPlaceholders}) AND Id NOT IN ({excludePlaceholders})";
|
||||
var parameters = new List<object>();
|
||||
parameters.AddRange(threadIds.Cast<object>());
|
||||
parameters.AddRange(excludeMailIds.Cast<object>());
|
||||
|
||||
return await Connection.QueryAsync<MailCopy>(query).ConfigureAwait(false);
|
||||
return await Connection.QueryAsync<MailCopy>(sql, parameters.ToArray()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -451,12 +457,9 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
/// <param name="mailCopyId">Mail copy id.</param>
|
||||
public async Task<MailCopy> GetSingleMailItemAsync(string mailCopyId)
|
||||
{
|
||||
var query = new Query("MailCopy")
|
||||
.Where("MailCopy.Id", mailCopyId)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
|
||||
var mailCopy = await Connection.FindWithQueryAsync<MailCopy>(query);
|
||||
var mailCopy = await Connection.FindWithQueryAsync<MailCopy>(
|
||||
"SELECT MailCopy.* FROM MailCopy WHERE MailCopy.Id = ?",
|
||||
mailCopyId);
|
||||
if (mailCopy == null) return null;
|
||||
|
||||
await LoadAssignedPropertiesAsync(mailCopy).ConfigureAwait(false);
|
||||
@@ -466,14 +469,9 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
|
||||
public async Task<MailCopy> GetSingleMailItemAsync(string mailCopyId, string remoteFolderId)
|
||||
{
|
||||
var query = new Query("MailCopy")
|
||||
.Join("MailItemFolder", "MailCopy.FolderId", "MailItemFolder.Id")
|
||||
.Where("MailCopy.Id", mailCopyId)
|
||||
.Where("MailItemFolder.RemoteFolderId", remoteFolderId)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
|
||||
var mailItem = await Connection.FindWithQueryAsync<MailCopy>(query);
|
||||
var mailItem = await Connection.FindWithQueryAsync<MailCopy>(
|
||||
"SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.Id = ? AND MailItemFolder.RemoteFolderId = ?",
|
||||
mailCopyId, remoteFolderId);
|
||||
|
||||
if (mailItem == null) return null;
|
||||
|
||||
@@ -1030,14 +1028,9 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
|
||||
public async Task<bool> MapLocalDraftAsync(Guid accountId, Guid localDraftCopyUniqueId, string newMailCopyId, string newDraftId, string newThreadId)
|
||||
{
|
||||
var query = new Query("MailCopy")
|
||||
.Join("MailItemFolder", "MailCopy.FolderId", "MailItemFolder.Id")
|
||||
.Where("MailCopy.UniqueId", localDraftCopyUniqueId)
|
||||
.Where("MailItemFolder.MailAccountId", accountId)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
|
||||
var localDraftCopy = await Connection.FindWithQueryAsync<MailCopy>(query);
|
||||
var localDraftCopy = await Connection.FindWithQueryAsync<MailCopy>(
|
||||
"SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.UniqueId = ? AND MailItemFolder.MailAccountId = ?",
|
||||
localDraftCopyUniqueId, accountId);
|
||||
|
||||
if (localDraftCopy == null)
|
||||
{
|
||||
@@ -1085,28 +1078,22 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
|
||||
public Task<List<MailCopy>> GetDownloadedUnreadMailsAsync(Guid accountId, IEnumerable<string> downloadedMailCopyIds)
|
||||
{
|
||||
var rawQuery = new Query("MailCopy")
|
||||
.Join("MailItemFolder", "MailCopy.FolderId", "MailItemFolder.Id")
|
||||
.WhereIn("MailCopy.Id", downloadedMailCopyIds)
|
||||
.Where("MailCopy.IsRead", false)
|
||||
.Where("MailItemFolder.MailAccountId", accountId)
|
||||
.Where("MailItemFolder.SpecialFolderType", SpecialFolderType.Inbox)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
var placeholders = string.Join(",", downloadedMailCopyIds.Select(_ => "?"));
|
||||
var sql = $"SELECT MailCopy.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id WHERE MailCopy.Id IN ({placeholders}) AND MailCopy.IsRead = ? AND MailItemFolder.MailAccountId = ? AND MailItemFolder.SpecialFolderType = ?";
|
||||
var parameters = new List<object>();
|
||||
parameters.AddRange(downloadedMailCopyIds.Cast<object>());
|
||||
parameters.Add(false);
|
||||
parameters.Add(accountId);
|
||||
parameters.Add((int)SpecialFolderType.Inbox);
|
||||
|
||||
return Connection.QueryAsync<MailCopy>(rawQuery);
|
||||
return Connection.QueryAsync<MailCopy>(sql, parameters.ToArray());
|
||||
}
|
||||
|
||||
public Task<MailAccount> GetMailAccountByUniqueIdAsync(Guid uniqueMailId)
|
||||
{
|
||||
var query = new Query("MailCopy")
|
||||
.Join("MailItemFolder", "MailCopy.FolderId", "MailItemFolder.Id")
|
||||
.Join("MailAccount", "MailItemFolder.MailAccountId", "MailAccount.Id")
|
||||
.Where("MailCopy.UniqueId", uniqueMailId)
|
||||
.SelectRaw("MailAccount.*")
|
||||
.GetRawQuery();
|
||||
|
||||
return Connection.FindWithQueryAsync<MailAccount>(query);
|
||||
return Connection.FindWithQueryAsync<MailAccount>(
|
||||
"SELECT MailAccount.* FROM MailCopy INNER JOIN MailItemFolder ON MailCopy.FolderId = MailItemFolder.Id INNER JOIN MailAccount ON MailItemFolder.MailAccountId = MailAccount.Id WHERE MailCopy.UniqueId = ?",
|
||||
uniqueMailId);
|
||||
}
|
||||
|
||||
public Task<bool> IsMailExistsAsync(string mailCopyId)
|
||||
@@ -1116,11 +1103,10 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
{
|
||||
var localMailIds = uniqueIds.Select(a => MailkitClientExtensions.CreateUid(folderId, a.Id)).ToArray();
|
||||
|
||||
var query = new Query(nameof(MailCopy))
|
||||
.WhereIn("Id", localMailIds)
|
||||
.GetRawQuery();
|
||||
var placeholders = string.Join(",", localMailIds.Select(_ => "?"));
|
||||
var sql = $"SELECT * FROM MailCopy WHERE Id IN ({placeholders})";
|
||||
|
||||
return await Connection.QueryAsync<MailCopy>(query);
|
||||
return await Connection.QueryAsync<MailCopy>(sql, localMailIds.Cast<object>().ToArray());
|
||||
}
|
||||
|
||||
public Task<bool> IsMailExistsAsync(string mailCopyId, Guid folderId)
|
||||
@@ -1142,12 +1128,10 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
{
|
||||
if (!mailCopyIds.Any()) return [];
|
||||
|
||||
var query = new Query("MailCopy")
|
||||
.WhereIn("MailCopy.Id", mailCopyIds)
|
||||
.SelectRaw("MailCopy.*")
|
||||
.GetRawQuery();
|
||||
var placeholders = string.Join(",", mailCopyIds.Select(_ => "?"));
|
||||
var sql = $"SELECT MailCopy.* FROM MailCopy WHERE MailCopy.Id IN ({placeholders})";
|
||||
|
||||
var mailCopies = await Connection.QueryAsync<MailCopy>(query);
|
||||
var mailCopies = await Connection.QueryAsync<MailCopy>(sql, mailCopyIds.Cast<object>().ToArray());
|
||||
if (mailCopies?.Count == 0) return [];
|
||||
|
||||
ConcurrentDictionary<Guid, MailItemFolder> folderCache = new();
|
||||
@@ -1164,11 +1148,9 @@ public class MailService : BaseDatabaseService, IMailService
|
||||
|
||||
public async Task<List<string>> AreMailsExistsAsync(IEnumerable<string> mailCopyIds)
|
||||
{
|
||||
var query = new Query(nameof(MailCopy))
|
||||
.WhereIn("Id", mailCopyIds)
|
||||
.Select("Id")
|
||||
.GetRawQuery();
|
||||
var placeholders = string.Join(",", mailCopyIds.Select(_ => "?"));
|
||||
var sql = $"SELECT Id FROM MailCopy WHERE Id IN ({placeholders})";
|
||||
|
||||
return await Connection.QueryScalarsAsync<string>(query);
|
||||
return await Connection.QueryScalarsAsync<string>(sql, mailCopyIds.Cast<object>().ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<PackageReference Include="Serilog.Sinks.Debug" />
|
||||
<PackageReference Include="Serilog.Sinks.File" />
|
||||
<PackageReference Include="Serilog.Exceptions" />
|
||||
<PackageReference Include="SqlKata" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Wino.Core.Domain\Wino.Core.Domain.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user