using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using BTCPayServer.Data; using BTCPayServer.Models; using BTCPayServer.Models.AppViewModels; using BTCPayServer.Security; using BTCPayServer.Services.Apps; using BTCPayServer.Services.Rates; using Ganss.XSS; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NBitcoin; using NBitcoin.DataEncoders; namespace BTCPayServer.Controllers { [Authorize(AuthenticationSchemes = Policies.CookieAuthentication)] [AutoValidateAntiforgeryToken] [Route("apps")] public partial class AppsController : Controller { public AppsController( UserManager userManager, ApplicationDbContextFactory contextFactory, EventAggregator eventAggregator, BTCPayNetworkProvider networkProvider, CurrencyNameTable currencies, HtmlSanitizer htmlSanitizer, AppService AppService) { _UserManager = userManager; _ContextFactory = contextFactory; _EventAggregator = eventAggregator; _NetworkProvider = networkProvider; _currencies = currencies; _htmlSanitizer = htmlSanitizer; _AppService = AppService; } private UserManager _UserManager; private ApplicationDbContextFactory _ContextFactory; private readonly EventAggregator _EventAggregator; private BTCPayNetworkProvider _NetworkProvider; private readonly CurrencyNameTable _currencies; private readonly HtmlSanitizer _htmlSanitizer; private AppService _AppService; [TempData] public string StatusMessage { get; set; } public string CreatedAppId { get; set; } public async Task ListApps() { var apps = await _AppService.GetAllApps(GetUserId()); return View(new ListAppsViewModel() { Apps = apps }); } [HttpPost] [Route("{appId}/delete")] public async Task DeleteAppPost(string appId) { var appData = await GetOwnedApp(appId); if (appData == null) return NotFound(); if (await _AppService.DeleteApp(appData)) StatusMessage = "App removed successfully"; return RedirectToAction(nameof(ListApps)); } [HttpGet] [Route("create")] public async Task CreateApp() { var stores = await _AppService.GetOwnedStores(GetUserId()); if (stores.Length == 0) { StatusMessage = new StatusMessageModel() { Html = $"Error: You need to create at least one store. Create store", Severity = StatusMessageModel.StatusSeverity.Error }.ToString(); return RedirectToAction(nameof(ListApps)); } var vm = new CreateAppViewModel(); vm.SetStores(stores); return View(vm); } [HttpPost] [Route("create")] public async Task CreateApp(CreateAppViewModel vm) { var stores = await _AppService.GetOwnedStores(GetUserId()); if (stores.Length == 0) { StatusMessage = new StatusMessageModel() { Html = $"Error: You need to create at least one store. Create store", Severity = StatusMessageModel.StatusSeverity.Error }.ToString(); return RedirectToAction(nameof(ListApps)); } var selectedStore = vm.SelectedStore; vm.SetStores(stores); vm.SelectedStore = selectedStore; if (!Enum.TryParse(vm.SelectedAppType, out AppType appType)) ModelState.AddModelError(nameof(vm.SelectedAppType), "Invalid App Type"); if (!ModelState.IsValid) { return View(vm); } if (!stores.Any(s => s.Id == selectedStore)) { StatusMessage = "Error: You are not owner of this store"; return RedirectToAction(nameof(ListApps)); } var id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(20)); using (var ctx = _ContextFactory.CreateContext()) { var appData = new AppData() { Id = id }; appData.StoreDataId = selectedStore; appData.Name = vm.Name; appData.AppType = appType.ToString(); ctx.Apps.Add(appData); await ctx.SaveChangesAsync(); } StatusMessage = "App successfully created"; CreatedAppId = id; switch (appType) { case AppType.PointOfSale: return RedirectToAction(nameof(UpdatePointOfSale), new { appId = id }); case AppType.Crowdfund: return RedirectToAction(nameof(UpdateCrowdfund), new { appId = id }); default: return RedirectToAction(nameof(ListApps)); } } [HttpGet] [Route("{appId}/delete")] public async Task DeleteApp(string appId) { var appData = await GetOwnedApp(appId); if (appData == null) return NotFound(); return View("Confirm", new ConfirmModel() { Title = $"Delete app {appData.Name} ({appData.AppType})", Description = "This app will be removed from this store", Action = "Delete" }); } private Task GetOwnedApp(string appId, AppType? type = null) { return _AppService.GetAppDataIfOwner(GetUserId(), appId, type); } private string GetUserId() { return _UserManager.GetUserId(User); } } }