using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using HashidsNet; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using MisIngredientesVue.Core.Exceptions; using MisIngredientesVue.Core.Extensions; using MisIngredientesVue.Core.Models; using MisIngredientesVue.Core.Services; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using AuthenticationToken = MisIngredientesVue.Core.Models.AuthenticationToken; namespace MisIngredientesVue.Controllers { [Route("api/[controller]")] [ApiController] public class AccountController : Controller { private readonly IAuthenticationTokenService _authenticationTokenService; private readonly IUsersService _userService; private readonly ISettingsService _settingsService; private readonly IInvoicingService _invoicingService; private readonly IEmailService _emailService; private readonly IBillingService _billingService; private readonly string APP_VERSION = "24"; private readonly string SHARE_LINK_SALT = "AO7P#KDjdO9KDj$klDkamN3?mDPqAOSddJKDJs"; public AccountController(IAuthenticationTokenService authenticationTokenService, IUsersService userService, ISettingsService settingsService, IInvoicingService invoicingService, IEmailService emailService, IBillingService billingService) { _authenticationTokenService = authenticationTokenService; _userService = userService; _settingsService = settingsService; _invoicingService = invoicingService; _emailService = emailService; _billingService = billingService; } [AllowAnonymous] [Route("contact")] [HttpPost] public async Task SendEmail([FromBody] EmailData emailData) { if (string.IsNullOrWhiteSpace(emailData.CaptchaResponse)) return BadRequest(); _emailService.SendEmail(false, "noreply@misingredientes.mx", new string[] { emailData.FromEmail }, "Confirmación de mensaje enviado en Mis Ingredientes", $"Hola {emailData.From}. Muchas gracias por escribirnos, pronto nos pondremos en contacto contigo. Tu mensaje: {emailData.Body}."); _emailService.SendEmail(false, "noreply@misingredientes.mx", new string[] { "hola@misingredientes.mx" }, "Nuevo mensaje en misingredientes.mx", $"De: {emailData.From}, Correo: {emailData.FromEmail}. Teléfono: {emailData.Phone}. {emailData.Body}."); return Ok(); } [Route("logo/{id}")] [HttpGet] [AllowAnonymous] public async Task GetCompanyLogoImage(string id, string t) { if(User.Identity.IsAuthenticated) return File(await _userService.GetCompanyImage(id, User.Identity.HasFreeSubscription()), "image/png"); return File(await _userService.GetCompanyImage(id, false), "image/png"); } [Route("public/settingsfromtemplateid/{templateId}")] [HttpGet] [AllowAnonymous] public async Task GetCompanyLogoUrlByTemplateId(string templateId) { return Ok(await _userService.GetSettingsFromTemplateId(templateId)); } [AllowAnonymous] [Route("sendresetpasswordemail")] [HttpPost] public async Task SendResetPasswordEmail(SendResetPasswordEmailRequest request) { var code = await _userService.GenerateResetPasswordCode(request.Email); var url = $"{Request.Scheme}://{Request.Host}{Request.PathBase}/resetpassword?code={code}"; var user = await _userService.TryGetUserByEmail(request.Email); var emailBody = await _settingsService.GetEmailTemplateBody(null, EmailTemplateKey.UsersResetPassword); if (user != null) { Console.WriteLine(url); _emailService.SendEmail(false, "noreply@misingredientes.mx", new string[] { request.Email }, "Mis Ingredientes - Recupere su contraseña", emailBody.Replace("[LINK]", url), true); } return Ok(); } [AllowAnonymous] [Route("sendconfirmationemail")] [HttpPost] public async Task SendConfirmationEmail(SendResetPasswordEmailRequest request) { var code = await _userService.GenerateResetPasswordCode(request.Email); var url = $"{Request.Scheme}://{Request.Host}{Request.PathBase}/verification?code={code}"; var user = await _userService.TryGetUserByEmail(request.Email); var emailBody = await _settingsService.GetEmailTemplateBody(null, EmailTemplateKey.UsersConfirmation); if (user != null) { Console.WriteLine(url); _emailService.SendEmail(false, "noreply@misingredientes.mx", new string[] { request.Email }, "Mis Ingredientes - Confirme su dirección de correo", emailBody.Replace("[LINK]", url), true); } return Ok(); } [AllowAnonymous] [Route("token")] [HttpPost] [ProducesResponseType(typeof(AuthenticationToken), (int)HttpStatusCode.OK)] public async Task Token([FromBody] UserCredentials credentials) { //if (appName == "sellers") //{ // var seller = await _userService.TryGetSellerByEmailAndPassword(credentials.Email, credentials.Password); // if (seller == null) // return BadRequest("Invalid Credentials"); // var sellerAuthToken = _authenticationTokenService.GetTokenForSeller(seller); // return Ok(sellerAuthToken); //} var user = await _userService.TryGetUserByEmailAndPassword(credentials.Email, credentials.Password); if (user != null && !user.IsConfirmed) { await SendConfirmationEmail(new SendResetPasswordEmailRequest() { Email = user.Email }); } if (user == null || !user.IsActive || !user.IsConfirmed) return BadRequest("Invalid Credentials"); var invoicingInfo = await _invoicingService.GetInvoicingInfo(user.TenantId); var authToken = await _authenticationTokenService.GetTokenForUser(user.TenantId, user, invoicingInfo); return Ok(authToken); } [AllowAnonymous] [Route("resetpassword")] [HttpPost] public async Task ResetPassword([FromBody] ResetPasswordModel resetPasswordModel) { if (resetPasswordModel.Password != resetPasswordModel.RepeatPassword) return BadRequest(); if(!string.IsNullOrEmpty(resetPasswordModel.Code)) { await _userService.ResetPasswordFromCode(resetPasswordModel.Code, resetPasswordModel.Password); } else if (User.Identity.IsAuthenticated) { await _userService.ResetPassword(User.Identity.GetTenantId(), User.Identity.GetUserId(), resetPasswordModel.Password); await RefreshJsonToken(); } return Ok(); } [AllowAnonymous] [Route("verify")] [HttpPost] public async Task ConfirmEmailAddress([FromBody] ConfirmEmailModel model) { if (string.IsNullOrEmpty(model.Code)) return BadRequest(); await _userService.ConfirmEmailAddress(model.Code); if (User.Identity.IsAuthenticated) { await RefreshJsonToken(); } return Ok(); } [Route("logout")] [HttpPost] public async Task Logout() { //TODO: Complete this method return Ok(); } [Route("me")] [HttpPost] public async Task PostCurrentUserInformation([FromForm] UpdateUserRequest request) { ClientUserData data = null; if(request.Image == null || request.Image.Length == 0) { data = await _userService.UpdateUser(User.Identity.GetTenantId(), User.Identity.GetUserId(), request.FirstName, request.LastName, request.Email, request.Phone, request.Role, null, request.Password, null); } else { if (request.Image.Length > 512000) return BadRequest("La imagen es muy grande"); using (var file = request.Image.OpenReadStream()) { using (var ms = new MemoryStream()) { file.CopyTo(ms); data = await _userService.UpdateUser(User.Identity.GetTenantId(), User.Identity.GetUserId(), request.FirstName, request.LastName, request.Email, request.Phone, request.Role, null, request.Password, ms.ToArray()); } } } await RefreshJsonToken(); return Ok(data); } [Route("company")] [HttpPost] public async Task PostCurrentCompanyInfo([FromForm] PostCurrentCompanyInformationRequest request) { var imgSrc = ""; var companyName = request.Name; if (request.Image == null || request.Image.Length == 0) { await _settingsService.SaveSettings(User.Identity.GetTenantId(), new List() { new ClientSetting() { Name = ClientSettingType.CompanyName, Value = request.Name } }); } else { if (request.Image.Length > 512000) return BadRequest("La imagen es muy grande"); using (var file = request.Image.OpenReadStream()) { using (var ms = new MemoryStream()) { file.CopyTo(ms); var imageData = ms.ToArray(); imgSrc = await _userService.SaveCompanyLogo(User.Identity.GetTenantId(), imageData); await _settingsService.SaveSettings(User.Identity.GetTenantId(), new List() { new ClientSetting() { Name = ClientSettingType.CompanyName, Value = request.Name }, new ClientSetting() { Name = ClientSettingType.CompanyLogoUrl, Value = imgSrc } }); } } } await RefreshJsonToken(); return Ok(new { imgSrc, companyName }); } [Route("profileimg/{id}")] [HttpGet] [AllowAnonymous] public async Task GetProfileImage(string id, string t, string initials) { //var initials = $"{GetFirstCharacter(User.Identity.GetFirstName())}{GetFirstCharacter(User.Identity.GetLastName())}"; return File(await _userService.GetImage(id.Split("_")[0], Convert.ToInt32(id.Split("_")[1]), initials?.ToUpper()?.Substring(0,2)), "image/png"); } [Route("version")] [HttpGet] public async Task GetCurrentVersion() { return Ok(new { Version = APP_VERSION }); } [Route("c2s/{id}")] [HttpPost] public async Task GetC2sInfo(string id) { return Ok(new { IsValid = true, ClientName = "El Cliente" }); } //id = ShareId [Route("connect/{id}")] [HttpPost] public async Task ConnectClientAndSupplier(string id) { var hashIds = new Hashids(SHARE_LINK_SALT); var supplierOrClientId = hashIds.Decode(id); if (User.Identity.IsClient()) { await _userService.AddClientToSupplier(User.Identity.GetTenantId(), supplierOrClientId[0]); return Ok(); } else { await _userService.AddSupplierToClient(User.Identity.GetTenantId(), supplierOrClientId[0]); return Ok(); } } [Route("me")] [HttpGet] public async Task GetCurrentUserInformation() { var token = await RefreshJsonToken(); var hashIds = new Hashids(SHARE_LINK_SALT); return Ok(new ClientUserData() { CurrentDateTime = DateTime.UtcNow, AppVersion = APP_VERSION, Id = User.Identity.GetUserId(), TenantId = User.Identity.GetTenantId(), Email = User.Identity.Name, FirstName = User.Identity.GetFirstName(token.Claims), LastName = User.Identity.GetLastName(token.Claims), IsClient = User.Identity.IsClient(), PlanId = User.Identity.GetPlanId(token.Claims), TrialPeriodEnd = User.Identity.GetTrialPeriodEnd(token.Claims), TrialDaysLeft = User.Identity.GetLeftTrialDays(token.Claims), HasFreePlan = User.Identity.GetSubscriptionLevel(token.Claims) == (int)SubscriptionLevelType.Free, IsPlanMonthly = User.Identity.IsPlanMonthly(token.Claims), Role = User.Identity.GetUserRole(token.Claims), HasDefaultPaymentMethodId = User.Identity.HasDefaultPaymentMethodId(token.Claims), ShareId = hashIds.Encode(User.Identity.GetClientOrSupplierId()), ClientOrSupllierId = User.Identity.GetClientOrSupplierId(), Folios = 0, //IsBranchManager = Aquel que tiene 2 o más sucursales (o ninguna sucursal a su cargo) Permissions = User.Identity.GetPermissions(token.Claims), IsBranchManager = User.Identity.GetAssignedBranchIds().Length != 1, InvoicingInfo = User.Identity.GetInvoicingInfo(token.Claims), ProfileImgSrc = User.Identity.GetProfileImgSrc(token.Claims), CompanyLogoImgSrc = User.Identity.GetCompanyLogoImgSrc(token.Claims), CompanyName = User.Identity.GetCompanyName(token.Claims), CompanyLogoImg = await _userService.GetCompanyImageAsBase64String(User.Identity.GetTenantId(), User.Identity.HasFreeSubscription(token.Claims)), SubscriptionLevel = User.Identity.GetSubscriptionLevel(token.Claims), IsTokenVersionCurrent = User.Identity.GetTokenVersion() == AuthenticationTokenService.TOKEN_VERSION }); //return Ok(new ClientUserData() { // CurrentDateTime = DateTime.UtcNow, // AppVersion = APP_VERSION, // Id = User.Identity.GetUserId(), // TenantId = User.Identity.GetTenantId(), // Email = User.Identity.Name, // FirstName = User.Identity.GetFirstName(), // LastName = User.Identity.GetLastName(), // PlanId = User.Identity.GetPlanId(), // TrialPeriodEnd = User.Identity.GetTrialPeriodEnd(), // TrialDaysLeft = User.Identity.GetLeftTrialDays(), // HasFreePlan = User.Identity.GetSubscriptionLevel() == (int)SubscriptionLevelType.Free, // IsPlanMonthly = User.Identity.IsPlanMonthly(), // Role = User.Identity.GetUserRole(), // HasDefaultPaymentMethodId = User.Identity.HasDefaultPaymentMethodId(), // Folios = 0, // InvoicingInfo = User.Identity.GetInvoicingInfo(), // ProfileImgSrc = User.Identity.GetProfileImgSrc(), // CompanyLogoImgSrc = User.Identity.GetCompanyLogoImgSrc(), // CompanyName = User.Identity.GetCompanyName(), // CompanyLogoImg = await _userService.GetCompanyImageAsBase64String(User.Identity.GetTenantId(), User.Identity.HasFreeSubscription()), // //Folios = !string.IsNullOrEmpty(rfc) ? // // (int?)FinkokService.report_total(rfc, // // new DateTime(now.Year, now.Month, 1), // // new DateTime(now.Year, now.Month, DateTime.DaysInMonth(now.Year, now.Month))) : null, // SubscriptionLevel = User.Identity.GetSubscriptionLevel(), // IsTokenVersionCurrent = User.Identity.GetTokenVersion() == AuthenticationTokenService.TOKEN_VERSION //}); } private async Task RefreshJsonToken() { var invoicingInfo = await _invoicingService.GetInvoicingInfo(User.Identity.GetTenantId()); var user = await _userService.GetUser(User.Identity.GetTenantId(), User.Identity.GetUserId(), User.Identity.IsClient()); var newToken = await _authenticationTokenService.GetTokenForUser(user.TenantId, user, invoicingInfo); Response.Headers.Add("x-refresh-token", newToken.Token); return newToken; } private string GetHashSHA1(byte[] data) { using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider()) { return string.Concat(sha1.ComputeHash(data).Select(x => x.ToString("X2"))); } } private string GetFirstCharacter(string str) { if (string.IsNullOrEmpty(str)) return ""; return str.FirstOrDefault().ToString().ToUpper(); } } public class UpdateUserRequest { public IFormFile Image {get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Phone { get; set; } public SystemUserRole? Role { get; set; } public int? CustomRoleId { get; set; } public string Password { get; set; } public string Email { get; set; } } public class EmailData { public string FromEmail { get; set; } public string From { get; set; } public string Body { get; set; } public string Phone { get; set; } public string CaptchaResponse { get; set; } } public class PostCurrentCompanyInformationRequest { public IFormFile Image { get; set; } public string Name { get; set; } } public class SendResetPasswordEmailRequest { [Required] public string Email { get; set; } } }