diff --git a/src/FrontOffice.Main/Pages/Index.razor.cs b/src/FrontOffice.Main/Pages/Index.razor.cs index d64bb3f..94d332a 100644 --- a/src/FrontOffice.Main/Pages/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Index.razor.cs @@ -2,12 +2,13 @@ using FrontOffice.Main.Utilities; using Microsoft.AspNetCore.Components; using MudBlazor; +using System.Security.Cryptography; namespace FrontOffice.Main.Pages; public partial class Index { [Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!; - + [Inject] private MobileNumberEncryptor Encryptor { get; set; } private string? _email; private bool _isLoadingPackages; private List _packs = new(); @@ -15,6 +16,17 @@ public partial class Index protected override async Task OnInitializedAsync() { await LoadPackagesAsync(); + + + //string mobileNumber = "09387342688"; + + //// انکریپت کردن + //string encrypted = Encryptor.EncryptMobileNumber(mobileNumber); + //Console.WriteLine($"Encrypted: {encrypted}"); + + //// دیکریپت کردن برای تست + //string decrypted = Encryptor.DecryptMobileNumber(encrypted); + //Console.WriteLine($"Decrypted: {decrypted}"); } private async Task LoadPackagesAsync() diff --git a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor index 3d135f9..0fc1412 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor +++ b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor @@ -1,41 +1,62 @@ -
-
-
-
-
- - - - @if (_currentUser?.Children?.Any() == true) - { - - } -
-
-
@(_currentUser?.FirstName) @(_currentUser?.LastName)
-
-
- خرید شخصی: - @(_currentUser?.PersonalPurchase?.ToThousands().ToCurrencyUnitIRT() ?? "0 تومان") -
-
- خرید تیمی: - @(_currentUser?.TeamPurchase?.ToThousands().ToCurrencyUnitIRT() ?? "0 تومان") +@if (_currentUser != null) +{ +
+
+
+
+
+ @if (!string.IsNullOrWhiteSpace(_currentUser.Avatar)) + { + + + + } + else + { + + @(string.IsNullOrWhiteSpace(_currentUser.FirstName) ? "N" : _currentUser.FirstName.Substring(0, 1)) + + } + + @if (_currentUser?.Children?.Any() == true) + { + + } +
+
+ @if (!string.IsNullOrWhiteSpace(_currentUser.FirstName) || !string.IsNullOrWhiteSpace(_currentUser.LastName)) + { +
@_currentUser.FirstName @_currentUser.LastName
+ } + else + { +
@_currentUser.Mobile
+ } +
+
+ خرید شخصی: + @(_currentUser?.PersonalPurchase?.ToThousands().ToCurrencyUnitIRT() ?? "0 تومان") +
+
+ خرید تیمی: + @(_currentUser?.TeamPurchase?.ToThousands().ToCurrencyUnitIRT() ?? "0 تومان") +
-
- @if (_isExpanded && _currentUser?.Children?.Any() == true) - { - - - - } + @if (_isExpanded && _currentUser?.Children?.Any() == true) + { + + + + } +
-
+} + diff --git a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs index d6600c4..d64ef65 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChart.razor.cs @@ -1,4 +1,7 @@ -using static FrontOffice.Main.Pages.Profile.Components.OrganizationChartLevel; +using FrontOffice.BFF.User.Protobuf.Protos.User; +using Mapster; +using Microsoft.AspNetCore.Components; +using static FrontOffice.Main.Pages.Profile.Components.OrganizationChartLevel; namespace FrontOffice.Main.Pages.Profile.Components; public partial class OrganizationChart @@ -6,112 +9,82 @@ public partial class OrganizationChart private UserNode? _currentUser; private bool _isExpanded; + [Inject] private UserContract.UserContractClient UserContract { get; set; } = default!; + private GetUserResponse _userProfile = new(); protected override async Task OnInitializedAsync() { await LoadCurrentUser(); } - + private async Task LoadUserProfile() + { + try + { + _userProfile = await UserContract.GetUserAsync(request: new()); + } + catch (Exception ex) + { + // Handle the case when user is not authenticated or API fails + _userProfile = new GetUserResponse(); + } + StateHasChanged(); + } private async Task LoadCurrentUser() { + await LoadUserProfile(); + + // Mock data - replace with actual API call _currentUser = new UserNode { - Id = 1, - FirstName = "علی", - LastName = "رضایی", - Avatar = "images/avatar1.jpg", - PersonalPurchase = 2500000, - TeamPurchase = 15000000, - Children = new List - { - new UserNode - { - Id = 2, - FirstName = "مریم", - LastName = "احمدی", - Avatar = "images/avatar2.jpg", - PersonalPurchase = 1800000, - TeamPurchase = 8500000, - Children = new List - { - new UserNode - { - Id = 5, - FirstName = "سارا", - LastName = "کریمی", - PersonalPurchase = 1200000, - TeamPurchase = 3200000, - Children = new List - { - new UserNode - { - Id = 8, - FirstName = "نازنین", - LastName = "رضایی", - PersonalPurchase = 950000, - TeamPurchase = 2100000 - }, - new UserNode - { - Id = 8, - FirstName = "فرزاد", - LastName = "رضایی", - PersonalPurchase = 950000, - TeamPurchase = 2100000 - } - } - }, - new UserNode - { - Id = 6, - FirstName = "امیر", - LastName = "حسینی", - PersonalPurchase = 950000, - TeamPurchase = 1800000 - } - } - }, - new UserNode - { - Id = 3, - FirstName = "حسن", - LastName = "کریمی", - Avatar = "images/avatar3.jpg", - PersonalPurchase = 2200000, - TeamPurchase = 9200000, - Children = new List - { - new UserNode - { - Id = 7, - FirstName = "فاطمه", - LastName = "رضایی", - PersonalPurchase = 1350000, - TeamPurchase = 4100000 - }, - new UserNode - { - Id = 7, - FirstName = "آرش", - LastName = "رضایی", - PersonalPurchase = 1350000, - TeamPurchase = 4100000 - } - } - }, - new UserNode - { - Id = 4, - FirstName = "زهرا", - LastName = "محمدی", - Avatar = "images/avatar4.jpg", - PersonalPurchase = 1950000, - TeamPurchase = 7800000 - } - } + Id = _userProfile.Id, + FirstName = _userProfile.FirstName, + LastName = _userProfile.LastName, + Mobile = _userProfile.Mobile, + Avatar = _userProfile.AvatarPath, + PersonalPurchase = 0, + TeamPurchase = 0, + Children = await GetUserChildren(userId: _userProfile.Id) }; } + private async Task?> GetUserChildren(long userId) + { + Console.WriteLine("OK0"); + if (userId != 0) + { + Console.WriteLine("OK1"); + var children = await UserContract.GetAllUserByFilterAsync(request: new() + { + Filter = new() + { + ParentId = userId, + } + }); + if (children?.Models?.Any() == true) + { + Console.WriteLine("OK2"); + var result = new List(); + foreach (var item in children.Models) + { + var node = new UserNode + { + Id = item.Id, + FirstName = item.FirstName, + LastName = item.LastName, + Mobile = item.Mobile, + Avatar = item.AvatarPath, + ReferralCode = item.ReferralCode, + PersonalPurchase = 0, + TeamPurchase = 0, + Children = await GetUserChildren(userId: item.Id) + }; + result.Add(node); + } + return result; + } + } + return null; + } private void ToggleExpand() { _isExpanded = !_isExpanded; diff --git a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor index d6e2731..2d33a28 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor +++ b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor @@ -6,11 +6,22 @@
- - - + @if (!string.IsNullOrWhiteSpace(node.Avatar)) + { + + + + } + else + { + + @(string.IsNullOrWhiteSpace(node.FirstName) ? "N" : node.FirstName.Substring(0, 1)) + + } @if (node.Children?.Any() == true) {
-
@node.FirstName @node.LastName
+ @if (!string.IsNullOrWhiteSpace(node.FirstName) || !string.IsNullOrWhiteSpace(node.LastName)) + { +
@node.FirstName @node.LastName
+ } + else + { +
@node.Mobile
+ }
خرید شخصی: diff --git a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor.cs b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor.cs index b643b2b..3f3a4f5 100644 --- a/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Components/OrganizationChartLevel.razor.cs @@ -40,6 +40,8 @@ public partial class OrganizationChartLevel public long Id { get; set; } public string? FirstName { get; set; } public string? LastName { get; set; } + public string? Mobile { get; set; } + public string? ReferralCode { get; set; } public string? Avatar { get; set; } public long? PersonalPurchase { get; set; } public long? TeamPurchase { get; set; } diff --git a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs index 1ea6aba..9a1721d 100644 --- a/src/FrontOffice.Main/Pages/Profile/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Profile/Index.razor.cs @@ -136,7 +136,7 @@ public partial class Index private async Task ShareReferralCode() { - var shareText = $"کد دعوت من در فرصت: {_userProfile.ReferralCode}\nبرای عضویت از این لینک استفاده کنید: {Navigation.BaseUri}?ref={_userProfile.ReferralCode}"; + var shareText = $"کد دعوت من در فرصت: {_userProfile.ReferralCode}\nبرای عضویت از این لینک استفاده کنید:"; try { diff --git a/src/FrontOffice.Main/Program.cs b/src/FrontOffice.Main/Program.cs index 2421db0..02ef306 100644 --- a/src/FrontOffice.Main/Program.cs +++ b/src/FrontOffice.Main/Program.cs @@ -25,6 +25,9 @@ ValidatorOptions.Global.LanguageManager = new CustomFluentValidationLanguageMana var appSettings = builder.Configuration.Get(); UrlUtility.DownloadUrl = appSettings.DownloadUrl; +builder.Services.Configure(builder.Configuration.GetSection("EncryptionSettings")); +builder.Services.AddSingleton(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -51,3 +54,8 @@ public class AppSettings { public string DownloadUrl { get; set; } } +public class EncryptionSettings +{ + public string Key { get; set; } + public string IV { get; set; } +} \ No newline at end of file diff --git a/src/FrontOffice.Main/Utilities/MobileNumberEncryptor.cs b/src/FrontOffice.Main/Utilities/MobileNumberEncryptor.cs new file mode 100644 index 0000000..e6ca1bb --- /dev/null +++ b/src/FrontOffice.Main/Utilities/MobileNumberEncryptor.cs @@ -0,0 +1,122 @@ +using Microsoft.AspNetCore.DataProtection.KeyManagement; +using System.Security.Cryptography; +using System.Text; + +namespace FrontOffice.Main.Utilities; + +public class MobileNumberEncryptor +{ + private readonly string _key; + private readonly string _iv; + public MobileNumberEncryptor(IConfiguration configuration) + { + var encryptionSettings = configuration.GetSection("EncryptionSettings").Get(); + + _key = encryptionSettings?.Key ?? throw new ArgumentNullException("Encryption Key not found in configuration"); + _iv = encryptionSettings?.IV ?? throw new ArgumentNullException("Encryption IV not found in configuration"); + + // اعتبارسنجی سایز + ValidateKeyAndIV(); + } + public MobileNumberEncryptor(string key, string iv) + { + _key = key; + _iv = iv; + ValidateKeyAndIV(); + } + private void ValidateKeyAndIV() + { + try + { + byte[] keyBytes = Convert.FromBase64String(_key); + byte[] ivBytes = Convert.FromBase64String(_iv); + + if (keyBytes.Length != 32) + throw new ArgumentException("Key must be 32 bytes in Base64 format"); + + if (ivBytes.Length != 16) + throw new ArgumentException("IV must be 16 bytes in Base64 format"); + } + catch (FormatException) + { + throw new ArgumentException("Key or IV is not valid Base64 string"); + } + } + + public string EncryptMobileNumber(string mobileNumber) + { + if (string.IsNullOrEmpty(mobileNumber)) + throw new ArgumentException("Mobile number cannot be null or empty"); + + try + { + byte[] key = Convert.FromBase64String(_key); + byte[] iv = Convert.FromBase64String(_iv); + byte[] plainTextBytes = Encoding.UTF8.GetBytes(mobileNumber); + + using (Aes aesAlg = Aes.Create()) + { + aesAlg.Key = key; + aesAlg.IV = iv; + aesAlg.Mode = CipherMode.ECB; + aesAlg.Padding = PaddingMode.PKCS7; + + ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); + + using (MemoryStream msEncrypt = new MemoryStream()) + { + using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) + { + csEncrypt.Write(plainTextBytes, 0, plainTextBytes.Length); + csEncrypt.FlushFinalBlock(); + + byte[] encryptedBytes = msEncrypt.ToArray(); + return Convert.ToBase64String(encryptedBytes); + } + } + } + } + catch (Exception ex) + { + throw new Exception($"Encryption failed: {ex.Message}", ex); + } + } + + public string DecryptMobileNumber(string encryptedMobileNumber) + { + if (string.IsNullOrEmpty(encryptedMobileNumber)) + throw new ArgumentException("Encrypted mobile number cannot be null or empty"); + + try + { + byte[] key = Convert.FromBase64String(_key); + byte[] iv = Convert.FromBase64String(_iv); + byte[] cipherTextBytes = Convert.FromBase64String(encryptedMobileNumber); + + using (Aes aesAlg = Aes.Create()) + { + aesAlg.Key = key; + aesAlg.IV = iv; + aesAlg.Mode = CipherMode.ECB; + aesAlg.Padding = PaddingMode.PKCS7; + + ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); + + using (MemoryStream msDecrypt = new MemoryStream(cipherTextBytes)) + { + using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) + { + using (StreamReader srDecrypt = new StreamReader(csDecrypt)) + { + return srDecrypt.ReadToEnd(); + } + } + } + } + } + catch (Exception ex) + { + throw new Exception($"Decryption failed: {ex.Message}", ex); + } + } +} diff --git a/src/FrontOffice.Main/appsettings.json b/src/FrontOffice.Main/appsettings.json index cbfed17..4760087 100644 --- a/src/FrontOffice.Main/appsettings.json +++ b/src/FrontOffice.Main/appsettings.json @@ -2,6 +2,10 @@ "GwUrl": "https://fogw.kbs1.ir", //"GwUrl": "https://localhost:34781", "DownloadUrl": "https://dl.afrino.co", + "EncryptionSettings": { + "Key": "kmcQ3XTmH4mrdh8VHziuscyf8LLYjG//Kyni81nH/0E=", + "IV": "1wyF3Tt142MOkCpIyCxh/g==" + }, "Logging": { "LogLevel": { "Default": "Information",