From e645acee5610e26659a94f869914f54a8c8626f0 Mon Sep 17 00:00:00 2001 From: Okasu007 Date: Fri, 12 Jul 2024 04:09:33 +0700 Subject: [PATCH] feat: Backlog API for logging --- .../Controllers/AccountController.cs | 126 ++++++++++-------- .../Controllers/PaymentController.cs | 12 +- .../Dental_Clinic_System/Program.cs | 4 +- .../Services/BacklogAPI/BacklogAPI.cs | 83 ++++++++++++ .../Services/BacklogAPI/IBacklogAPI.cs | 8 ++ .../Services/MOMO/MOMOPayment.cs | 2 + 6 files changed, 174 insertions(+), 61 deletions(-) create mode 100644 Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/BacklogAPI.cs create mode 100644 Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/IBacklogAPI.cs diff --git a/Dental_Clinic_System/Dental_Clinic_System/Controllers/AccountController.cs b/Dental_Clinic_System/Dental_Clinic_System/Controllers/AccountController.cs index ad6c3d58..8a7e9c59 100644 --- a/Dental_Clinic_System/Dental_Clinic_System/Controllers/AccountController.cs +++ b/Dental_Clinic_System/Dental_Clinic_System/Controllers/AccountController.cs @@ -3,6 +3,7 @@ using Dental_Clinic_System.Helper; using Dental_Clinic_System.Models.Data; using Dental_Clinic_System.Services; +using Dental_Clinic_System.Services.BacklogAPI; using Dental_Clinic_System.Services.EmailSender; using Dental_Clinic_System.Services.GoogleSecurity; using Dental_Clinic_System.Services.MOMO; @@ -25,6 +26,7 @@ using Newtonsoft.Json; using NuGet.Common; using System.Globalization; +using System.Reflection; using System.Security.Claims; using System.Text.Encodings.Web; using ZXing.QrCode.Internal; @@ -39,14 +41,16 @@ public class AccountController : Controller private readonly IEmailSenderCustom _emailSender; private readonly GoogleSecurity _googleSecurity; private readonly IMOMOPayment _momoPayment; + private readonly IBacklogAPI _backlogApi; - public AccountController(DentalClinicDbContext context, IMapper mapper, IEmailSenderCustom emailSender, GoogleSecurity googleSecurity, IMOMOPayment momoPayment) + public AccountController(DentalClinicDbContext context, IMapper mapper, IEmailSenderCustom emailSender, GoogleSecurity googleSecurity, IMOMOPayment momoPayment, IBacklogAPI backlogApi) { _context = context; _mapper = mapper; _emailSender = emailSender; _googleSecurity = googleSecurity; _momoPayment = momoPayment; + _backlogApi = backlogApi; } [HttpGet] @@ -332,6 +336,7 @@ public async Task Login(LoginVM model, string? ReturnUrl) if (errorMessages.Any()) { ViewBag.ToastMessage = string.Join(". ", errorMessages); // Combine all error messages + await _backlogApi.SendErrorToWebhookAsync($"Account Controller || {MethodBase.GetCurrentMethod().Name} Method", string.Join(". ", errorMessages), "153744"); } } return View(); @@ -497,6 +502,8 @@ public async Task GoogleResponse() // Log the exception details (optional) await Console.Out.WriteLineAsync(ex + "Google authentication failed."); + await _backlogApi.SendErrorToWebhookAsync($"Account Controller || {MethodBase.GetCurrentMethod().Name} Method", string.Join(". ", ex), "153744"); + // Redirect to the home page with an error message return RedirectToAction("Login", "Account"); } @@ -520,6 +527,7 @@ public async Task LinkWithGoogle(string emailLinked) if (user == null) { + await _backlogApi.SendErrorToWebhookAsync($"Account Controller || {MethodBase.GetCurrentMethod().Name} Method", "Không tìm thấy người dùng", "153744"); return NotFound(); } @@ -608,66 +616,75 @@ public async Task LinkWithGoogle(string emailLinked) [HttpGet] public async Task Profile() { - - var claimsValue = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value; - if (_context.Accounts.FirstOrDefault(u => u.Email == claimsValue) == null) + try { - await HttpContext.SignOutAsync(); - return RedirectToAction("Index", "Home"); - } - // Extract the Date of Birth claim value - var dateOfBirthClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.DateOfBirth)?.Value; - // Parse the Date of Birth claim value - DateOnly? dateOfBirth = null; - if (DateOnly.TryParse(dateOfBirthClaim, out var parsedDateOfBirth)) - { - dateOfBirth = parsedDateOfBirth; - } - - // Prefill the model with data from claims or other sources - var model = new PatientVM - { - FirstName = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value, - LastName = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value, - PhoneNumber = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.MobilePhone)?.Value, - Email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value, - Gender = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Gender)?.Value, - Address = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.StreetAddress)?.Value, - DateOfBirth = dateOfBirth - }; + var claimsValue = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value; + if (_context.Accounts.FirstOrDefault(u => u.Email == claimsValue) == null) + { + await HttpContext.SignOutAsync(); + return RedirectToAction("Index", "Home"); + } - //var appointment = new Dictionary - //{ - // { "Appointment", await _context.Accounts.Include(p => p.PatientRecords).ThenInclude(a => a.Appointments).ThenInclude(s => s.Schedule).ThenInclude(t => t.TimeSlot).FirstOrDefaultAsync(u => u.Email == model.Email) } - //}; + // Extract the Date of Birth claim value + var dateOfBirthClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.DateOfBirth)?.Value; - var account = await _context.Accounts - .Include(p => p.PatientRecords) - .ThenInclude(pr => pr.Appointments) - .ThenInclude(a => a.Schedule) - .ThenInclude(s => s.TimeSlot) - .Include(p => p.PatientRecords) - .ThenInclude(pr => pr.Appointments) - .ThenInclude(a => a.Specialty) - .Include(p => p.PatientRecords) - .ThenInclude(pr => pr.Appointments) - .ThenInclude(s => s.Schedule) - .ThenInclude(a => a.Dentist) - .ThenInclude(d => d.Account)// Include Dentist information - .Include(p => p.PatientRecords) - .ThenInclude(pr => pr.Appointments) - .ThenInclude(s => s.Schedule) - .ThenInclude(a => a.Dentist) - .ThenInclude(c => c.Clinic) - .FirstOrDefaultAsync(u => u.Email == model.Email); + // Parse the Date of Birth claim value + DateOnly? dateOfBirth = null; + if (DateOnly.TryParse(dateOfBirthClaim, out var parsedDateOfBirth)) + { + dateOfBirth = parsedDateOfBirth; + } - var appointments = account?.PatientRecords.SelectMany(pr => pr.Appointments).Reverse().ToList(); + // Prefill the model with data from claims or other sources + var model = new PatientVM + { + FirstName = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value, + LastName = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value, + PhoneNumber = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.MobilePhone)?.Value, + Email = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value, + Gender = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Gender)?.Value, + Address = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.StreetAddress)?.Value, + DateOfBirth = dateOfBirth + }; - ViewBag.Appointment = appointments; + //var appointment = new Dictionary + //{ + // { "Appointment", await _context.Accounts.Include(p => p.PatientRecords).ThenInclude(a => a.Appointments).ThenInclude(s => s.Schedule).ThenInclude(t => t.TimeSlot).FirstOrDefaultAsync(u => u.Email == model.Email) } + //}; - return View(model); + var account = await _context.Accounts + .Include(p => p.PatientRecords) + .ThenInclude(pr => pr.Appointments) + .ThenInclude(a => a.Schedule) + .ThenInclude(s => s.TimeSlot) + .Include(p => p.PatientRecords) + .ThenInclude(pr => pr.Appointments) + .ThenInclude(a => a.Specialty) + .Include(p => p.PatientRecords) + .ThenInclude(pr => pr.Appointments) + .ThenInclude(s => s.Schedule) + .ThenInclude(a => a.Dentist) + .ThenInclude(d => d.Account)// Include Dentist information + .Include(p => p.PatientRecords) + .ThenInclude(pr => pr.Appointments) + .ThenInclude(s => s.Schedule) + .ThenInclude(a => a.Dentist) + .ThenInclude(c => c.Clinic) + .FirstOrDefaultAsync(u => u.Email == model.Email); + + var appointments = account?.PatientRecords.SelectMany(pr => pr.Appointments).Reverse().ToList(); + + ViewBag.Appointment = appointments; + return View(model); + } + catch(Exception ex) + { + await _backlogApi.SendErrorToWebhookAsync($"Account Controller || {MethodBase.GetCurrentMethod().Name} Method", string.Join(". ", ex), "153853"); + return NotFound(); + } + } @@ -829,7 +846,7 @@ public async Task RateAppointment(int clinicID, int dentistID, in { Rating = rating, Comment = comment, - Date = DateOnly.FromDateTime(DateTime.UtcNow), + Date = DateOnly.FromDateTime(Util.GetUtcPlus7Time()), DentistID = dentistID, PatientID = patientID }; @@ -1173,6 +1190,7 @@ public async Task CancelAppointment(int appointmentID, int schedu } else { + await _backlogApi.SendErrorToWebhookAsync($"Account Controller || {HttpContext.GetRouteData().Values["action"]} Method", string.Join(". ", "Không tìm thấy response từ MOMO API"), "153854"); TempData["ToastMessageFailTempData"] = "Đã có lỗi xảy ra trong quá trình hủy khám"; return RedirectToAction("Profile", "Account"); } diff --git a/Dental_Clinic_System/Dental_Clinic_System/Controllers/PaymentController.cs b/Dental_Clinic_System/Dental_Clinic_System/Controllers/PaymentController.cs index f69c6d2f..bb015f10 100644 --- a/Dental_Clinic_System/Dental_Clinic_System/Controllers/PaymentController.cs +++ b/Dental_Clinic_System/Dental_Clinic_System/Controllers/PaymentController.cs @@ -293,16 +293,16 @@ public async Task ReturnUrl(string partnerCode, string orderId, s return View("PaymentFail"); } - //await Console.Out.WriteLineAsync("=================="); - //await Console.Out.WriteLineAsync($"Code = {resultCode} | Message = {message}"); - //await Console.Out.WriteLineAsync("=================="); + await Console.Out.WriteLineAsync("=================="); + await Console.Out.WriteLineAsync($"Code = {resultCode} | Message = {message}"); + await Console.Out.WriteLineAsync("=================="); message = message.Trim(); if(message == "Thành công.") { - //await Console.Out.WriteLineAsync("=================="); - //await Console.Out.WriteLineAsync($"Code 2 = {resultCode.GetType().Name} | Message 2 = {message}"); - //await Console.Out.WriteLineAsync("=================="); + await Console.Out.WriteLineAsync("=================="); + await Console.Out.WriteLineAsync($"Code 2 = {resultCode.GetType().Name} | Message 2 = {message}"); + await Console.Out.WriteLineAsync("=================="); message = "Success"; } diff --git a/Dental_Clinic_System/Dental_Clinic_System/Program.cs b/Dental_Clinic_System/Dental_Clinic_System/Program.cs index d03b39ca..ab9b1b7d 100644 --- a/Dental_Clinic_System/Dental_Clinic_System/Program.cs +++ b/Dental_Clinic_System/Dental_Clinic_System/Program.cs @@ -1,6 +1,7 @@ using Dental_Clinic_System.Areas.Admin.Models; using Dental_Clinic_System.Helper; using Dental_Clinic_System.Models.Data; +using Dental_Clinic_System.Services.BacklogAPI; using Dental_Clinic_System.Services.EmailSender; using Dental_Clinic_System.Services.EmailVerification; using Dental_Clinic_System.Services.GoogleSecurity; @@ -105,7 +106,8 @@ // Register EmailVerification (ZeroBounce) Service for Verificating Email builder.Services.AddSingleton(); - +// Register BacklogAPI Service +builder.Services.AddSingleton(); // Register Redis Caching Service //builder.Services.AddStackExchangeRedisCache(options => diff --git a/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/BacklogAPI.cs b/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/BacklogAPI.cs new file mode 100644 index 00000000..0ba6b8a2 --- /dev/null +++ b/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/BacklogAPI.cs @@ -0,0 +1,83 @@ +using Dental_Clinic_System.Helper; + +namespace Dental_Clinic_System.Services.BacklogAPI +{ + public class BacklogAPI : IBacklogAPI + { + public async Task GetSpaceInfoAsync() + { + string backlogApiUrl = "https://rivinger.backlog.com/api/v2/space?apiKey=a4sf65GwuS7fqvUhebSZOt0ZgLUH8ZrCt8DmIpwddcx90iHQkvsRC5ekAgjGw7lm"; + + using (var httpClient = new HttpClient()) + { + var response = await httpClient.GetAsync(backlogApiUrl); + + if (response.IsSuccessStatusCode) + { + var responseBody = await response.Content.ReadAsStringAsync(); + + //Console.WriteLine("=================================================="); + //Console.WriteLine($"Status code: {response.StatusCode}"); + //Console.WriteLine("=================================================="); + + } + else + { + var responseBody = await response.Content.ReadAsStringAsync(); + + //Console.WriteLine($"Failed to get space info. Status code: {response.StatusCode}"); + } + } + } + + public async Task SendErrorToWebhookAsync(string subject, string description, string categoryID) + { + // Category ID + // Login = 153744 + // Schedule = 153745 + // EmailSender = 153746 + // UI = 153747 + // Booking = 153748 + // Firebase = 153750 + // Searching = 153751 + // Register = 153752 + // APIKey = 153753 + // Profile = 153853 + // Cancel Appointment = 153854 + + string backlogApiUrl = "https://rivinger.backlog.com/api/v2/issues?apiKey=a4sf65GwuS7fqvUhebSZOt0ZgLUH8ZrCt8DmIpwddcx90iHQkvsRC5ekAgjGw7lm"; + + var newIssue = new FormUrlEncodedContent(new[] + { + new KeyValuePair("projectId", "135037"), + new KeyValuePair("summary", subject), + new KeyValuePair("description", description), + new KeyValuePair("issueTypeId", "575393"), + new KeyValuePair("priorityId", "2"), + new KeyValuePair("categoryId[]", categoryID), + new KeyValuePair("milestoneId[]", "125475"), + new KeyValuePair("startDate", DateOnly.FromDateTime(Util.GetUtcPlus7Time()).ToString("yyyy-MM-dd")), + //new KeyValuePair("dueDate", "2024-07-24"), + //new KeyValuePair("estimatedHours", "12") + }); + + using (var httpClient = new HttpClient()) + { + var response = await httpClient.PostAsync(backlogApiUrl, newIssue); + + if (!response.IsSuccessStatusCode) + { + var responseBody = await response.Content.ReadAsStringAsync(); + + Console.WriteLine("==============================================================="); + Console.WriteLine($"Failed to create issue. Status code: {response.StatusCode}"); + Console.WriteLine("==============================================================="); + + } + Console.WriteLine("==============================================================="); + Console.WriteLine($"Failed to create issue. Status code: {response.StatusCode}"); + Console.WriteLine("==============================================================="); + } + } + } +} diff --git a/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/IBacklogAPI.cs b/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/IBacklogAPI.cs new file mode 100644 index 00000000..811295d1 --- /dev/null +++ b/Dental_Clinic_System/Dental_Clinic_System/Services/BacklogAPI/IBacklogAPI.cs @@ -0,0 +1,8 @@ +namespace Dental_Clinic_System.Services.BacklogAPI +{ + public interface IBacklogAPI + { + public Task GetSpaceInfoAsync(); + public Task SendErrorToWebhookAsync(string subject, string description, string categoryID); + } +} diff --git a/Dental_Clinic_System/Dental_Clinic_System/Services/MOMO/MOMOPayment.cs b/Dental_Clinic_System/Dental_Clinic_System/Services/MOMO/MOMOPayment.cs index e420e0a4..ad45f9a8 100644 --- a/Dental_Clinic_System/Dental_Clinic_System/Services/MOMO/MOMOPayment.cs +++ b/Dental_Clinic_System/Dental_Clinic_System/Services/MOMO/MOMOPayment.cs @@ -150,7 +150,9 @@ public MOMOPayment(IConfiguration config, DentalClinicDbContext context) } else { + Console.WriteLine("===================================================="); Console.WriteLine("Fail from MOMO Payment"); + Console.WriteLine("===================================================="); // Xử lý lỗi return responseObject; }