btcpayserver/BTCPayServer/Controllers/UIAppsController.cs

278 lines
10 KiB
C#
Raw Normal View History

using System;
2018-04-03 04:50:41 +02:00
using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client;
2021-12-31 08:59:02 +01:00
using BTCPayServer.Data;
2018-04-03 04:50:41 +02:00
using BTCPayServer.Models.AppViewModels;
2018-08-22 10:26:49 +02:00
using BTCPayServer.Services.Apps;
using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
2018-04-03 04:50:41 +02:00
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
2023-01-21 19:08:12 +01:00
using Microsoft.AspNetCore.Mvc.Rendering;
2018-04-03 04:50:41 +02:00
namespace BTCPayServer.Controllers
{
[AutoValidateAntiforgeryToken]
[Route("apps")]
2022-01-07 04:32:00 +01:00
public partial class UIAppsController : Controller
2018-04-03 04:50:41 +02:00
{
2022-01-07 04:32:00 +01:00
public UIAppsController(
2018-04-03 04:50:41 +02:00
UserManager<ApplicationUser> userManager,
StoreRepository storeRepository,
IFileService fileService,
2023-01-21 19:08:12 +01:00
AppService appService,
IHtmlHelper html)
2018-04-03 04:50:41 +02:00
{
_userManager = userManager;
_storeRepository = storeRepository;
_fileService = fileService;
_appService = appService;
2023-01-21 19:08:12 +01:00
Html = html;
2018-04-03 04:50:41 +02:00
}
private readonly UserManager<ApplicationUser> _userManager;
private readonly StoreRepository _storeRepository;
private readonly IFileService _fileService;
private readonly AppService _appService;
public string CreatedAppId { get; set; }
2023-01-21 19:08:12 +01:00
public IHtmlHelper Html { get; }
2022-07-18 20:51:53 +02:00
public class AppUpdated
{
public string AppId { get; set; }
public object Settings { get; set; }
public string StoreId { get; set; }
public override string ToString()
{
return string.Empty;
}
}
2022-07-22 15:41:14 +02:00
[HttpGet("/apps/{appId}")]
public async Task<IActionResult> RedirectToApp(string appId)
{
var app = await _appService.GetApp(appId, null);
if (app is null)
return NotFound();
2023-04-10 04:07:03 +02:00
var res = await _appService.ViewLink(app);
if (res is null)
2022-07-22 15:41:14 +02:00
{
return NotFound();
}
return Redirect(res);
2022-07-22 15:41:14 +02:00
}
2021-12-31 08:59:02 +01:00
2022-07-22 15:41:14 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("/stores/{storeId}/apps")]
public async Task<IActionResult> ListApps(
2021-12-31 08:59:02 +01:00
string storeId,
string sortOrder = null,
string sortOrderColumn = null,
bool archived = false
)
2018-04-03 04:50:41 +02:00
{
var store = GetCurrentStore();
var apps = (await _appService.GetAllApps(GetUserId(), false, store.Id, archived))
.Where(app => app.Archived == archived);
2021-12-31 08:59:02 +01:00
if (sortOrder != null && sortOrderColumn != null)
{
2021-12-31 08:59:02 +01:00
apps = apps.OrderByDescending(app =>
{
return sortOrderColumn switch
{
nameof(app.AppName) => app.AppName,
nameof(app.StoreName) => app.StoreName,
nameof(app.AppType) => app.AppType,
_ => app.Id
};
});
switch (sortOrder)
{
case "desc":
ViewData[$"{sortOrderColumn}SortOrder"] = "asc";
break;
case "asc":
apps = apps.Reverse();
ViewData[$"{sortOrderColumn}SortOrder"] = "desc";
break;
}
}
2021-12-31 08:59:02 +01:00
return View(new ListAppsViewModel
2018-04-03 04:50:41 +02:00
{
Apps = apps.ToArray()
2018-04-03 04:50:41 +02:00
});
}
2022-07-22 15:41:14 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("/stores/{storeId}/apps/create/{appType?}")]
public IActionResult CreateApp(string storeId, string appType = null)
2018-04-03 04:50:41 +02:00
{
var vm = new CreateAppViewModel(_appService)
{
StoreId = storeId,
AppType = appType,
SelectedAppType = appType
};
return View(vm);
2018-04-03 04:50:41 +02:00
}
2022-07-22 15:41:14 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpPost("/stores/{storeId}/apps/create/{appType?}")]
public async Task<IActionResult> CreateApp(string storeId, CreateAppViewModel vm)
2018-04-03 04:50:41 +02:00
{
var store = GetCurrentStore();
vm.StoreId = store.Id;
var type = _appService.GetAppType(vm.AppType ?? vm.SelectedAppType);
if (type is null)
{
2018-04-03 04:50:41 +02:00
ModelState.AddModelError(nameof(vm.SelectedAppType), "Invalid App Type");
}
2018-04-03 04:50:41 +02:00
if (!ModelState.IsValid)
{
return View(vm);
}
var appData = new AppData
2018-04-03 04:50:41 +02:00
{
StoreDataId = store.Id,
Name = vm.AppName,
AppType = type!.Type
};
var defaultCurrency = await GetStoreDefaultCurrentIfEmpty(appData.StoreDataId, null);
await _appService.SetDefaultSettings(appData, defaultCurrency);
await _appService.UpdateOrCreateApp(appData);
2023-04-10 04:07:03 +02:00
TempData[WellKnownTempData.SuccessMessage] = "App successfully created";
CreatedAppId = appData.Id;
2018-12-29 11:52:07 +01:00
var url = await type.ConfigureLink(appData);
return Redirect(url);
2018-04-03 04:50:41 +02:00
}
2022-07-22 15:41:14 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpGet("{appId}/delete")]
public IActionResult DeleteApp(string appId)
2018-04-03 04:50:41 +02:00
{
var app = GetCurrentApp();
if (app == null)
2018-04-03 04:50:41 +02:00
return NotFound();
2021-12-31 08:59:02 +01:00
2023-01-21 19:08:12 +01:00
return View("Confirm", new ConfirmModel("Delete app", $"The app <strong>{Html.Encode(app.Name)}</strong> and its settings will be permanently deleted. Are you sure?", "Delete"));
2018-04-03 04:50:41 +02:00
}
2022-07-22 15:41:14 +02:00
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpPost("{appId}/delete")]
public async Task<IActionResult> DeleteAppPost(string appId)
{
var app = GetCurrentApp();
if (app == null)
return NotFound();
2021-12-31 08:59:02 +01:00
if (await _appService.DeleteApp(app))
TempData[WellKnownTempData.SuccessMessage] = "App deleted successfully.";
2021-12-31 08:59:02 +01:00
return RedirectToAction(nameof(UIStoresController.Dashboard), "UIStores", new { storeId = app.StoreDataId });
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpPost("{appId}/archive")]
public async Task<IActionResult> ToggleArchive(string appId)
{
var app = GetCurrentApp();
if (app == null)
return NotFound();
var type = _appService.GetAppType(app.AppType);
if (type is null)
{
return UnprocessableEntity();
}
var archived = !app.Archived;
if (await _appService.SetArchived(app, archived))
{
TempData[WellKnownTempData.SuccessMessage] = archived
? "The app has been archived and will no longer appear in the apps list by default."
: "The app has been unarchived and will appear in the apps list by default again.";
}
else
{
TempData[WellKnownTempData.ErrorMessage] = $"Failed to {(archived ? "archive" : "unarchive")} the app.";
}
var url = await type.ConfigureLink(app);
return Redirect(url);
}
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[HttpPost("{appId}/upload-file")]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> FileUpload(IFormFile file)
{
var app = GetCurrentApp();
var userId = GetUserId();
if (app is null || userId is null)
return NotFound();
if (!file.FileName.IsValidFileName())
{
return Json(new { error = "Invalid file name" });
}
if (!file.ContentType.StartsWith("image/", StringComparison.InvariantCulture))
{
return Json(new { error = "The file needs to be an image" });
}
if (file.Length > 500_000)
{
return Json(new { error = "The file size should be less than 0.5MB" });
}
var formFile = await file.Bufferize();
if (!FileTypeDetector.IsPicture(formFile.Buffer, formFile.FileName))
{
return Json(new { error = "The file needs to be an image" });
}
try
{
var storedFile = await _fileService.AddFile(file, userId);
var fileId = storedFile.Id;
var fileUrl = await _fileService.GetFileUrl(Request.GetAbsoluteRootUri(), fileId);
return Json(new { fileId, fileUrl });
}
catch (Exception e)
{
return Json(new { error = $"Could not save file: {e.Message}" });
}
}
async Task<string> GetStoreDefaultCurrentIfEmpty(string storeId, string currency)
{
if (string.IsNullOrWhiteSpace(currency))
{
var store = await _storeRepository.FindStore(storeId);
currency = store?.GetStoreBlob().DefaultCurrency;
}
return currency?.Trim().ToUpperInvariant();
}
private string GetUserId() => _userManager.GetUserId(User);
private StoreData GetCurrentStore() => HttpContext.GetStoreData();
2021-12-31 08:59:02 +01:00
private AppData GetCurrentApp() => HttpContext.GetAppData();
2018-04-03 04:50:41 +02:00
}
}