diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-06-01 21:13:43 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-06-01 21:13:43 +0200 |
| commit | 9383a2fb09ffb60cfe63683106945bd688affa59 (patch) | |
| tree | 65b3f4b48841583e355887db5de5a16e7005fc87 /src/Services | |
| download | vinjesvingenhandel.no-9383a2fb09ffb60cfe63683106945bd688affa59.tar.xz vinjesvingenhandel.no-9383a2fb09ffb60cfe63683106945bd688affa59.zip | |
feat: Initial commit after clean slate
Diffstat (limited to 'src/Services')
| -rw-r--r-- | src/Services/AssetsService.cs | 58 | ||||
| -rw-r--r-- | src/Services/CookieService.cs | 55 | ||||
| -rw-r--r-- | src/Services/EmailService.cs | 45 | ||||
| -rw-r--r-- | src/Services/OrderService.cs | 126 |
4 files changed, 284 insertions, 0 deletions
diff --git a/src/Services/AssetsService.cs b/src/Services/AssetsService.cs new file mode 100644 index 0000000..bf0029a --- /dev/null +++ b/src/Services/AssetsService.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using IOL.Helpers; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using VSH.Data; +using VSH.Data.Static; + +namespace VSH.Services; + +public class AssetsService +{ + private readonly MainDbContext _context; + private readonly ILogger<AssetsService> _logger; + + + public AssetsService(MainDbContext context, ILogger<AssetsService> logger) { + _context = context; + _logger = logger; + } + + public Task RemoveUnusedProductImages() { + try { + _logger.LogDebug("Starting RemoveUnusedProductImages"); + var inUseFileNames = new List<string>(); + + foreach (var productImageList in _context.Products.Select(c => c.Images).AsNoTracking()) { + var defaultFiles = productImageList.Select(image => image.FileName).ToList(); + var smallFiles = defaultFiles.Select(c => c.ExtractFileName() + "-300" + c.ExtractExtension()); + var miniFiles = defaultFiles.Select(c => c.ExtractFileName() + "-150" + c.ExtractExtension()); + inUseFileNames.AddRange(defaultFiles); + inUseFileNames.AddRange(miniFiles); + inUseFileNames.AddRange(smallFiles); + } + + var removedFileCount = 0; + if (inUseFileNames.Any()) { + foreach (var diskFile in Directory.EnumerateFiles(AppPaths.ProductImages.HostPath)) { + if (inUseFileNames.Any(c => c == diskFile)) + continue; + if (File.Exists(diskFile)) + File.Delete(diskFile); + removedFileCount++; + _logger.LogDebug("Deleted " + diskFile); + } + } + + _logger.LogInformation("Removed " + removedFileCount + " unused product images"); + return Task.CompletedTask; + } catch (Exception ex) { + _logger.LogError("Exception removing unused assets: {exception}", ex.Message); + return Task.CompletedTask; + } + } +}
\ No newline at end of file diff --git a/src/Services/CookieService.cs b/src/Services/CookieService.cs new file mode 100644 index 0000000..d73f0b6 --- /dev/null +++ b/src/Services/CookieService.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Globalization; +using VSH.Data.Enums; +using VSH.Data.Miscellaneous; +using VSH.Data.Static; + +namespace VSH.Services; + +public class CookieService +{ + private static Dictionary<string, string> XsrfCookieDescriptions => new() { + { + "en", + "This cookie is only required for submitting forms like the order submit form. The cookie is used to prevent abuse, nothing personal is saved or shared with this cookie." + }, { + "nb", + "Denne informasjonskapselen er bare påkrevd for å sende skjema som for eksempel bestillingsskjema. Informasjonskapselen blir brukt for å forhindre misbruk, ingen persondata blir lagret eller delt med denne informasjonskapselen." + }, + }; + + private static Dictionary<string, string> SessionCookieDescriptions => new() { + { + "en", + "This cookie is only required for keeping you logged in while using this site. The cookie is purely functional and nothing personal is saved or shared with this cookie." + }, { + "nb", + "Denne informasjonskapselen er bare påkrevd for å holde deg logget på imens du bruker denne siden. Informasjonskapselen er bare funksjonell og ingen persondata blir lagret eller delt med denne informasjonskapselen." + }, + }; + + private static Dictionary<string, string> CultureCookieDescriptions => new() { + { + "en", "This cookie is used to keep track of your preffered language, nothing personal is saved or shared with this cookie." + }, { + "nb", + "Denne informasjonskapselen bruker vi for å lagre hvilket språk du vil se siden på, ingen persondata blir lagret eller delt med denne informasjonskapselen." + }, + }; + + public static AppCookie GetCookie(CookieType type) { + var isoCode = CultureInfo.DefaultThreadCurrentCulture?.TwoLetterISOLanguageName ?? Startup.DefaultCulture.TwoLetterISOLanguageName; + return type switch { + CookieType.XSRF => AppCookies.Xsrf with { + Description = XsrfCookieDescriptions[isoCode] + }, + CookieType.SESSION => AppCookies.Session with { + Description = SessionCookieDescriptions[isoCode] + }, + CookieType.CULTURE => AppCookies.Culture with { + Description = CultureCookieDescriptions[isoCode] + }, + _ => default + }; + } +}
\ No newline at end of file diff --git a/src/Services/EmailService.cs b/src/Services/EmailService.cs new file mode 100644 index 0000000..d5098e0 --- /dev/null +++ b/src/Services/EmailService.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace VSH.Services; + +public class EmailService +{ + private readonly string _sendGridApiKey; + private readonly string _fromAddress; + private readonly string _fromName; + private readonly string _replyToAddress; + private readonly ILogger<EmailService> _logger; + + public EmailService(IConfiguration configuration, ILogger<EmailService> logger) { + _sendGridApiKey = configuration.GetValue<string>("SENDGRID_API_KEY"); + _fromAddress = configuration.GetValue<string>("MAIL_FROM_ADDRESS"); + _replyToAddress = configuration.GetValue<string>("MAIL_REPLY_TO_ADDRESS"); + _fromName = configuration.GetValue<string>("MAIL_FROM_NAME"); + _logger = logger; + } + + public async Task<bool> SendEmailAsync( + string subject, + string message, + IEnumerable<string> recipients + ) { + foreach (var recipient in recipients) { + if (!await SendEmailAsync(subject, message, recipient)) { + return false; + } + } + + return true; + } + + public Task<bool> SendEmailAsync( + string subject, + string message, + string recipient + ) { + return Task.FromResult(false); + } +} diff --git a/src/Services/OrderService.cs b/src/Services/OrderService.cs new file mode 100644 index 0000000..21dfdee --- /dev/null +++ b/src/Services/OrderService.cs @@ -0,0 +1,126 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using IOL.Helpers; +using IOL.VippsEcommerce; +using IOL.VippsEcommerce.Models.Api; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Localization; +using VSH.Data; +using VSH.Data.Database; +using VSH.Data.Results; +using VSH.Utilities; + +namespace VSH.Services; + +public class OrderService +{ + private readonly MainDbContext _context; + private readonly IStringLocalizer<SharedServiceResources> _localizer; + private readonly IVippsEcommerceService _vippsService; + private readonly string _vippsMsn; + + public OrderService( + MainDbContext context, + IStringLocalizer<SharedServiceResources> localizer, + IVippsEcommerceService vippsService, + IConfiguration configuration + ) { + _context = context; + _localizer = localizer; + _vippsService = vippsService; + _vippsMsn = configuration.GetValue<string>("VIPPS_MSN"); + } + + public AppValidationResult ValidateOrderProducts(Order payload) { + var validationResult = new AppValidationResult(); + foreach (var product in payload.Products) { + var dbProduct = _context.Products.SingleOrDefault(p => p.Id == product.Id); + if (dbProduct == default || !dbProduct.IsAvailable || !dbProduct.IsVisible) { + var error = new AppValidationResult.ValidationError(product.Id); + error.Errors.Add(string.Format(_localizer["Dette produktet er dessverre ikke tilgjengelig"])); + validationResult.Errors.Add(error); + } else if (dbProduct.Count != -1 && dbProduct.Count < product.NumberOfItems) { + var error = new AppValidationResult.ValidationError(product.Id); + error.Errors.Add(string.Format(_localizer + [ + "Vi har dessverre ikke så mange eksemplarer av dette produktet"])); + validationResult.Errors.Add(error); + } + } + + return validationResult; + } + + public AppValidationResult ValidateOrder(Order payload) { + var validationResult = new AppValidationResult(); + if (payload.ContactInfo != default) { + if (payload.ContactInfo.Name.IsNullOrWhiteSpace()) { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["Navn er påkrevd"]); + validationResult.Errors.Add(error); + } + + if (payload.ContactInfo.EmailAddress.IsNullOrWhiteSpace()) { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["E-postadresse er påkrevd"]); + validationResult.Errors.Add(error); + } else if (!payload.ContactInfo.EmailAddress.IsValidEmailAddress()) { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["E-postadressen er ugyldig"]); + validationResult.Errors.Add(error); + } + + if (payload.ContactInfo.PhoneNumber.IsNullOrWhiteSpace()) { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["Telefonnummer er påkrevd"]); + validationResult.Errors.Add(error); + } else if (!payload.ContactInfo.PhoneNumber.IsValidNorwegianPhoneNumber()) { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["Telefonnummeret er ugyldig"]); + validationResult.Errors.Add(error); + } + } else { + var error = new AppValidationResult.ValidationError(); + error.Errors.Add(_localizer["Kontaktinfo er påkrevd"]); + validationResult.Errors.Add(error); + } + + var productValidationResult = ValidateOrderProducts(payload); + validationResult.Errors.AddRange(productValidationResult.Errors); + + return validationResult; + } + + public async Task<Uri> GetVippsPaymentUrlAsync(Order order, string hostname) { + var totalAmountInOre = order.Products.Sum(c => c.NumberOfItems * c.PriceAtTimeOfOrder) * 100; + + var initiatePaymentRequest = new VippsInitiatePaymentRequest { + CustomerInfo = new TCustomerInfo { + MobileNumber = order.ContactInfo.PhoneNumber + }, + Transaction = new TTransactionInfoInitiate { + Amount = Convert.ToInt32(totalAmountInOre), + OrderId = order.OrderReference, + TimeStamp = DateTime.UtcNow.ToString("o"), + SkipLandingPage = false, + TransactionText = "Bestilling på nett", + UseExplicitCheckoutFlow = false + }, + MerchantInfo = new TMerchantInfo { + FallBack = hostname + "/api/orders/vipps/payment-callback/" + order.OrderReference, + CallbackPrefix = hostname + "/api/orders/vipps/callbacks-for-payment-update", + IsApp = false, + MerchantSerialNumber = _vippsMsn + } + }; + + try { + var response = await _vippsService.InitiatePaymentAsync(initiatePaymentRequest); + return response.Url.IsNullOrWhiteSpace() ? default : new Uri(response.Url); + } catch (Exception e) { + Console.WriteLine(e); + throw; + } + } +}
\ No newline at end of file |
