Web API for the bulk printing desktop application.

BatchesController.cs 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using BulkPrintingAPI.Configuration;
  2. using BulkPrintingAPI.Pagination;
  3. using MAX.Models;
  4. using Microsoft.AspNetCore.Mvc;
  5. using Microsoft.EntityFrameworkCore;
  6. using Microsoft.Extensions.Caching.Memory;
  7. using Microsoft.Extensions.Logging;
  8. using System;
  9. using System.ComponentModel.DataAnnotations;
  10. using System.Linq;
  11. using System.Threading.Tasks;
  12. namespace BulkPrintingAPI.Controllers
  13. {
  14. [Produces("application/json")]
  15. [Route("api/[controller]")]
  16. public class BatchesController : Controller
  17. {
  18. public class OrderRequest
  19. {
  20. [Required]
  21. public int? ProductId { get; set; }
  22. [Required]
  23. [Range(1, int.MaxValue)]
  24. public int Quantity { get; set; }
  25. [Required]
  26. public string CustomerReference { get; set; }
  27. [Required]
  28. public string InternalReference { get; set; }
  29. public Guid? OrderGuid { get; set; }
  30. };
  31. private readonly ILogger _logger;
  32. private readonly IMemoryCache _cache;
  33. private readonly DataEncryptionOptions _dataEncryptionOptions;
  34. private readonly SFTPOptions _sftpOptions;
  35. private readonly MAX.ClientFactory _clientFactory;
  36. private readonly MAXContext _context;
  37. public BatchesController(ILoggerFactory loggerFactory, IMemoryCache cache,
  38. DataEncryptionOptions dataEncryptionOptions, SFTPOptions sftpOptions,
  39. MAX.ClientFactory clientFactory, MAXContext context)
  40. {
  41. _logger = loggerFactory.CreateLogger(GetType().FullName);
  42. _cache = cache;
  43. _dataEncryptionOptions = dataEncryptionOptions;
  44. _sftpOptions = sftpOptions;
  45. _clientFactory = clientFactory;
  46. _context = context;
  47. }
  48. private IQueryable<Batch> BatchesForVendor(int vendorId)
  49. {
  50. return _context.Batches.Where(b => b.VendorId == vendorId);
  51. }
  52. [HttpGet]
  53. public async Task<Page<Batch>> GetBatchesAsync([FromQuery] int page = 1,
  54. [FromQuery] int pageSize = 100, [FromQuery] int? lastBatchId = null, int? minBatchId = null)
  55. {
  56. var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context);
  57. var query = BatchesForVendor(credentials.Vendor.Id);
  58. if (minBatchId.HasValue)
  59. {
  60. query = query.Where(b => b.Id >= minBatchId.Value).OrderBy(b => b.Id);
  61. }
  62. else if (lastBatchId.HasValue)
  63. {
  64. // Deprecated in favour of minBatchId for clarity. Use minBatchId = lastBatchId + 1 for equivalent
  65. // functionality
  66. query = query.Where(b => b.Id > lastBatchId.Value).OrderBy(b => b.Id);
  67. }
  68. else
  69. {
  70. query = query.OrderByDescending(b => b.Id);
  71. }
  72. return await Page<Batch>.GetPageAsync(query, page, pageSize);
  73. }
  74. [HttpGet("{id}")]
  75. public async Task<IActionResult> GetBatchAsync([FromRoute] int id)
  76. {
  77. if (!ModelState.IsValid)
  78. {
  79. return BadRequest(ModelState);
  80. }
  81. var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context);
  82. var batch = await BatchesForVendor(credentials.Vendor.Id)
  83. .Include(b => b.Account)
  84. .SingleOrDefaultAsync(m => m.Id == id);
  85. if (batch == null)
  86. {
  87. return NotFound();
  88. }
  89. if (!batch.ReadyForDownload)
  90. {
  91. try
  92. {
  93. await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, batch);
  94. }
  95. catch (Exception e)
  96. {
  97. _logger.LogError(string.Format(
  98. "Failed to download vouchers for {0} batchId={1}: {2}",
  99. credentials.ToString(), batch.Id, e.Message));
  100. }
  101. }
  102. return Ok(batch);
  103. }
  104. [HttpPost]
  105. public async Task<IActionResult> PlaceOrderAsync([FromBody] OrderRequest order)
  106. {
  107. if (!ModelState.IsValid)
  108. {
  109. return BadRequest(ModelState);
  110. }
  111. if (order.OrderGuid.HasValue)
  112. {
  113. var batch = await _context.Batches.SingleOrDefaultAsync(b => b.OrderGuid == order.OrderGuid.Value);
  114. if (batch != null)
  115. {
  116. return BadRequest(new { error = "Duplicate OrderGuid" });
  117. }
  118. }
  119. var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context);
  120. var catalogue = await Utils.GetProductCatalogueAsync(_clientFactory, _logger, _cache,
  121. credentials, false);
  122. Product product;
  123. if (!catalogue.ProductMap.TryGetValue(order.ProductId.Value, out product))
  124. {
  125. return BadRequest(new { error = "Invalid product ID" });
  126. }
  127. var orderResponse = await MAX.Utils.PlaceOrderAsync(_clientFactory, _logger,
  128. credentials, product, order.Quantity, order.CustomerReference, order.InternalReference, order.OrderGuid,
  129. Utils.AesDecryptBytes(credentials.Vendor.EncryptedVoucherKey,
  130. _dataEncryptionOptions.DefaultKey));
  131. _context.Batches.Add(orderResponse.Batch);
  132. credentials.User.Account.Balance = orderResponse.RemainingBalance;
  133. await _context.SaveChangesAsync();
  134. _logger.LogDebug("Saved batchId={0} for {1}", orderResponse.Batch.Id, credentials.ToString());
  135. try
  136. {
  137. await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, orderResponse.Batch);
  138. }
  139. catch (Exception e)
  140. {
  141. _logger.LogError(string.Format(
  142. "Failed to download vouchers for {0} batchId={1}: {2}",
  143. credentials.ToString(), orderResponse.Batch.Id, e.Message));
  144. }
  145. return Ok(orderResponse);
  146. }
  147. }
  148. }