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);
        }
Example #2
0
        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);
        }