public async Task <IWriterResult> DelistCurrency(string adminUserId, UpdateListingStatusModel model) { model.ListingStatus = CurrencyListingStatus.Delisted; var writerResult = await UpdateListingStatus(adminUserId, model); if (!writerResult.Success) { return(writerResult); } using (var context = ExchangeDataContextFactory.CreateContext()) { // Checks for closing trade pairs only as it's expected to be in 'delisting' before it's delisted. var tradePairs = await context.TradePair.Where(t => t.Status == TradePairStatus.Closing && (t.CurrencyId1 == model.CurrencyId || t.CurrencyId2 == model.CurrencyId)).ToListNoLockAsync(); foreach (var tradePair in tradePairs) { tradePair.Status = TradePairStatus.Closed; } using (var adminContext = DataContextFactory.CreateContext()) { adminContext.LogActivity(adminUserId, $"Delisted Currency: {model.Name}"); await adminContext.SaveChangesAsync().ConfigureAwait(false); } await context.SaveChangesAsync().ConfigureAwait(false); await CacheService.InvalidateAsync(CacheKey.Currencies(), CacheKey.CurrencyInfo(), CacheKey.CurrencyDataTable(), CacheKey.CurrencySummary(model.CurrencyId)).ConfigureAwait(false); } writerResult.Message = "Successfully delisted currency."; return(writerResult); }
public async Task <ActionResult> BeginDelistingCurrency(UpdateListingStatusModel model) { if (!ModelState.IsValid) { return(View("DelistCurrencyModal", model)); } if (model.DelistOn == null) { ModelState.AddModelError(nameof(model.DelistOn), "A delist date is required"); return(View("DelistCurrencyModal", model)); } var isAuthenticated = await CryptopiaAuthenticationHelper.VerifyTwoFactorCode(AuthenticatedFeatureType.Delisting, model.TwoFactorCode); if (!isAuthenticated) { ModelState.AddModelError(nameof(model.TwoFactorCode), "Invalid code"); return(View("DelistCurrencyModal", model)); } var result = await AdminCurrencyWriter.BeginDelistingCurrency(User.Identity.GetUserId(), model); if (!ModelState.IsWriterResultValid(result)) { return(View("DelistCurrencyModal", model)); } return(CloseModalSuccess(result.Message)); }
private async Task <IWriterResult> UpdateListingStatus(string adminUserId, UpdateListingStatusModel model) { try { using (var context = ExchangeDataContextFactory.CreateContext()) { var currency = await context.Currency.Where(c => c.Id == model.CurrencyId).FirstOrDefaultNoLockAsync().ConfigureAwait(false); if (currency == null) { return(new WriterResult(false, "Currency not found")); } var oldStatus = currency.ListingStatus; currency.StatusMessage = model.StatusMessage; currency.ListingStatus = model.ListingStatus; currency.Settings.DelistOn = model.DelistOn; using (var adminContext = DataContextFactory.CreateContext()) { adminContext.LogActivity(adminUserId, $"Updated Currency listing status from : {oldStatus} to: {model.ListingStatus}"); await adminContext.SaveChangesAsync().ConfigureAwait(false); } await context.SaveChangesAsync().ConfigureAwait(false); await CacheService.InvalidateAsync(CacheKey.Currencies(), CacheKey.CurrencyInfo(), CacheKey.CurrencyDataTable(), CacheKey.CurrencySummary(model.CurrencyId)).ConfigureAwait(false); return(new WriterResult(true, "Succesfully updated listing status.")); } } catch (Exception) { return(null); } }
public async Task <IWriterResult> BeginDelistingCurrency(string adminUserId, UpdateListingStatusModel model) { model.ListingStatus = CurrencyListingStatus.Delisting; if (model.DelistOn == null) { return(new WriterResult(false, "Delist date cannot be null")); } var writerResult = await UpdateListingStatus(adminUserId, model); if (!writerResult.Success) { return(writerResult); } using (var context = ExchangeDataContextFactory.CreateContext()) { // Checks for open trade pairs only to avoid accidentally relisting delisted currencies. var tradePairs = await context.TradePair.Where(t => (t.Status == TradePairStatus.OK || t.Status == TradePairStatus.Paused) && (t.CurrencyId1 == model.CurrencyId || t.CurrencyId2 == model.CurrencyId)).ToListNoLockAsync(); foreach (var tradePair in tradePairs) { tradePair.Status = TradePairStatus.Closing; } using (var adminContext = DataContextFactory.CreateContext()) { adminContext.LogActivity(adminUserId, "Closing TradePair due to delisting"); await adminContext.SaveChangesAsync().ConfigureAwait(false); } await context.SaveChangesAsync().ConfigureAwait(false); await CacheService.InvalidateAsync(CacheKey.AllTradePairs(), CacheKey.TradePairs()).ConfigureAwait(false); } writerResult.Message = "Successfully started the delisting process."; try { var email = new EmailMessageModel { EmailType = EmailTemplateType.CoinDelisting, BodyParameters = new object[0], SystemIdentifier = model.Symbol }; using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var balances = await context.Balance.Include(b => b.User).Where(b => b.Currency.Name == model.Name && b.Total > 0).OrderBy(b => b.User.Email).ToListNoLockAsync(); if (!balances.Any()) { writerResult.Message = "Successfully started the delisting process but no non zero balances found so no emails were sent."; return(writerResult); } var personalisations = new List <IEmailPersonalisation>(balances.Select(balance => new EmailPersonalisation { Tos = new List <string> { balance.User.Email }, Substitutions = new Dictionary <string, string> { { "-name-", balance.User.UserName }, { "-coinName-", model.Name }, { "-coinSymbol-", model.Symbol }, { "-delistDate-", model.DelistOn.Value.ToString("R") }, { "-delistReason-", model.StatusMessage }, { "-balance-", balance.Total.ToString(CultureInfo.InvariantCulture) } } }) .ToList()); var hasSentSuccessfully = await EmailService.SendEmails(email, personalisations); if (!hasSentSuccessfully) { writerResult.Success = false; writerResult.Message = "Successfully started the delisting process but emails failed to send."; return(writerResult); } } using (var adminContext = DataContextFactory.CreateContext()) { adminContext.LogActivity(adminUserId, $"Started Currency Delisting Process for: {model.Name}"); await adminContext.SaveChangesAsync().ConfigureAwait(false); } } catch (Exception) { return(new WriterResult(false, "Sending emails failed")); } return(writerResult); }