mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-01-18 13:26:47 +01:00
00cc16455c
* App: Add events which the app subscribes to Various events, which are relevant for the app to react to changes made on the server. * Refactor events * Do not extend NewBlockEvent * Refactoring events * Add store role events * Refactoring: Rename StoreUserEvent * Fix: Subscribe to UserEvent.Invited --------- Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
142 lines
6.1 KiB
C#
142 lines
6.1 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Abstractions.Constants;
|
|
using BTCPayServer.Abstractions.Extensions;
|
|
using BTCPayServer.Abstractions.Models;
|
|
using BTCPayServer.Client;
|
|
using BTCPayServer.Data;
|
|
using BTCPayServer.Events;
|
|
using BTCPayServer.Models.StoreViewModels;
|
|
using BTCPayServer.Services;
|
|
using BTCPayServer.Services.Mails;
|
|
using BTCPayServer.Services.Stores;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace BTCPayServer.Controllers;
|
|
|
|
public partial class UIStoresController
|
|
{
|
|
[HttpGet("{storeId}/users")]
|
|
public async Task<IActionResult> StoreUsers()
|
|
{
|
|
var vm = new StoreUsersViewModel { Role = StoreRoleId.Employee.Role };
|
|
await FillUsers(vm);
|
|
return View(vm);
|
|
}
|
|
|
|
[HttpPost("{storeId}/users")]
|
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
|
public async Task<IActionResult> StoreUsers(string storeId, StoreUsersViewModel vm)
|
|
{
|
|
await FillUsers(vm);
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return View(vm);
|
|
}
|
|
|
|
var roles = await _storeRepo.GetStoreRoles(CurrentStore.Id);
|
|
if (roles.All(role => role.Id != vm.Role))
|
|
{
|
|
ModelState.AddModelError(nameof(vm.Role), StringLocalizer["Invalid role"]);
|
|
return View(vm);
|
|
}
|
|
|
|
var user = await _userManager.FindByEmailAsync(vm.Email);
|
|
var isExistingUser = user is not null;
|
|
var isExistingStoreUser = isExistingUser && await _storeRepo.GetStoreUser(storeId, user!.Id) is not null;
|
|
var successInfo = string.Empty;
|
|
if (user == null)
|
|
{
|
|
user = new ApplicationUser
|
|
{
|
|
UserName = vm.Email,
|
|
Email = vm.Email,
|
|
RequiresEmailConfirmation = _policiesSettings.RequiresConfirmedEmail,
|
|
RequiresApproval = _policiesSettings.RequiresUserApproval,
|
|
Created = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
var currentUser = await _userManager.GetUserAsync(HttpContext.User);
|
|
if (currentUser is not null &&
|
|
(await _userManager.CreateAsync(user)) is { Succeeded: true } result)
|
|
{
|
|
var invitationEmail = await _emailSenderFactory.IsComplete();
|
|
var evt = await UserEvent.Invited.Create(user, currentUser, _callbackGenerator, Request, invitationEmail);
|
|
_eventAggregator.Publish(evt);
|
|
|
|
var info = invitationEmail
|
|
? "An invitation email has been sent.<br/>You may alternatively"
|
|
: "An invitation email has not been sent, because the server does not have an email server configured.<br/> You need to";
|
|
successInfo = $"{info} share this link with them: <a class='alert-link' href='{evt.InvitationLink}'>{evt.InvitationLink}</a>";
|
|
}
|
|
else
|
|
{
|
|
ModelState.AddModelError(nameof(vm.Email), "User could not be invited");
|
|
return View(vm);
|
|
}
|
|
}
|
|
|
|
var roleId = await _storeRepo.ResolveStoreRoleId(storeId, vm.Role);
|
|
var action = isExistingUser
|
|
? isExistingStoreUser ? "updated" : "added"
|
|
: "invited";
|
|
if (await _storeRepo.AddOrUpdateStoreUser(CurrentStore.Id, user.Id, roleId))
|
|
{
|
|
TempData.SetStatusMessageModel(new StatusMessageModel
|
|
{
|
|
Severity = StatusMessageModel.StatusSeverity.Success,
|
|
AllowDismiss = false,
|
|
Html = $"User {action} successfully." + (string.IsNullOrEmpty(successInfo) ? "" : $" {successInfo}")
|
|
});
|
|
return RedirectToAction(nameof(StoreUsers));
|
|
}
|
|
|
|
ModelState.AddModelError(nameof(vm.Email), $"The user could not be {action}");
|
|
return View(vm);
|
|
}
|
|
|
|
[HttpPost("{storeId}/users/{userId}")]
|
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
|
public async Task<IActionResult> UpdateStoreUser(string storeId, string userId, StoreUsersViewModel.StoreUserViewModel vm)
|
|
{
|
|
var roleId = await _storeRepo.ResolveStoreRoleId(storeId, vm.Role);
|
|
var storeUsers = await _storeRepo.GetStoreUsers(storeId);
|
|
var user = storeUsers.First(user => user.Id == userId);
|
|
var isOwner = user.StoreRole.Id == StoreRoleId.Owner.Id;
|
|
var isLastOwner = isOwner && storeUsers.Count(u => u.StoreRole.Id == StoreRoleId.Owner.Id) == 1;
|
|
if (isLastOwner && roleId != StoreRoleId.Owner)
|
|
TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["User {0} is the last owner. Their role cannot be changed.", user.Email].Value;
|
|
else if (await _storeRepo.AddOrUpdateStoreUser(storeId, userId, roleId))
|
|
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["The role of {0} has been changed to {1}.", user.Email, vm.Role].Value;
|
|
return RedirectToAction(nameof(StoreUsers), new { storeId, userId });
|
|
}
|
|
|
|
[HttpPost("{storeId}/users/{userId}/delete")]
|
|
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
|
public async Task<IActionResult> DeleteStoreUser(string storeId, string userId)
|
|
{
|
|
if (await _storeRepo.RemoveStoreUser(storeId, userId))
|
|
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["User removed successfully."].Value;
|
|
else
|
|
TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["Removing this user would result in the store having no owner."].Value;
|
|
return RedirectToAction(nameof(StoreUsers), new { storeId, userId });
|
|
}
|
|
|
|
private async Task FillUsers(StoreUsersViewModel vm)
|
|
{
|
|
var users = await _storeRepo.GetStoreUsers(CurrentStore.Id);
|
|
vm.StoreId = CurrentStore.Id;
|
|
vm.Users = users.Select(u => new StoreUsersViewModel.StoreUserViewModel
|
|
{
|
|
Email = u.Email,
|
|
Name = u.UserBlob.Name,
|
|
ImageUrl = u.UserBlob.ImageUrl,
|
|
Id = u.Id,
|
|
Role = u.StoreRole.Role
|
|
}).ToList();
|
|
}
|
|
}
|