Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Custom Autocomplete Components for TimeZone and Language Selection and Extend ApplicationUser #773

Merged
merged 14 commits into from
Oct 9, 2024
3 changes: 2 additions & 1 deletion src/Application/Common/Security/ChangeUserProfileModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public class ChangeUserProfileModel
public bool IsActive { get; set; }
public string? TenantId { get; set; }
public string? TenantName { get; set; }

public string? TimeZoneId { get; set; }
public string? LanguageCode { get; set; }
private class Mapping : Profile
{
public Mapping()
Expand Down
6 changes: 6 additions & 0 deletions src/Application/Common/Security/UserProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ public class UserProfile
public bool IsActive { get; set; }
public string? TenantId { get; set; }
public string? TenantName { get; set; }

public string? TimeZoneId { get; set; }
public string? LanguageCode { get; set; }
public TimeSpan LocalTimeOffset => string.IsNullOrEmpty(TimeZoneId)
? TimeZoneInfo.Local.BaseUtcOffset
: TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId).BaseUtcOffset;
}
4 changes: 3 additions & 1 deletion src/Application/Common/Security/UserProfileStateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ public UserProfile UserProfile

private void NotifyStateChanged() => OnChange?.Invoke();

public void UpdateUserProfile(string userName,string? profilePictureDataUrl, string? fullName,string? phoneNumber)
public void UpdateUserProfile(string userName,string? profilePictureDataUrl, string? fullName,string? phoneNumber,string? timeZoneId,string? languageCode)
{
_userProfile.ProfilePictureDataUrl = profilePictureDataUrl;
_userProfile.DisplayName = fullName;
_userProfile.PhoneNumber = phoneNumber;
_userProfile.TimeZoneId = timeZoneId;
_userProfile.LanguageCode = languageCode;
RemoveApplicationUserCache(userName);
NotifyStateChanged();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class AuditTrailsWithPaginationQuery : AuditTrailAdvancedFilter, ICacheab
public override string ToString()
{
return
$"Listview:{ListView}-{LocalTimezoneOffset.TotalHours},AuditType:{AuditType},Search:{Keyword},Sort:{SortDirection},OrderBy:{OrderBy},{PageNumber},{PageSize}";
$"Listview:{ListView}-{CurrentUser?.UserId},AuditType:{AuditType},Search:{Keyword},Sort:{SortDirection},OrderBy:{OrderBy},{PageNumber},{PageSize}";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public enum AuditTrailListView

public class AuditTrailAdvancedFilter : PaginationFilter
{
public TimeSpan LocalTimezoneOffset { get; set; }
public AuditType? AuditType { get; set; }
public AuditTrailListView ListView { get; set; } = AuditTrailListView.All;
public UserProfile? CurrentUser { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CleanArchitecture.Blazor.Application.Features.AuditTrails.Queries.PaginationQuery;
using CleanArchitecture.Blazor.Application.Features.Products.Specifications;

namespace CleanArchitecture.Blazor.Application.Features.AuditTrails.Specifications;
#nullable disable warnings
Expand All @@ -8,8 +7,8 @@ public class AuditTrailAdvancedSpecification : Specification<AuditTrail>
public AuditTrailAdvancedSpecification(AuditTrailsWithPaginationQuery filter)
{
DateTime today = DateTime.UtcNow;
var todayrange = today.GetDateRange("TODAY", filter.LocalTimezoneOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS",filter.LocalTimezoneOffset);
var todayrange = today.GetDateRange("TODAY", filter.CurrentUser.LocalTimeOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS",filter.CurrentUser.LocalTimeOffset);



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ContactsWithPaginationQuery : ContactAdvancedFilter, ICacheableRequ
{
public override string ToString()
{
return $"Listview:{ListView}-{LocalTimezoneOffset.TotalHours}, Search:{Keyword}, {OrderBy}, {SortDirection}, {PageNumber}, {PageSize}";
return $"Listview:{ListView}-{CurrentUser?.UserId}, Search:{Keyword}, {OrderBy}, {SortDirection}, {PageNumber}, {PageSize}";
}
public string CacheKey => ContactCacheKey.GetPaginationCacheKey($"{this}");
public MemoryCacheEntryOptions? Options => ContactCacheKey.MemoryCacheEntryOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public enum ContactListView
/// </summary>
public class ContactAdvancedFilter: PaginationFilter
{
public TimeSpan LocalTimezoneOffset { get; set; }
public ContactListView ListView { get; set; } = ContactListView.All;
public UserProfile? CurrentUser { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public ContactAdvancedSpecification(ContactAdvancedFilter filter)
{

DateTime today = DateTime.UtcNow;
var todayrange = today.GetDateRange(ContactListView.TODAY.ToString(), filter.LocalTimezoneOffset);
var last30daysrange = today.GetDateRange(ContactListView.LAST_30_DAYS.ToString(),filter.LocalTimezoneOffset);
var todayrange = today.GetDateRange(ContactListView.TODAY.ToString(), filter.CurrentUser.LocalTimeOffset);
var last30daysrange = today.GetDateRange(ContactListView.LAST_30_DAYS.ToString(),filter.CurrentUser.LocalTimeOffset);

Query.Where(q => q.Name != null)
.Where(filter.Keyword,!string.IsNullOrEmpty(filter.Keyword))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class DocumentsWithPaginationQuery : AdvancedDocumentsFilter, ICacheableR
public override string ToString()
{
return
$"CurrentUserId:{CurrentUser?.UserId},ListView:{ListView}-{LocalTimezoneOffset.TotalHours},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
$"CurrentUserId:{CurrentUser?.UserId},ListView:{ListView},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public enum DocumentListView

public class AdvancedDocumentsFilter : PaginationFilter
{
public TimeSpan LocalTimezoneOffset { get; set; }
public DocumentListView ListView { get; set; } = DocumentListView.All;
public UserProfile? CurrentUser { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ public class AdvancedDocumentsSpecification : Specification<Document>
{
public AdvancedDocumentsSpecification(AdvancedDocumentsFilter filter)
{

DateTime today = DateTime.UtcNow;
var todayrange = today.GetDateRange("TODAY", filter.LocalTimezoneOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.LocalTimezoneOffset);

var todayrange = today.GetDateRange("TODAY", filter.CurrentUser.LocalTimeOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.CurrentUser.LocalTimeOffset);
Query.Where(p =>
(p.CreatedBy == filter.CurrentUser.UserId && p.IsPublic == false) ||
(p.IsPublic == true && p.TenantId == filter.CurrentUser.TenantId),
Expand Down
14 changes: 12 additions & 2 deletions src/Application/Features/Identity/DTOs/ApplicationUserDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ public class ApplicationUserDto
[Description("Email Confirmed")] public bool EmailConfirmed { get; set; }

[Description("Status")] public DateTimeOffset? LockoutEnd { get; set; }

[Description("Time Zone")]
public string? TimeZoneId { get; set; }
[Description("Local Time Offset")]
public TimeSpan LocalTimeOffset => string.IsNullOrEmpty(TimeZoneId)
? TimeZoneInfo.Local.BaseUtcOffset
: TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId).BaseUtcOffset;
[Description("Language")]
public string? LanguageCode { get; set; }
public UserProfile ToUserProfile()
{
return new UserProfile
Expand All @@ -60,7 +67,9 @@ public UserProfile ToUserProfile()
SuperiorId = SuperiorId,
SuperiorName = Superior?.UserName,
AssignedRoles = AssignedRoles,
DefaultRole = DefaultRole
DefaultRole = DefaultRole,
TimeZoneId = TimeZoneId,
LanguageCode = LanguageCode
};
}

Expand All @@ -74,6 +83,7 @@ private class Mapping : Profile
public Mapping()
{
CreateMap<ApplicationUser, ApplicationUserDto>(MemberList.None)
.ForMember(x => x.LocalTimeOffset, s => s.Ignore())
.ForMember(x => x.EmailConfirmed, s => s.MapFrom(y => y.EmailConfirmed))
.ForMember(x => x.AssignedRoles, s => s.MapFrom(y => y.UserRoles.Select(r => r.Role.Name)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class LogsWithPaginationQuery : LoggerAdvancedFilter, ICacheableRequest<P
public override string ToString()
{
return
$"Listview:{ListView}-{LocalTimezoneOffset.TotalHours},{Level},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
$"Listview:{ListView}-{LocalTimeOffset.TotalHours},{Level},Search:{Keyword},OrderBy:{OrderBy} {SortDirection},{PageNumber},{PageSize}";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public enum LogListView

public class LoggerAdvancedFilter : PaginationFilter
{
public TimeSpan LocalTimezoneOffset { get; set; }
public TimeSpan LocalTimeOffset { get; set; }
public LogLevel? Level { get; set; }
public LogListView ListView { get; set; } = LogListView.LAST_30_DAYS;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ public class LoggerAdvancedSpecification : Specification<Logger>
public LoggerAdvancedSpecification(LogsWithPaginationQuery filter)
{
DateTime today = DateTime.UtcNow;
var todayrange = today.GetDateRange("TODAY", filter.LocalTimezoneOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.LocalTimezoneOffset);
var todayrange = today.GetDateRange("TODAY", filter.LocalTimeOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.LocalTimeOffset);
// Build query conditions
Query.Where(p => p.TimeStamp >= todayrange.Start && p.TimeStamp < todayrange.End.AddDays(1),
filter.ListView == LogListView.TODAY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class ProductsWithPaginationQuery : ProductAdvancedFilter, ICacheableRequ
public override string ToString()
{
return
$"CurrentUser:{CurrentUser?.UserId},ListView:{ListView}-{LocalTimezoneOffset.TotalHours},Search:{Keyword},Name:{Name},Brand:{Brand},Unit:{Unit},MinPrice:{MinPrice},MaxPrice:{MaxPrice},SortDirection:{SortDirection},OrderBy:{OrderBy},{PageNumber},{PageSize}";
$"CurrentUser:{CurrentUser?.UserId},ListView:{ListView},Search:{Keyword},Name:{Name},Brand:{Brand},Unit:{Unit},MinPrice:{MinPrice},MaxPrice:{MaxPrice},SortDirection:{SortDirection},OrderBy:{OrderBy},{PageNumber},{PageSize}";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,4 @@ public class ProductAdvancedFilter : PaginationFilter

public UserProfile?
CurrentUser { get; set; } // <-- This CurrentUser property gets its value from the information of

public TimeSpan LocalTimezoneOffset { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ public class ProductAdvancedSpecification : Specification<Product>
public ProductAdvancedSpecification(ProductAdvancedFilter filter)
{
DateTime today = DateTime.UtcNow;
var todayrange = today.GetDateRange("TODAY",filter.LocalTimezoneOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.LocalTimezoneOffset);
var todayrange = today.GetDateRange("TODAY",filter.CurrentUser.LocalTimeOffset);
var last30daysrange = today.GetDateRange("LAST_30_DAYS", filter.CurrentUser.LocalTimeOffset);
Query.Where(x => x.Name != null)
.Where(x => x.Name.Contains(filter.Keyword) || x.Description.Contains(filter.Keyword) ||
x.Brand.Contains(filter.Keyword), !string.IsNullOrEmpty(filter.Keyword))
Expand Down
15 changes: 13 additions & 2 deletions src/Domain/Common/Entities/BaseAuditableEntity.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace CleanArchitecture.Blazor.Domain.Common.Entities;

public abstract class BaseAuditableEntity : BaseEntity
public abstract class BaseAuditableEntity : BaseEntity, IAuditableEntity
{
public virtual DateTime? Created { get; set; }

Expand All @@ -12,4 +12,15 @@ public abstract class BaseAuditableEntity : BaseEntity
public virtual DateTime? LastModified { get; set; }

public virtual string? LastModifiedBy { get; set; }
}

public interface IAuditableEntity
{
DateTime? Created { get; set; }

string? CreatedBy { get; set; }

DateTime? LastModified { get; set; }

string? LastModifiedBy { get; set; }
}
8 changes: 7 additions & 1 deletion src/Domain/Identity/ApplicationRole.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using CleanArchitecture.Blazor.Domain.Common.Entities;

namespace CleanArchitecture.Blazor.Domain.Identity;

public class ApplicationRole : IdentityRole
public class ApplicationRole : IdentityRole, IAuditableEntity
{
public ApplicationRole()
{
Expand All @@ -21,4 +23,8 @@ public ApplicationRole(string roleName) : base(roleName)
public string? Description { get; set; }
public virtual ICollection<ApplicationRoleClaim> RoleClaims { get; set; }
public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
public DateTime? Created { get; set; }
public string? CreatedBy { get; set; }
public DateTime? LastModified { get; set; }
public string? LastModifiedBy { get; set; }
}
12 changes: 10 additions & 2 deletions src/Domain/Identity/ApplicationUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel.DataAnnotations.Schema;
using CleanArchitecture.Blazor.Domain.Common.Entities;

namespace CleanArchitecture.Blazor.Domain.Identity;

public class ApplicationUser : IdentityUser
public class ApplicationUser : IdentityUser, IAuditableEntity
{
public ApplicationUser()
{
Expand All @@ -20,7 +21,7 @@ public ApplicationUser()
public string? TenantId { get; set; }
public virtual Tenant? Tenant { get; set; }

[Column(TypeName = "text")] public string? ProfilePictureDataUrl { get; set; }
public string? ProfilePictureDataUrl { get; set; }

public bool IsActive { get; set; }
public bool IsLive { get; set; }
Expand All @@ -33,4 +34,11 @@ public ApplicationUser()

public string? SuperiorId { get; set; } = null;
public ApplicationUser? Superior { get; set; } = null;
public DateTime? Created { get; set; }
public string? CreatedBy { get; set; }
public DateTime? LastModified { get; set; }
public string? LastModifiedBy { get; set; }

public string? TimeZoneId { get; set; }
public string? LanguageCode { get; set; }
}
20 changes: 10 additions & 10 deletions src/Infrastructure/Constants/Localization/LocalizationConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,47 @@ public static class LocalizationConstants
new()
{
Code = "en-US",
DisplayName = "English"
DisplayName = "English (United States)"
},
new()
{
Code = "de-DE",
DisplayName = "Deutsch"
DisplayName = "Deutsch (Deutschland)"
},
new()
{
Code = "ru-RU",
DisplayName = "Russian"
DisplayName = "русский (Россия)"
},
new()
{
Code = "fr-FR",
DisplayName = "French"
DisplayName = "français (France)"
},
new()
{
Code = "ja-JP",
DisplayName = "Japanese"
DisplayName = "日本語 (日本)"
},
new()
{
Code = "km-KH",
DisplayName = "Khmer"
DisplayName = "ខ្មែរ (កម្ពុជា)"
},
new()
{
Code = "ca-ES",
DisplayName = "Catalan"
DisplayName = "català (Espanya)"
},
new()
{
Code = "es-ES",
DisplayName = "Spanish"
DisplayName = "español (España)"
},
new()
{
Code = "zh-CN",
DisplayName = "中文"
DisplayName = "中文(简体,中国)"
},
new()
{
Expand All @@ -62,7 +62,7 @@ public static class LocalizationConstants
new()
{
Code = "ko-kr",
DisplayName = "Korean"
DisplayName = "한국어(대한민국)"
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ private async Task SeedUsersAsync()
Email = "[email protected]",
EmailConfirmed = true,
ProfilePictureDataUrl = "https://s.gravatar.com/avatar/78be68221020124c23c665ac54e07074?s=80",
LanguageCode="en-US",
TimeZoneId= "Asia/Shanghai",
TwoFactorEnabled = false
};

Expand All @@ -161,6 +163,8 @@ private async Task SeedUsersAsync()
DisplayName = UserName.Demo,
Email = "[email protected]",
EmailConfirmed = true,
LanguageCode = "de-DE",
TimeZoneId = "Europe/Berlin",
ProfilePictureDataUrl = "https://s.gravatar.com/avatar/ea753b0b0f357a41491408307ade445e?s=80"
};

Expand Down
Loading
Loading