using BulkPrintingAPI.Configuration; using BulkPrintingAPI.Pagination; using MAX.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; namespace BulkPrintingAPI.Controllers { [Produces("application/json")] [Route("api/[controller]")] public class BatchesController : Controller { public class OrderRequest { [Required] public int? ProductId { get; set; } [Required] [Range(1, int.MaxValue)] public int Quantity { get; set; } [Required] public string CustomerReference { get; set; } [Required] public string InternalReference { get; set; } public Guid? OrderGuid { get; set; } }; private readonly ILogger _logger; private readonly IMemoryCache _cache; private readonly DataEncryptionOptions _dataEncryptionOptions; private readonly SFTPOptions _sftpOptions; private readonly MAX.ClientFactory _clientFactory; private readonly MAXContext _context; public BatchesController(ILoggerFactory loggerFactory, IMemoryCache cache, DataEncryptionOptions dataEncryptionOptions, SFTPOptions sftpOptions, MAX.ClientFactory clientFactory, MAXContext context) { _logger = loggerFactory.CreateLogger(GetType().FullName); _cache = cache; _dataEncryptionOptions = dataEncryptionOptions; _sftpOptions = sftpOptions; _clientFactory = clientFactory; _context = context; } private IQueryable BatchesForVendor(int vendorId) { return _context.Batches.Where(b => b.VendorId == vendorId); } [HttpGet] public async Task> GetBatchesAsync([FromQuery] int page = 1, [FromQuery] int pageSize = 100) { var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context); return await Page.GetPageAsync( BatchesForVendor(credentials.Vendor.Id).OrderByDescending(b => b.OrderDate), page, pageSize); } [HttpGet("{id}")] public async Task GetBatchAsync([FromRoute] int id) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context); var batch = await BatchesForVendor(credentials.Vendor.Id) .Include(b => b.Account) .SingleOrDefaultAsync(m => m.Id == id); if (batch == null) { return NotFound(); } if (!batch.ReadyForDownload) { try { await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, batch); } catch (Exception e) { _logger.LogError(string.Format( "Failed to download vouchers for {0} batchId={1}: {2}", credentials.ToString(), batch.Id, e.Message)); } } return Ok(batch); } [HttpPost] public async Task PlaceOrderAsync([FromBody] OrderRequest order) { if (!ModelState.IsValid) { return BadRequest(ModelState); } if (order.OrderGuid.HasValue) { var batch = await _context.Batches.SingleOrDefaultAsync(b => b.OrderGuid == order.OrderGuid.Value); if (batch != null) { return BadRequest(new { error = "Duplicate OrderGuid" }); } } var credentials = await Utils.GetLoginCredentialsFromRequestAsync(HttpContext, _context); var catalogue = await Utils.GetProductCatalogueAsync(_clientFactory, _logger, _cache, credentials, false); Product product; if (!catalogue.ProductMap.TryGetValue(order.ProductId.Value, out product)) { return BadRequest(new { error = "Invalid product ID" }); } var orderResponse = await MAX.Utils.PlaceOrderAsync(_clientFactory, _logger, credentials, product, order.Quantity, order.CustomerReference, order.InternalReference, order.OrderGuid, Utils.AesDecryptBytes(credentials.Vendor.EncryptedVoucherKey, _dataEncryptionOptions.DefaultKey)); _context.Batches.Add(orderResponse.Batch); credentials.User.Account.Balance = orderResponse.RemainingBalance; await _context.SaveChangesAsync(); _logger.LogDebug("Saved batchId={0} for {1}", orderResponse.Batch.Id, credentials.ToString()); try { await Utils.DownloadVouchersAsync(_sftpOptions, _context, _logger, orderResponse.Batch); } catch (Exception e) { _logger.LogError(string.Format( "Failed to download vouchers for {0} batchId={1}: {2}", credentials.ToString(), orderResponse.Batch.Id, e.Message)); } return Ok(orderResponse); } } }