feat(postit): admin search includes profile metadata

This commit is contained in:
Paul Schneider 2026-10-07 12:29:16 +01:00
commit 6b75ae7682
Signed by: notazof
GPG key ID: AD4B9B545FBD7D12
4 changed files with 57 additions and 14 deletions

View file

@ -45,9 +45,9 @@ public class HomePageProviderFlowTests
public void Administration_page_filters_users_by_search_text() public void Administration_page_filters_users_by_search_text()
{ {
var vm = new AdministrationPageViewModel(); var vm = new AdministrationPageViewModel();
vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "1", UserName = "alice" }); vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "1", UserName = "alice", FullName = "Alice Example" });
vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "2", UserName = "bob" }); vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "2", UserName = "bob", FullName = "Bob Jones" });
vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "3", UserName = "carol" }); vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "3", UserName = "carol", FullName = "Carol Smith" });
vm.SearchText = "ali"; vm.SearchText = "ali";
@ -55,6 +55,19 @@ public class HomePageProviderFlowTests
Assert.Equal("alice", vm.FilteredUsers[0].UserName); Assert.Equal("alice", vm.FilteredUsers[0].UserName);
} }
[Fact]
public void Administration_page_filters_users_by_full_name()
{
var vm = new AdministrationPageViewModel();
vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "1", UserName = "alice", FullName = "Alice Example" });
vm.Users.Add(new Yavsc.Abstract.Identity.UserInfo { UserId = "2", UserName = "bob", FullName = "Bob Jones" });
vm.SearchText = "example";
Assert.Single(vm.FilteredUsers);
Assert.Equal("alice", vm.FilteredUsers[0].UserName);
}
[Fact] [Fact]
public void UserProfilePage_exposes_full_name_and_address_fields() public void UserProfilePage_exposes_full_name_and_address_fields()
{ {

View file

@ -32,6 +32,7 @@ public partial class AdministrationPageViewModel : ViewModelBase
? Users.ToList() ? Users.ToList()
: Users.Where(user => : Users.Where(user =>
(user.UserName ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase) (user.UserName ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| (user.FullName ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| (user.Email ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase) || (user.Email ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|| (user.UserId ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase)) || (user.UserId ?? string.Empty).Contains(SearchText, StringComparison.OrdinalIgnoreCase))
.ToList(); .ToList();

View file

@ -31,7 +31,9 @@
<Border Padding="8" BorderBrush="#D0D7DE" BorderThickness="1" CornerRadius="6"> <Border Padding="8" BorderBrush="#D0D7DE" BorderThickness="1" CornerRadius="6">
<StackPanel Spacing="4"> <StackPanel Spacing="4">
<TextBlock Text="{Binding UserName, StringFormat='Nom : {0}'}" FontWeight="SemiBold"/> <TextBlock Text="{Binding UserName, StringFormat='Nom : {0}'}" FontWeight="SemiBold"/>
<TextBlock Text="{Binding FullName, StringFormat='Nom complet : {0}'}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding Email, StringFormat='Email : {0}'}" TextWrapping="Wrap"/> <TextBlock Text="{Binding Email, StringFormat='Email : {0}'}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding DedicatedGoogleCalendar, StringFormat='Calendrier : {0}'}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding UserId, StringFormat='ID : {0}'}" Foreground="#4B5563" TextWrapping="Wrap"/> <TextBlock Text="{Binding UserId, StringFormat='ID : {0}'}" Foreground="#4B5563" TextWrapping="Wrap"/>
</StackPanel> </StackPanel>
</Border> </Border>

View file

@ -22,22 +22,49 @@ namespace Yavsc.Controllers
[HttpGet] [HttpGet]
public IEnumerable<UserInfo> GetApplicationUser(int skip=0, int take = 25) public IEnumerable<UserInfo> GetApplicationUser(int skip=0, int take = 25)
{ {
return _context.Users.Skip(skip).Take(take) return _context.Users
.Select(u=> new UserInfo{ .Include(u => u.PostalAddress)
UserId = u.Id, .Include(u => u.BankInfo)
UserName = u.UserName, .Skip(skip).Take(take)
Avatar = u.Avatar}); .Select(u => new UserInfo
{
UserId = u.Id,
UserName = u.UserName,
FullName = u.FullName,
Email = u.Email,
Address = u.PostalAddress != null ? u.PostalAddress.Address : string.Empty,
Avatar = u.Avatar,
DedicatedGoogleCalendar = u.DedicatedGoogleCalendar,
BankInfoSummary = u.BankInfo != null && u.BankInfo.Count > 0
? string.Join(" | ", u.BankInfo.Select(b => string.IsNullOrWhiteSpace(b.IBAN) ? b.BIC : $"{b.IBAN} / {b.BIC}"))
: string.Empty
});
} }
[HttpGet("search/{pattern}")] [HttpGet("search/{pattern}")]
public IEnumerable<UserInfo> SearchApplicationUser(string pattern, int skip=0, int take = 25) public IEnumerable<UserInfo> SearchApplicationUser(string pattern, int skip=0, int take = 25)
{ {
return _context.Users.Where(u => u.UserName.Contains(pattern)) var normalizedPattern = pattern ?? string.Empty;
.Skip(skip).Take(take) return _context.Users
.Select(u=> new UserInfo { .Include(u => u.PostalAddress)
UserId = u.Id, .Include(u => u.BankInfo)
UserName = u.UserName, .Where(u => u.UserName.Contains(normalizedPattern)
Avatar = u.Avatar }); || (u.FullName != null && u.FullName.Contains(normalizedPattern))
|| (u.Email != null && u.Email.Contains(normalizedPattern)))
.Skip(skip).Take(take)
.Select(u => new UserInfo
{
UserId = u.Id,
UserName = u.UserName,
FullName = u.FullName,
Email = u.Email,
Address = u.PostalAddress != null ? u.PostalAddress.Address : string.Empty,
Avatar = u.Avatar,
DedicatedGoogleCalendar = u.DedicatedGoogleCalendar,
BankInfoSummary = u.BankInfo != null && u.BankInfo.Count > 0
? string.Join(" | ", u.BankInfo.Select(b => string.IsNullOrWhiteSpace(b.IBAN) ? b.BIC : $"{b.IBAN} / {b.BIC}"))
: string.Empty
});
} }
// GET: api/ApplicationUserApi/5 // GET: api/ApplicationUserApi/5