diff --git a/src/AliasVault.Admin/Main/Components/Icons/SearchIcon.razor b/src/AliasVault.Admin/Main/Components/Icons/SearchIcon.razor
new file mode 100644
index 000000000..0e27b6a0f
--- /dev/null
+++ b/src/AliasVault.Admin/Main/Components/Icons/SearchIcon.razor
@@ -0,0 +1,5 @@
+
+
+
diff --git a/src/AliasVault.Admin/Main/Pages/Emails.razor b/src/AliasVault.Admin/Main/Pages/Emails.razor
index be72e841b..17607b559 100644
--- a/src/AliasVault.Admin/Main/Pages/Emails.razor
+++ b/src/AliasVault.Admin/Main/Pages/Emails.razor
@@ -7,12 +7,25 @@
+ Description="This page shows an overview of recently received mails by this AliasVault server. Note: all email fields except 'To' are encrypted with the public key of the user and are unreadable by the server.">
+@if (IsInitialized)
+{
+
+
+
+
+
+
+
+
+
+}
+
@if (IsLoading)
{
@@ -20,23 +33,25 @@
else
{
-
-
- @foreach (var email in EmailList)
+ @foreach (var viewModel in EmailViewModelList)
{
- @email.Id
- @email.DateSystem.ToString("yyyy-MM-dd HH:mm")
- @(email.FromLocal.Length > 15 ? email.FromLocal.Substring(0, 15) : email.FromLocal)@@@(email.FromDomain.Length > 15 ? email.FromDomain.Substring(0, 15) : email.FromDomain)
- @email.ToLocal@@@email.ToDomain
- @(email.Subject.Length > 30 ? email.Subject.Substring(0, 30) : email.Subject)
+ @viewModel.Email.Id
+ @viewModel.Email.DateSystem.ToString("yyyy-MM-dd HH:mm")
+ @(viewModel.Email.FromLocal.Length > 10 ? viewModel.Email.FromLocal.Substring(0, 10) : viewModel.Email.FromLocal)@@@(viewModel.Email.FromDomain.Length > 10 ? viewModel.Email.FromDomain.Substring(0, 10) : viewModel.Email.FromDomain)
+ @viewModel.Email.ToLocal@@@viewModel.Email.ToDomain
-
- @(email.MessagePreview?.Length > 30 ? email.MessagePreview.Substring(0, 30) : email.MessagePreview)
-
+ @if (viewModel.UserName.Length > 0)
+ {
+ @viewModel.UserName
+ }
+ else
+ {
+ n/a
+ }
- @email.Attachments.Count
+ @viewModel.Email.Attachments.Count
}
@@ -49,20 +64,40 @@ else
new TableColumn { Title = "Time", PropertyName = "DateSystem" },
new TableColumn { Title = "From", PropertyName = "From" },
new TableColumn { Title = "To", PropertyName = "To" },
- new TableColumn { Title = "Subject", PropertyName = "Subject" },
- new TableColumn { Title = "Preview", PropertyName = "MessagePreview" },
+ new TableColumn { Title = "User", Sortable = false },
new TableColumn { Title = "Attachments", PropertyName = "Attachments" },
];
- private List EmailList { get; set; } = [];
+ private List EmailViewModelList { get; set; } = [];
+ private bool IsInitialized { get; set; } = false;
+
private bool IsLoading { get; set; } = true;
+
private int CurrentPage { get; set; } = 1;
private int PageSize { get; set; } = 50;
private int TotalRecords { get; set; }
+ private string _searchTerm = string.Empty;
+
+ ///
+ /// The last search term.
+ ///
+ private string _lastSearchTerm = string.Empty;
+
+ private string SearchTerm
+ {
+ get => _searchTerm;
+ set
+ {
+ if (_searchTerm != value)
+ {
+ _searchTerm = value;
+ _ = RefreshData();
+ }
+ }
+ }
private string SortColumn { get; set; } = "Id";
private SortDirection SortDirection { get; set; } = SortDirection.Descending;
-
private async Task HandleSortChanged((string column, SortDirection direction) sort)
{
SortColumn = sort.column;
@@ -91,8 +126,68 @@ else
StateHasChanged();
await using var dbContext = await DbContextFactory.CreateDbContextAsync();
+
IQueryable query = dbContext.Emails;
+ query = ApplySearchFilter(query);
+ query = ApplySort(query);
+
+ TotalRecords = await query.CountAsync();
+ var emailList = await query
+ .Skip((CurrentPage - 1) * PageSize)
+ .Take(PageSize)
+ .ToListAsync();
+
+ // Get all usernames for the emails in the current list
+ var encryptionKeyIds = emailList.Select(x => x.UserEncryptionKeyId).Distinct().ToList();
+ var encryptionKeyUsernames = await dbContext.UserEncryptionKeys
+ .Where(x => encryptionKeyIds.Contains(x.Id))
+ .Join(dbContext.AliasVaultUsers, x => x.UserId, y => y.Id, (x, y) => new { EncryptionKeyId = x.Id, UserId = y.Id, y.UserName })
+ .ToListAsync();
+
+ // Create new list of viewmodels
+ EmailViewModelList = new List();
+
+ foreach (var email in emailList)
+ {
+ var encryptionKey = encryptionKeyUsernames.FirstOrDefault(x => x.EncryptionKeyId == email.UserEncryptionKeyId);
+ EmailViewModelList.Add(new EmailViewModel { Email = email, UserId = encryptionKey?.UserId ?? string.Empty, UserName = encryptionKey?.UserName ?? string.Empty });
+ }
+
+ IsLoading = false;
+ IsInitialized = true;
+ StateHasChanged();
+ }
+
+ ///
+ /// Applies a search filter to the query based on the search term.
+ ///
+ /// The query to filter.
+ /// The filtered query.
+ private IQueryable ApplySearchFilter(IQueryable query)
+ {
+ if (SearchTerm.Length > 0)
+ {
+ // Reset page number back to 1 if the search term has changed.
+ if (SearchTerm != _lastSearchTerm && CurrentPage != 1)
+ {
+ CurrentPage = 1;
+ }
+ _lastSearchTerm = SearchTerm;
+
+ query = query.Where(x => EF.Functions.Like(x.To.ToLower(), "%" + SearchTerm.Trim().ToLower() + "%"));
+ }
+
+ return query;
+ }
+
+ ///
+ /// Applies sorting to the query based on the sort column and direction.
+ ///
+ /// The query to sort.
+ /// The sorted query.
+ private IQueryable ApplySort(IQueryable query)
+ {
// Apply sort
switch (SortColumn)
{
@@ -116,16 +211,6 @@ else
? query.OrderBy(x => x.ToLocal + "@" + x.ToDomain)
: query.OrderByDescending(x => x.ToLocal + "@" + x.ToDomain);
break;
- case "Subject":
- query = SortDirection == SortDirection.Ascending
- ? query.OrderBy(x => x.Subject)
- : query.OrderByDescending(x => x.Subject);
- break;
- case "MessagePreview":
- query = SortDirection == SortDirection.Ascending
- ? query.OrderBy(x => x.MessagePreview)
- : query.OrderByDescending(x => x.MessagePreview);
- break;
case "Attachments":
query = SortDirection == SortDirection.Ascending
? query.OrderBy(x => x.Attachments.Count)
@@ -136,13 +221,13 @@ else
break;
}
- TotalRecords = await query.CountAsync();
- EmailList = await query
- .Skip((CurrentPage - 1) * PageSize)
- .Take(PageSize)
- .ToListAsync();
+ return query;
+ }
- IsLoading = false;
- StateHasChanged();
+ private sealed class EmailViewModel
+ {
+ public Email Email { get; set; } = new();
+ public string UserId { get; set; } = string.Empty;
+ public string UserName { get; set; } = string.Empty;
}
}
diff --git a/src/AliasVault.Admin/Main/Pages/Logging/Auth.razor b/src/AliasVault.Admin/Main/Pages/Logging/Auth.razor
index 655cf1c45..2cc383226 100644
--- a/src/AliasVault.Admin/Main/Pages/Logging/Auth.razor
+++ b/src/AliasVault.Admin/Main/Pages/Logging/Auth.razor
@@ -15,19 +15,18 @@
-@if (IsLoading)
-{
-
-}
-else
+@if (IsInitialized)
{