Significant updates to WalkService.cs for improved fee handling and voucher processing. Introduced API version 3 in ApiAccountController.cs with new user registration and external login endpoints, supporting Google and Apple. Added functionality for setting user types without creating MangoPay users.
3002 lines
152 KiB
C#
3002 lines
152 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Threading.Tasks;
|
|
using AutoMapper;
|
|
using gehGassi.Core.Interfaces;
|
|
using gehGassi.Core.Services;
|
|
using gehGassi.Domain.Common;
|
|
using gehGassi.Domain.Users;
|
|
using gehGassi.Dto;
|
|
using gehGassi.Dto.Common;
|
|
using gehGassi.Permissions;
|
|
using gehGassi.Web.Auth;
|
|
using gehGassi.Web.Auth.Attributes;
|
|
using gehGassi.Web.Helper;
|
|
using gehGassi.Web.Services;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Localization;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using NetTopologySuite.Geometries;
|
|
using NetTopologySuite;
|
|
using SixLabors.ImageSharp;
|
|
using LocalizationOptions = gehGassi.Web.Helper.LocalizationOptions;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using SixLabors.ImageSharp.Advanced;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using gehGassi.Dto.DogWalkers;
|
|
using System.Net.Http.Headers;
|
|
using System.Text.Json;
|
|
using Microsoft.IdentityModel.Tokens;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Cryptography;
|
|
using System.Threading;
|
|
using Microsoft.Extensions.Caching.Distributed;
|
|
using gehGassi.Dto.Reporting;
|
|
using Asp.Versioning;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
|
|
namespace gehGassi.Web.Controllers.Api
|
|
{
|
|
/// <summary>
|
|
/// Controller für den API-Zugriff auf gehGassi Authentifizierung und Tokens
|
|
/// </summary>
|
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
|
[HasHeaderAuthorize(ClaimConstants.HasHeader, ClaimConstants.HasHeaderValue)]
|
|
[ApiController]
|
|
[ApiVersion(1)]
|
|
[ApiVersion(2)]
|
|
[ApiVersion(3)]
|
|
[Route("api/account")]
|
|
[Route("api/v{v:apiVersion}/account")]
|
|
public class ApiAccountController : ApiBaseController
|
|
{
|
|
private readonly ILogger<AccountController> _logger;
|
|
private readonly ITokenService _tokenService;
|
|
private readonly IRefreshTokenService _refreshTokenService;
|
|
private readonly IUserService _userService;
|
|
private readonly UserManager<ApplicationUser> _userManager;
|
|
private readonly IOptions<JwtTokenOptions> _jwtTokenOptions;
|
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
|
private readonly IEmailSender _emailSender;
|
|
private readonly IStringLocalizer<ApiAccountController> _localizer;
|
|
private readonly IOptions<LicenseOptions> _licenseOptions;
|
|
private readonly IOptions<AuthOptions> _authOptions;
|
|
private readonly IGeoLocationService _geoLocationService;
|
|
private readonly IMessageService _messageService;
|
|
private readonly IWebHostEnvironment _environment;
|
|
private readonly IDistributedCache _memoryCache;
|
|
private readonly IOptions<AppleOptions> _appleOptions;
|
|
private readonly IMangoPayService _mangoPayService;
|
|
private readonly IOptions<EmailSenderOptions> _emailSenderOptions;
|
|
private readonly IWalkService _walkService;
|
|
private readonly IPublicWalkRequestService _publicWalkRequestService;
|
|
private readonly IPublicWalkResponseService _publicWalkResponseService;
|
|
private readonly IAppUserReportService _appUserReportService;
|
|
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="mapper">Instanz eines IMapper</param>
|
|
/// <param name="localizationOptions">Instanz von LocalizationOptions</param>
|
|
/// <param name="logger">Instanz eines ILogger</param>
|
|
/// <param name="tokenService">Instanz eines ITokenService</param>
|
|
/// <param name="refreshTokenService">Instanz eines IRefreshTokenService</param>
|
|
/// <param name="userService">Instanz eines IUserService</param>
|
|
/// <param name="userManager">Instanz eines UserManager</param>
|
|
/// <param name="jwtTokenOptions">Instanz eines IOptions JwtTokenOptions</param>
|
|
/// <param name="signInManager">Instanz eines SignInManager</param>
|
|
/// <param name="emailSender">Instanz eines IEmailSender</param>
|
|
/// <param name="localizer">Instanz eines IStringLocalizer</param>
|
|
/// <param name="licenseOptions">Instanz von LicenseOptions</param>
|
|
/// <param name="appUserService">Instanz eines IAppUserService</param>
|
|
/// <param name="authOptions">Instanz von AuthOptions</param>
|
|
/// <param name="geoLocationService">Instanz eines IGeoLocationService</param>
|
|
/// <param name="messageService">Instanz eines IMessageService</param>
|
|
/// <param name="environment">Instanz eines IWebHostEnvironment</param>
|
|
/// <param name="memoryCache">Instanz eines IDistributedCache</param>
|
|
/// <param name="appleOptions">Instanz von AppleOptions</param>
|
|
/// <param name="mangoPayService">Instanz eines IMangoPayService</param>
|
|
/// <param name="emailSenderOptions">Instanz eines EmailSenderOptions</param>
|
|
/// <param name="walkService">Instanz eines IWalkService</param>
|
|
/// <param name="publicWalkRequestService">Instanz eines IPublicWalkRequestService</param>
|
|
/// <param name="publicWalkResponseService">Instanz eines IPublicWalkResponseService</param>
|
|
/// <param name="appUserReportService">Instanz eines IAppUserReportService</param>
|
|
public ApiAccountController(IMapper mapper, IOptions<LocalizationOptions> localizationOptions, ILogger<AccountController> logger, ITokenService tokenService, IRefreshTokenService refreshTokenService, IUserService userService,
|
|
UserManager<ApplicationUser> userManager, IOptions<JwtTokenOptions> jwtTokenOptions, SignInManager<ApplicationUser> signInManager,
|
|
IEmailSender emailSender, IStringLocalizer<ApiAccountController> localizer, IOptions<LicenseOptions> licenseOptions, IAppUserService appUserService,
|
|
IOptions<AuthOptions> authOptions, IGeoLocationService geoLocationService, IMessageService messageService, IWebHostEnvironment environment, IDistributedCache memoryCache,
|
|
IOptions<AppleOptions> appleOptions, IMangoPayService mangoPayService, IOptions<EmailSenderOptions> emailSenderOptions, IWalkService walkService,
|
|
IPublicWalkRequestService publicWalkRequestService, IPublicWalkResponseService publicWalkResponseService, IAppUserReportService appUserReportService) : base(mapper, localizationOptions, appUserService)
|
|
{
|
|
_logger = logger;
|
|
_tokenService = tokenService;
|
|
_refreshTokenService = refreshTokenService;
|
|
_userService = userService;
|
|
_userManager = userManager;
|
|
_jwtTokenOptions = jwtTokenOptions;
|
|
_signInManager = signInManager;
|
|
_emailSender = emailSender;
|
|
_localizer = localizer;
|
|
_licenseOptions = licenseOptions;
|
|
_authOptions = authOptions;
|
|
_geoLocationService = geoLocationService;
|
|
_messageService = messageService;
|
|
_environment = environment;
|
|
_memoryCache = memoryCache;
|
|
_appleOptions = appleOptions;
|
|
_mangoPayService = mangoPayService;
|
|
_emailSenderOptions = emailSenderOptions;
|
|
_walkService = walkService;
|
|
_publicWalkRequestService = publicWalkRequestService;
|
|
_publicWalkResponseService = publicWalkResponseService;
|
|
_appUserReportService = appUserReportService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prüfen ob eine E-Mail Adresse noch verfügbar ist
|
|
/// </summary>
|
|
/// <param name="model">Model mit Benutzername & Passwort</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("IsAvailable")]
|
|
public async Task<IActionResult> IsAvailable(LoginDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
//Der Benutzername ist noch frei.
|
|
//Prüfen ob das Passwort ausreicht
|
|
var helpUser = new ApplicationUser();
|
|
foreach (var passwordValidator in _userManager.PasswordValidators)
|
|
{
|
|
var result = await passwordValidator.ValidateAsync(_userManager, helpUser, model.Password);
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
if (result.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prüfen ob ein Passwort gültig ist
|
|
/// </summary>
|
|
/// <param name="model">Model mit Passwort</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("CheckPassword")]
|
|
public async Task<IActionResult> CheckPassword(CheckPasswordDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var helpUser = new ApplicationUser();
|
|
foreach (var passwordValidator in _userManager.PasswordValidators)
|
|
{
|
|
var result = await passwordValidator.ValidateAsync(_userManager, helpUser, model.Password);
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
if (result.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("Register")]
|
|
public async Task<IActionResult> Register(RegisterDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = !_authOptions.Value.MustConfirmEmail;
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
var createResult = await _userManager.CreateAsync(user, model.Password);
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userService.GetAsync(user.Id);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = true;
|
|
appUser.PaymentTermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userService.CommitAsync("System");
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
}
|
|
|
|
if (_authOptions.Value.MustConfirmEmail)
|
|
{
|
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
|
var callbackUrl = Url.Action("ConfirmEmailApp", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
|
await _emailSender.SendEmailConfirmationAsync(user.UserName, callbackUrl, _localizer, _licenseOptions);
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[MapToApiVersion(2)]
|
|
[Route("Register")]
|
|
public async Task<IActionResult> RegisterV2(RegisterV2Dto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = !_authOptions.Value.MustConfirmEmail;
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
var createResult = await _userManager.CreateAsync(user, model.Password);
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userService.GetAsync(user.Id);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.City = model.City;
|
|
appUser.Address.Zip = model.Zip;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = true;
|
|
appUser.PaymentTermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.Zip},{model.City},{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userService.CommitAsync("System");
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
}
|
|
|
|
if (_authOptions.Value.MustConfirmEmail)
|
|
{
|
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
|
var callbackUrl = Url.Action("ConfirmEmailApp", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
|
await _emailSender.SendEmailConfirmationAsync(user.UserName, callbackUrl, _localizer, _licenseOptions);
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[MapToApiVersion(3)]
|
|
[Route("Register")]
|
|
public async Task<IActionResult> RegisterV3(RegisterV2Dto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = !_authOptions.Value.MustConfirmEmail;
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
var createResult = await _userManager.CreateAsync(user, model.Password);
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userService.GetAsync(user.Id);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.City = model.City;
|
|
appUser.Address.Zip = model.Zip;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.Zip},{model.City},{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userService.CommitAsync("System");
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
//var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
//if (mangoPayResult.Success)
|
|
//{
|
|
// //Wallets anlegen
|
|
// var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
// var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
//}
|
|
}
|
|
|
|
if (_authOptions.Value.MustConfirmEmail)
|
|
{
|
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
|
var callbackUrl = Url.Action("ConfirmEmailApp", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
|
await _emailSender.SendEmailConfirmationAsync(user.UserName, callbackUrl, _localizer, _licenseOptions);
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users mittels external Provider
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("RegisterExternal")]
|
|
public async Task<IActionResult> RegisterExternal(RegisterExternalDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//Zuerst holen wir nochmal die Infos für den User. Token prüfen... //TODO: Je nach Provider vorgehen. Derzeit nur google. Apple einführen...
|
|
var tokenValid = false;
|
|
ExternalLoginGoogleResponse userInfo = null;
|
|
AppleResponseDto appleResponse = null;
|
|
|
|
if (model.LoginProvider == "Google")
|
|
{
|
|
HttpStatusCode tokenResponseCode = HttpStatusCode.OK;
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", model.AccessToken);
|
|
var tokenResult = await httpClient.GetAsync($"https://www.googleapis.com/oauth2/v3/userinfo");
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
string jsonString = tokenResult.Content.ReadAsStringAsync().Result;
|
|
userInfo = JsonSerializer.Deserialize<ExternalLoginGoogleResponse>(jsonString);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
tokenResponseCode = tokenResult.StatusCode;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple")
|
|
{
|
|
var clientSecret = await GenerateAppleClientSecretAsync();
|
|
var parameters = new List<KeyValuePair<string, string>>
|
|
{
|
|
new KeyValuePair<string, string>("client_id", _appleOptions.Value.ClientId),
|
|
new KeyValuePair<string, string>("client_secret", clientSecret),
|
|
new KeyValuePair<string, string>("refresh_token", model.AccessToken),
|
|
new KeyValuePair<string, string>("grant_type", "refresh_token")
|
|
};
|
|
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
var tokenResult = await httpClient.PostAsync($"https://appleid.apple.com/auth/token", new FormUrlEncodedContent(parameters));
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
var successResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
appleResponse = JsonSerializer.Deserialize<AppleResponseDto>(successResponse);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
var errorResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
_logger.LogError(errorResponse);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
|
|
if (tokenValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = true; //Weil über externen Provider
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
IdentityResult createResult;
|
|
if (!string.IsNullOrEmpty(model.Password))
|
|
createResult = await _userManager.CreateAsync(user, model.Password);
|
|
else
|
|
createResult = await _userManager.CreateAsync(user);
|
|
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userManager.FindByEmailAsync(user.UserName);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = true;
|
|
appUser.PaymentTermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
}
|
|
|
|
//Da wir den User gleich einloggen möchten, geben wir alles nötige zurück
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (model.LoginProvider == "Google" && userInfo != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Google", userInfo.Sub, user.FullName));
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple" && appleResponse != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
var appleToken = new JwtSecurityToken(appleResponse.IdToken);
|
|
if (appleToken != null)
|
|
{
|
|
var appleUserId = appleToken.Claims.First(c => c.Type == "sub").Value;
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Apple", appleUserId, user.FullName));
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_TokenInvalid);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users mittels external Provider
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[MapToApiVersion(2)]
|
|
[Route("RegisterExternal")]
|
|
public async Task<IActionResult> RegisterExternalV2(RegisterExternalV2Dto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//Zuerst holen wir nochmal die Infos für den User. Token prüfen... //TODO: Je nach Provider vorgehen. Derzeit nur google. Apple einführen...
|
|
var tokenValid = false;
|
|
ExternalLoginGoogleResponse userInfo = null;
|
|
AppleResponseDto appleResponse = null;
|
|
|
|
if (model.LoginProvider == "Google")
|
|
{
|
|
HttpStatusCode tokenResponseCode = HttpStatusCode.OK;
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", model.AccessToken);
|
|
var tokenResult = await httpClient.GetAsync($"https://www.googleapis.com/oauth2/v3/userinfo");
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
string jsonString = tokenResult.Content.ReadAsStringAsync().Result;
|
|
userInfo = JsonSerializer.Deserialize<ExternalLoginGoogleResponse>(jsonString);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
tokenResponseCode = tokenResult.StatusCode;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple")
|
|
{
|
|
var clientSecret = await GenerateAppleClientSecretAsync();
|
|
var parameters = new List<KeyValuePair<string, string>>
|
|
{
|
|
new KeyValuePair<string, string>("client_id", _appleOptions.Value.ClientId),
|
|
new KeyValuePair<string, string>("client_secret", clientSecret),
|
|
new KeyValuePair<string, string>("refresh_token", model.AccessToken),
|
|
new KeyValuePair<string, string>("grant_type", "refresh_token")
|
|
};
|
|
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
var tokenResult = await httpClient.PostAsync($"https://appleid.apple.com/auth/token", new FormUrlEncodedContent(parameters));
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
var successResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
appleResponse = JsonSerializer.Deserialize<AppleResponseDto>(successResponse);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
var errorResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
_logger.LogError(errorResponse);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
|
|
if (tokenValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = true; //Weil über externen Provider
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
IdentityResult createResult;
|
|
if (!string.IsNullOrEmpty(model.Password))
|
|
createResult = await _userManager.CreateAsync(user, model.Password);
|
|
else
|
|
createResult = await _userManager.CreateAsync(user);
|
|
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userManager.FindByEmailAsync(user.UserName);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.City = model.City;
|
|
appUser.Address.Zip = model.Zip;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = true;
|
|
appUser.PaymentTermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.Zip},{model.City},{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
}
|
|
|
|
//Da wir den User gleich einloggen möchten, geben wir alles nötige zurück
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (model.LoginProvider == "Google" && userInfo != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Google", userInfo.Sub, user.FullName));
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple" && appleResponse != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
var appleToken = new JwtSecurityToken(appleResponse.IdToken);
|
|
if (appleToken != null)
|
|
{
|
|
var appleUserId = appleToken.Claims.First(c => c.Type == "sub").Value;
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Apple", appleUserId, user.FullName));
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_TokenInvalid);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registrieren eines App-Users mittels external Provider
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>HTTP 200 OK wenn erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[MapToApiVersion(3)]
|
|
[Route("RegisterExternal")]
|
|
public async Task<IActionResult> RegisterExternalV3(RegisterExternalV2Dto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//Zuerst holen wir nochmal die Infos für den User. Token prüfen... //TODO: Je nach Provider vorgehen. Derzeit nur google. Apple einführen...
|
|
var tokenValid = false;
|
|
ExternalLoginGoogleResponse userInfo = null;
|
|
AppleResponseDto appleResponse = null;
|
|
|
|
if (model.LoginProvider == "Google")
|
|
{
|
|
HttpStatusCode tokenResponseCode = HttpStatusCode.OK;
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", model.AccessToken);
|
|
var tokenResult = await httpClient.GetAsync($"https://www.googleapis.com/oauth2/v3/userinfo");
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
string jsonString = tokenResult.Content.ReadAsStringAsync().Result;
|
|
userInfo = JsonSerializer.Deserialize<ExternalLoginGoogleResponse>(jsonString);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
tokenResponseCode = tokenResult.StatusCode;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple")
|
|
{
|
|
var clientSecret = await GenerateAppleClientSecretAsync();
|
|
var parameters = new List<KeyValuePair<string, string>>
|
|
{
|
|
new KeyValuePair<string, string>("client_id", _appleOptions.Value.ClientId),
|
|
new KeyValuePair<string, string>("client_secret", clientSecret),
|
|
new KeyValuePair<string, string>("refresh_token", model.AccessToken),
|
|
new KeyValuePair<string, string>("grant_type", "refresh_token")
|
|
};
|
|
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
var tokenResult = await httpClient.PostAsync($"https://appleid.apple.com/auth/token", new FormUrlEncodedContent(parameters));
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
var successResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
appleResponse = JsonSerializer.Deserialize<AppleResponseDto>(successResponse);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
var errorResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
_logger.LogError(errorResponse);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
}
|
|
|
|
if (tokenValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(model.UserName);
|
|
if (user == null)
|
|
{
|
|
user = _userService.Create();
|
|
user.Id = Guid.NewGuid().ToString();
|
|
user.UserName = model.UserName;
|
|
user.FirstName = model.FirstName;
|
|
user.LastName = model.LastName;
|
|
user.FullName = $"{model.FirstName} {model.LastName}";
|
|
user.RegistrationDate = DateTimeOffset.UtcNow;
|
|
user.Photo = string.Empty;
|
|
user.Email = model.UserName;
|
|
user.EmailConfirmed = true; //Weil über externen Provider
|
|
user.Permissions = PermissionHelper.GetForRole("AppUser").PackPermissionsIntoString();
|
|
|
|
IdentityResult createResult;
|
|
if (!string.IsNullOrEmpty(model.Password))
|
|
createResult = await _userManager.CreateAsync(user, model.Password);
|
|
else
|
|
createResult = await _userManager.CreateAsync(user);
|
|
|
|
if (createResult.Succeeded)
|
|
{
|
|
await _userManager.AddToRoleAsync(user, "AppUser");
|
|
user = await _userManager.FindByEmailAsync(user.UserName);
|
|
|
|
//Nun den AppUser anlegen und dann mit dem Benutzer verknüpfen
|
|
var appUser = AppUserService.Create();
|
|
appUser.Type = (AppUserType)model.AppUserType;
|
|
appUser.Number = AppUserService.GetNextNumber();
|
|
appUser.FirstName = model.FirstName;
|
|
appUser.LastName = model.LastName;
|
|
appUser.Sex = Sex.Undefined;
|
|
appUser.BirthDate = model.BirthDate;
|
|
appUser.Photo = string.Empty;
|
|
appUser.Contact.Email = model.UserName;
|
|
appUser.Address.City = model.City;
|
|
appUser.Address.Zip = model.Zip;
|
|
appUser.Address.CountryCode = model.CountryCode;
|
|
appUser.Address.State = model.State;
|
|
appUser.TermsAccepted = true;
|
|
appUser.TermsAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.PrivacyAccepted = true;
|
|
appUser.PrivacyAcceptedDate = DateTimeOffset.UtcNow;
|
|
appUser.Verified = false;
|
|
appUser.VerifiedDate = null;
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = string.Empty;
|
|
appUser.MainResidenceCode = string.Empty;
|
|
|
|
if (appUser.Type == AppUserType.DogWalker)
|
|
{
|
|
appUser.PaymentTermsAccepted = false;
|
|
appUser.PaymentTermsAcceptedDate = null;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCountryCode;
|
|
}
|
|
|
|
var location = await _geoLocationService.GetLocationAsync($"{model.Zip},{model.City},{model.CountryCode},{model.State}", CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
|
|
AppUserService.Add(appUser);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
user.AppUserId = appUser.Id;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync("System");
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
//var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
//if (mangoPayResult.Success)
|
|
//{
|
|
// //Wallets anlegen
|
|
// var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
// var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
//}
|
|
}
|
|
|
|
//Da wir den User gleich einloggen möchten, geben wir alles nötige zurück
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
|
|
if (model.LoginProvider == "Google" && userInfo != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Google", userInfo.Sub, user.FullName));
|
|
}
|
|
}
|
|
else if (model.LoginProvider == "Apple" && appleResponse != null)
|
|
{
|
|
var createdUser = await _userManager.FindByEmailAsync(user.UserName);
|
|
if (createdUser != null)
|
|
{
|
|
var appleToken = new JwtSecurityToken(appleResponse.IdToken);
|
|
if (appleToken != null)
|
|
{
|
|
var appleUserId = appleToken.Claims.First(c => c.Type == "sub").Value;
|
|
await _userManager.AddLoginAsync(createdUser, new UserLoginInfo("Apple", appleUserId, user.FullName));
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (createResult.Errors.FirstOrDefault(c => c.Code.StartsWith("Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Failed);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_Email_Exists);
|
|
}
|
|
return BadRequest(CommunicationErrors.Register_TokenInvalid);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Anmelden via API. Erstellt ein Access-Token und ein Refresh-Token wenn erfolgreich
|
|
/// </summary>
|
|
/// <param name="model">Model mit Benutzername & Passwort</param>
|
|
/// <returns>Token und Refreshtoken oder BadRequest wenn nicht erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("Login")]
|
|
public async Task<IActionResult> Login(LoginDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userManager.FindByNameAsync(model.UserName);// _userService.GetByUsernameAsync(model.UserName);
|
|
|
|
if (user != null)
|
|
{
|
|
if (await _userManager.CheckPasswordAsync(user, model.Password))
|
|
{
|
|
if (await _userManager.IsLockedOutAsync(user) == false)
|
|
{
|
|
if (await _userManager.IsEmailConfirmedAsync(user))
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
|
|
if (appUser != null)
|
|
{
|
|
if (appUser.Locked && appUser.LockedUntil < DateTimeOffset.UtcNow)
|
|
{
|
|
appUser.Locked = false;
|
|
appUser.LockedUntil = null;
|
|
await AppUserService.CommitAsync("System");
|
|
}
|
|
|
|
if (!appUser.Locked)
|
|
{
|
|
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
if (!string.IsNullOrWhiteSpace(user.Photo))
|
|
{
|
|
var photo = await FileService.GetAsync(FileServiceHelper.DocumentContainer, user.Photo);
|
|
//if (photo != null)
|
|
// userDto.PhotoBase64 = Convert.ToBase64String(photo);
|
|
}
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
//await _userService.CommitAsync(user.UserName);
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(CommunicationErrors.Login_Assignment_Missing);
|
|
}
|
|
}
|
|
|
|
return BadRequest(CommunicationErrors.Login_Email_NotConfirmed);
|
|
}
|
|
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
}
|
|
|
|
return Unauthorized(CommunicationErrors.Login_Invalid_Credentials);
|
|
}
|
|
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Anmelden mit external Provider von der App.
|
|
/// Die App hat erfolgreich ein AccessToken erhalten, daher wissen wir wer der Benutzer ist.
|
|
/// Nun einen Login durchführen ohne Prüfung des Passwortes
|
|
/// </summary>
|
|
/// <returns>Token und Refreshtoken oder BadRequest wenn nicht erfolgreich</returns>
|
|
[HttpGet]
|
|
[Route("LoginExternal")]
|
|
public async Task<IActionResult> LoginExternal()
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userManager.FindByNameAsync(User.Identity.Name);
|
|
|
|
if (user != null)
|
|
{
|
|
if (await _userManager.IsLockedOutAsync(user) == false)
|
|
{
|
|
if (await _userManager.IsEmailConfirmedAsync(user))
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
|
|
if (appUser != null)
|
|
{
|
|
if (appUser.Locked && appUser.LockedUntil < DateTimeOffset.UtcNow)
|
|
{
|
|
appUser.Locked = false;
|
|
appUser.LockedUntil = null;
|
|
await AppUserService.CommitAsync("System");
|
|
}
|
|
|
|
if (!appUser.Locked)
|
|
{
|
|
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
if (!string.IsNullOrWhiteSpace(user.Photo))
|
|
{
|
|
var photo = await FileService.GetAsync(FileServiceHelper.DocumentContainer, user.Photo);
|
|
//if (photo != null)
|
|
// userDto.PhotoBase64 = Convert.ToBase64String(photo);
|
|
}
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
//await _userService.CommitAsync(user.UserName);
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(CommunicationErrors.Login_Assignment_Missing);
|
|
}
|
|
}
|
|
|
|
return BadRequest(CommunicationErrors.Login_Email_NotConfirmed);
|
|
}
|
|
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
}
|
|
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Anmelden mit Apple
|
|
/// </summary>
|
|
/// <param name="model">Model mit notwendigen Daten von Apple</param>
|
|
/// <returns>Token und Refreshtoken oder BadRequest wenn nicht erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("LoginApple")]
|
|
public async Task<IActionResult> LoginApple(LoginAppleDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
//Daten gegen Apple validieren...
|
|
var tokenValid = false;
|
|
var emailToUse = model.Email;
|
|
AppleResponseDto tokenResponse = null;
|
|
|
|
var clientSecret = await GenerateAppleClientSecretAsync();
|
|
var parameters = new List<KeyValuePair<string, string>>
|
|
{
|
|
new KeyValuePair<string, string>("client_id", _appleOptions.Value.ClientId),
|
|
new KeyValuePair<string, string>("client_secret", clientSecret),
|
|
new KeyValuePair<string, string>("code", model.AuthCode),
|
|
new KeyValuePair<string, string>("grant_type", "authorization_code")
|
|
};
|
|
|
|
var httpClient = new HttpClient();
|
|
try
|
|
{
|
|
var tokenResult = await httpClient.PostAsync($"https://appleid.apple.com/auth/token", new FormUrlEncodedContent(parameters));
|
|
if (tokenResult.IsSuccessStatusCode)
|
|
{
|
|
var successResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
tokenResponse = JsonSerializer.Deserialize<AppleResponseDto>(successResponse);
|
|
tokenValid = true;
|
|
}
|
|
else
|
|
{
|
|
var errorResponse = await tokenResult.Content.ReadAsStringAsync();
|
|
_logger.LogError(errorResponse);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tokenValid = false;
|
|
}
|
|
|
|
if (tokenValid)
|
|
{
|
|
var user = await _userManager.FindByLoginAsync("Apple", model.UserId);
|
|
if (user == null && !string.IsNullOrWhiteSpace(emailToUse))
|
|
{
|
|
user = await _userManager.FindByEmailAsync(emailToUse);
|
|
}
|
|
|
|
if (user != null)
|
|
{
|
|
if (await _userManager.IsLockedOutAsync(user) == false)
|
|
{
|
|
if (await _userManager.IsEmailConfirmedAsync(user))
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
|
|
if (appUser != null)
|
|
{
|
|
if (appUser.Locked && appUser.LockedUntil < DateTimeOffset.UtcNow)
|
|
{
|
|
appUser.Locked = false;
|
|
appUser.LockedUntil = null;
|
|
await AppUserService.CommitAsync("System");
|
|
}
|
|
|
|
if (!appUser.Locked)
|
|
{
|
|
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
var refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var userDto = Mapper.Map<UserDto>(user);
|
|
userDto.AccessToken = token;
|
|
userDto.AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes);
|
|
userDto.RefreshToken = refreshToken.Token;
|
|
userDto.RefreshTokenExpires = refreshToken.Expires;
|
|
userDto.AppUserType = (AppUserTypeDto)appUser.Type;
|
|
|
|
var roleList = roles.ToList();
|
|
userDto.Roles = string.Join(";", roleList);
|
|
|
|
if (!string.IsNullOrWhiteSpace(user.Photo))
|
|
{
|
|
var photo = await FileService.GetAsync(FileServiceHelper.DocumentContainer, user.Photo);
|
|
//if (photo != null)
|
|
// userDto.PhotoBase64 = Convert.ToBase64String(photo);
|
|
}
|
|
|
|
user.LastLoginDate = DateTimeOffset.UtcNow;
|
|
await _userManager.UpdateAsync(user);
|
|
//await _userService.CommitAsync(user.UserName);
|
|
|
|
var externalLogins = await _userManager.GetLoginsAsync(user);
|
|
if (externalLogins?.FirstOrDefault(c => c.LoginProvider == "Apple") == null)
|
|
{
|
|
await _userManager.AddLoginAsync(user, new UserLoginInfo("Apple", model.UserId, user.FullName));
|
|
}
|
|
|
|
return Ok(userDto);
|
|
}
|
|
else
|
|
{
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(CommunicationErrors.Login_Assignment_Missing);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(CommunicationErrors.Login_Assignment_Missing);
|
|
}
|
|
}
|
|
|
|
return BadRequest(CommunicationErrors.Login_Email_NotConfirmed);
|
|
}
|
|
|
|
return Unauthorized(CommunicationErrors.Login_LockedOut);
|
|
|
|
}
|
|
return NotFound(JsonSerializer.Serialize(tokenResponse)); //Wir müssen hier tricksen, damit das Refreshtoken zur App übertragen wird
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Abmelden eines Benutzers
|
|
/// </summary>
|
|
/// <returns>HTTP 200 wenn erfolgreich</returns>
|
|
[HttpGet]
|
|
[Route("Logout")]
|
|
public async Task<IActionResult> Logout()
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
//Löschen aller Refresh-tokens des Benutzers da eine Abmeldung erfolgt ist
|
|
await _refreshTokenService.RemoveAllAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
return Ok();
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Zurücksetzen des Passworts für einen App-Benutzer
|
|
/// </summary>
|
|
/// <param name="email">Benutzername / E-Mail Adresse des Benutzers</param>
|
|
/// <returns>HTTP 200 - immer!</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("ResetPassword")]
|
|
public async Task<IActionResult> ResetPassword([FromBody] string email)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
try
|
|
{
|
|
var user = await _signInManager.UserManager.FindByNameAsync(email);
|
|
if (user != null && (await _signInManager.UserManager.IsEmailConfirmedAsync(user)))
|
|
{
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
if (roles.Contains("AppUser"))
|
|
{
|
|
var token = await _signInManager.UserManager.GeneratePasswordResetTokenAsync(user);
|
|
var callbackUrl = Url.ResetPasswordCallbackLinkApp(user.Id, token, Request.Scheme);
|
|
await _emailSender.SendPasswordResetAppAsync(email, callbackUrl, _localizer, _licenseOptions);
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
return Ok();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Senden der E-Mail Bestätigung für einen App-Benutzer
|
|
/// </summary>
|
|
/// <param name="email">Benutzername / E-Mail Adresse des Benutzers</param>
|
|
/// <returns>HTTP 200 - immer!</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("SendConfirmation")]
|
|
public async Task<IActionResult> SendConfirmation([FromBody] string email)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
try
|
|
{
|
|
var user = await _signInManager.UserManager.FindByNameAsync(email);
|
|
if (user != null && (await _signInManager.UserManager.IsEmailConfirmedAsync(user)) == false)
|
|
{
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
if (roles.Contains("AppUser"))
|
|
{
|
|
var code = await _signInManager.UserManager.GenerateEmailConfirmationTokenAsync(user);
|
|
var callbackUrl = Url.Action("ConfirmEmailApp", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
|
|
await _emailSender.SendEmailConfirmationAppAsync(email, callbackUrl, _localizer, _licenseOptions);
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
return Ok();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Mit einem abgelaufenen Token und einem RefreshToken ein neues AccessToken holen
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>Token und Refreshtoken oder BadRequest wenn nicht erfolgreich</returns>
|
|
[AllowAnonymous]
|
|
[HttpPost]
|
|
[Route("Refresh")]
|
|
public async Task<IActionResult> Refresh(RefreshTokenDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (ModelState.IsValid)
|
|
{
|
|
var principal = _tokenService.GetPrincipalFromExpiredToken(model.AccessToken);
|
|
if (principal != null)
|
|
{
|
|
var username = principal.Identity.Name; //this is mapped to the Name claim by default
|
|
|
|
var user = await _userService.GetByUsernameAsync(username);
|
|
if (user != null)
|
|
{
|
|
//Wenn der Benutzer gesperrt ist, dann alle RefreshTokens löschen und Fehler zurückgeben
|
|
if (user.LockoutEnd.HasValue && user.LockoutEnd > DateTimeOffset.UtcNow)
|
|
{
|
|
await _refreshTokenService.RemoveAllAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
return BadRequest(CommunicationErrors.RefreshToken_Expired);
|
|
}
|
|
|
|
var existingRefreshToken = await _refreshTokenService.GetAsync(user.Id, model.RefreshToken);
|
|
if (existingRefreshToken != null)
|
|
{
|
|
if (existingRefreshToken.Expires > DateTimeOffset.UtcNow)
|
|
{
|
|
var token = _tokenService.GenerateAccessToken(principal.Claims);
|
|
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
RefreshToken refreshToken = null;
|
|
if (existingRefreshToken.Expires >= DateTimeOffset.UtcNow.AddDays(1))
|
|
{
|
|
refreshToken = existingRefreshToken;
|
|
}
|
|
else
|
|
{
|
|
refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
_refreshTokenService.Remove(existingRefreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
}
|
|
|
|
var dto = new RefreshTokenResponseDto()
|
|
{
|
|
AccessToken = token,
|
|
AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes),
|
|
RefreshToken = refreshToken.Token,
|
|
RefreshTokenExpires = refreshToken.Expires
|
|
};
|
|
|
|
return Ok(dto);
|
|
}
|
|
return BadRequest(CommunicationErrors.RefreshToken_Expired);
|
|
}
|
|
return BadRequest(CommunicationErrors.RefreshToken_NotFound);
|
|
}
|
|
}
|
|
//Principal oder user null, nun anhand des Tokens alleine versuchen
|
|
if (!string.IsNullOrWhiteSpace(model.AccessToken))
|
|
{
|
|
var existingRefreshToken = await _refreshTokenService.GetAsync(model.RefreshToken);
|
|
if (existingRefreshToken != null)
|
|
{
|
|
if (existingRefreshToken.Expires > DateTimeOffset.UtcNow)
|
|
{
|
|
var user = await _userService.GetAsync(existingRefreshToken.UserId);
|
|
if (user != null)
|
|
{
|
|
//Wenn der Benutzer gesperrt ist, dann alle RefreshTokens löschen und Fehler zurückgeben
|
|
if (user.LockoutEnd.HasValue && user.LockoutEnd > DateTimeOffset.UtcNow)
|
|
{
|
|
await _refreshTokenService.RemoveAllAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
return BadRequest(CommunicationErrors.RefreshToken_Expired);
|
|
}
|
|
|
|
var usersClaims = new List<Claim>()
|
|
{
|
|
new Claim(ClaimTypes.Name, user.UserName),
|
|
new Claim(ClaimTypes.GivenName, user.FirstName),
|
|
new Claim(ClaimTypes.Surname, user.LastName),
|
|
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
|
new Claim(ClaimTypes.UserData, user.Photo ?? ""),
|
|
new Claim(ClaimConstants.AppUserIdClaimType, user.AppUserId ?? ""),
|
|
};
|
|
|
|
var roles = await _userManager.GetRolesAsync(user);
|
|
foreach (var role in roles)
|
|
{
|
|
usersClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
}
|
|
|
|
var token = _tokenService.GenerateAccessToken(usersClaims);
|
|
|
|
await _refreshTokenService.RemoveExpiredAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
RefreshToken refreshToken = null;
|
|
if (existingRefreshToken.Expires >= DateTimeOffset.UtcNow.AddDays(1))
|
|
{
|
|
refreshToken = existingRefreshToken;
|
|
}
|
|
else
|
|
{
|
|
refreshToken = _refreshTokenService.Create();
|
|
refreshToken.UserId = user.Id;
|
|
_refreshTokenService.Add(refreshToken);
|
|
_refreshTokenService.Remove(existingRefreshToken);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
}
|
|
|
|
var dto = new RefreshTokenResponseDto()
|
|
{
|
|
AccessToken = token,
|
|
AccessTokenExpires = DateTimeOffset.UtcNow.AddMinutes(_jwtTokenOptions.Value.TokenMinutes),
|
|
RefreshToken = refreshToken.Token,
|
|
RefreshTokenExpires = refreshToken.Expires
|
|
};
|
|
|
|
return Ok(dto);
|
|
}
|
|
return NotFound(CommunicationErrors.RefreshToken_UserNotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.RefreshToken_Expired);
|
|
}
|
|
return BadRequest(CommunicationErrors.RefreshToken_NotFound);
|
|
}
|
|
return NotFound(CommunicationErrors.AccessToken_Empty);
|
|
}
|
|
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prüfen ob der angemeldete Benutzer ein Passwort hat oder nicht.
|
|
/// Das kann bei externen Providern vorkommen
|
|
/// </summary>
|
|
/// <returns>HTTP 200 OK</returns>
|
|
[HttpGet]
|
|
[Route("HasPassword")]
|
|
public async Task<IActionResult> HasPassword()
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
|
return Ok(hasPassword);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hinzufügen eines PAsswortes zu einem Benutzer wenn dieser keines har
|
|
/// </summary>
|
|
/// <param name="model">Model mit Passwort</param>
|
|
/// <returns>HTTP 200 OK</returns>
|
|
[HttpPost]
|
|
[Route("AddPassword")]
|
|
public async Task<IActionResult> AddPassword(AddPasswordDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
|
if (user != null && user.UserName.ToLower() == model.UserName.ToLower())
|
|
{
|
|
var hasPassword = await _userManager.HasPasswordAsync(user);
|
|
if (!hasPassword)
|
|
{
|
|
var addPasswordResult = await _userManager.AddPasswordAsync(user, model.Password);
|
|
if (addPasswordResult.Succeeded)
|
|
{
|
|
return Ok(true);
|
|
}
|
|
else
|
|
{
|
|
if (addPasswordResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (addPasswordResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
}
|
|
return Ok(false);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ändern des Passwortes eines Benutzers
|
|
/// </summary>
|
|
/// <param name="model">Model mit Passwort</param>
|
|
/// <returns>HTTP 200 OK</returns>
|
|
[HttpPost]
|
|
[Route("ChangePassword")]
|
|
public async Task<IActionResult> ChangePassword(ChangePasswordDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userManager.FindByEmailAsync(User.Identity.Name);
|
|
if (user != null && user.UserName.ToLower() == model.UserName.ToLower())
|
|
{
|
|
var changeResult = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.Password);
|
|
if (changeResult.Succeeded)
|
|
{
|
|
return Ok(true);
|
|
}
|
|
else
|
|
{
|
|
if (changeResult.Errors.FirstOrDefault(c => c.Code == "PwnedPassword") != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Pwned);
|
|
}
|
|
if (changeResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_PasswordMismatch")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Mismatch);
|
|
}
|
|
if (changeResult.Errors.FirstOrDefault(c => c.Code.StartsWith("IdentityError_Password")) != null)
|
|
{
|
|
return BadRequest(CommunicationErrors.Register_Password_Rules);
|
|
}
|
|
}
|
|
return Ok(false);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Löschen eines Accounts, Sperren des Benutzers und Ausloggen
|
|
/// </summary>
|
|
/// <returns>HTTP 200 wenn erfolgreich</returns>
|
|
[HttpPost]
|
|
[Route("DeleteAccount")]
|
|
public async Task<IActionResult> DeleteAccount(DeleteAccountDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (user.Id == model.UserId && user.Email == model.UserName)
|
|
{
|
|
|
|
//Sperren des Benutzers
|
|
user.LockoutEnd = DateTimeOffset.UtcNow.AddYears(5);
|
|
await _userService.CommitAsync(user.UserName);
|
|
|
|
//Löschen aller Refresh-tokens des Benutzers da eine Abmeldung erfolgt ist
|
|
await _refreshTokenService.RemoveAllAsync(user.Id, user.UserName);
|
|
await _refreshTokenService.CommitAsync(user.UserName);
|
|
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
if (appUser != null)
|
|
{
|
|
appUser.Locked = true;
|
|
appUser.LockedReason = "Delete account requested";
|
|
appUser.LockedUntil = DateTimeOffset.UtcNow.AddYears(5);
|
|
await AppUserService.CommitAsync(user.UserName);
|
|
}
|
|
|
|
//Nun Email an gehgassi senden, dass der Benutzer gelöscht werden soll
|
|
await _emailSender.SendDeleteAccountEmailAsync(user.Email, user.FirstName, user.LastName, _localizer, _emailSenderOptions);
|
|
|
|
return Ok(true);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
#region AppUser
|
|
|
|
/// <summary>
|
|
/// Gibt den App-User zurück
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet]
|
|
[Route("GetAppUser")]
|
|
public async Task<IActionResult> GetAppUser()
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
if (appUser != null)
|
|
{
|
|
var appUserDto = Mapper.Map<AppUserDto>(appUser);
|
|
var baseAddress = GetBaseAddress();
|
|
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
|
|
{
|
|
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
|
|
}
|
|
return Ok(appUserDto);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt den App-User für die Background Sync zurück
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet]
|
|
[Route("GetAppUserSync")]
|
|
public async Task<IActionResult> GetAppUserSync(DateTimeOffset? lastUpdate)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var appUser = await AppUserService.GetAsync(user.AppUserId);
|
|
if (appUser != null && appUser.UpdatedAt > lastUpdate)
|
|
{
|
|
var appUserDto = Mapper.Map<AppUserDto>(appUser);
|
|
var baseAddress = GetBaseAddress();
|
|
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
|
|
{
|
|
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
|
|
}
|
|
return Ok(appUserDto);
|
|
}
|
|
|
|
return NoContent();
|
|
}
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aktualisieren eines App-Users
|
|
/// </summary>
|
|
/// <param name="model">AppUserDto</param>
|
|
/// <param name="photoUpdateFile">Optional Foto</param>
|
|
/// <returns></returns>
|
|
[HttpPost]
|
|
[Route("Update")]
|
|
public async Task<IActionResult> Update([ModelBinder(BinderType = typeof(JsonModelBinder))] AppUserDto model, IFormFile photoUpdateFile)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.Id);
|
|
if (appUser != null)
|
|
{
|
|
if (model.UpdatedAt > appUser.UpdatedAt)
|
|
{
|
|
var photoChanged = false;
|
|
var oldPhoto = appUser.Photo;
|
|
Mapper.Map(model, appUser);
|
|
|
|
if (string.IsNullOrWhiteSpace(model.Photo) || model.Photo.StartsWithHttp())
|
|
{
|
|
//Altes Foto behalten wenn eines als Link kommt
|
|
appUser.Photo = oldPhoto;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (photoUpdateFile != null && !string.IsNullOrEmpty(photoUpdateFile.FileName))
|
|
{
|
|
//Wenn es ein altes Foto gibt, dieses löschen
|
|
if (!string.IsNullOrWhiteSpace(oldPhoto))
|
|
{
|
|
await FileService.DeleteAsync(FileServiceHelper.DocumentContainer, oldPhoto);
|
|
await RemoveThumbnail(FileServiceHelper.DocumentContainer, oldPhoto, 400);
|
|
await RemoveThumbnail(FileServiceHelper.DocumentContainer, oldPhoto, 200);
|
|
await RemoveThumbnail(FileServiceHelper.DocumentContainer, oldPhoto, 100);
|
|
}
|
|
|
|
var extension = Path.GetExtension(photoUpdateFile.FileName);
|
|
var filenameToUse = FileServiceHelper.GetAppUserPath(appUser.Id) + $"photo-{Guid.NewGuid():N}{extension}";
|
|
|
|
using var memoryStream = new MemoryStream();
|
|
|
|
await photoUpdateFile.CopyToAsync(memoryStream);
|
|
memoryStream.Position = 0;
|
|
|
|
using var img = await Image.LoadAsync(memoryStream);
|
|
|
|
img.Mutate(x => x.Resize(new ResizeOptions() { Mode = ResizeMode.Crop, Size = new Size(800) }));
|
|
var format = img.DetectEncoder(photoUpdateFile.FileName);
|
|
|
|
await using var memStream = new MemoryStream();
|
|
await img.SaveAsync(memStream, format);
|
|
memStream.Position = 0;
|
|
await FileService.StoreAsync(FileServiceHelper.DocumentContainer, filenameToUse, memStream);
|
|
appUser.Photo = filenameToUse;
|
|
|
|
//Thumbnails erstellten
|
|
await GenerateThumbnailByWidth(FileServiceHelper.DocumentContainer, filenameToUse, 400);
|
|
await GenerateThumbnailByWidth(FileServiceHelper.DocumentContainer, filenameToUse, 200);
|
|
await GenerateThumbnailByWidth(FileServiceHelper.DocumentContainer, filenameToUse, 100);
|
|
|
|
photoChanged = true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
//Wenn beim Update keine Koordinaten übergeben werden, dann basierend auf der Adresse versuchen
|
|
if (model.Lat == 0 && model.Lng == 0)
|
|
{
|
|
var location = await _geoLocationService.GetLocationAsync(appUser.Address, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
|
|
if (location.Success)
|
|
{
|
|
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
|
|
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
|
|
appUser.Location = geoLocation;
|
|
}
|
|
}
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
user.FirstName = appUser.FirstName;
|
|
user.LastName = appUser.LastName;
|
|
user.FullName = $"{appUser.FirstName} {appUser.LastName}";
|
|
user.Photo = appUser.Photo;
|
|
|
|
await _userService.CommitAsync(User.Identity.Name);
|
|
|
|
if (photoChanged)
|
|
{
|
|
//Update-Datum der Konversationen des Benutzers neu setzen, damit das Foto neu geholt wird...
|
|
await _messageService.SetUpdatedAtAsync(appUser.Id, DateTimeOffset.UtcNow, User.Identity.Name);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(appUser.PaymentId) && appUser.PaymentTermsAccepted)
|
|
{
|
|
//Wenn schon eine MangopayId vorhanden ist, dann auch das Mangopay-Profil aktualisieren
|
|
var mangoUpdateResult = await _mangoPayService.UpdateOwnerAsync(appUser.Id);
|
|
}
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzt den Modus eines App-Users auf "Beides"
|
|
/// </summary>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("SetAppUserType")]
|
|
public async Task<IActionResult> SetAppUserType(SetAppUserTypeDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.Id);
|
|
if (appUser != null)
|
|
{
|
|
if (model.UpdatedAt > appUser.UpdatedAt)
|
|
{
|
|
appUser.Type = (AppUserType)model.Type;
|
|
appUser.UpdatedAt = model.UpdatedAt;
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzt den Modus eines App-Users auf "Beides" - von Owner aufgerufen.
|
|
/// Erstellt ebenso einen MangoPay User und legt die Wallets an
|
|
/// </summary>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("SetAppUserTypeEx")]
|
|
public async Task<IActionResult> SetAppUserTypeEx(SetAppUserTypeExDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.Id);
|
|
if (appUser != null)
|
|
{
|
|
if (model.UpdatedAt > appUser.UpdatedAt)
|
|
{
|
|
appUser.Type = (AppUserType)model.Type;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCode;
|
|
appUser.PaymentTermsAccepted = model.PaymentTermsAccepted;
|
|
appUser.PaymentTermsAcceptedDate = model.PaymentTermsAcceptedDate;
|
|
|
|
appUser.UpdatedAt = model.UpdatedAt;
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
//Nun für den Walker Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
appUser.PaymentId = mangoPayResult.Value;
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
}
|
|
|
|
var appUserDto = Mapper.Map<AppUserDto>(appUser);
|
|
var baseAddress = GetBaseAddress();
|
|
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
|
|
{
|
|
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
|
|
}
|
|
return Ok(appUserDto);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzt den Modus eines App-Users auf "Beides" - von Owner aufgerufen.
|
|
/// Erstellt keinen MangoPay User und legt keine Wallets an
|
|
/// </summary>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("SetAppUserTypeNoMango")]
|
|
public async Task<IActionResult> SetAppUserTypeNoMango(SetAppUserTypeExDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.Id);
|
|
if (appUser != null)
|
|
{
|
|
if (model.UpdatedAt > appUser.UpdatedAt)
|
|
{
|
|
appUser.Type = (AppUserType)model.Type;
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCode;
|
|
appUser.PaymentTermsAccepted = model.PaymentTermsAccepted;
|
|
appUser.PaymentTermsAcceptedDate = model.PaymentTermsAcceptedDate;
|
|
|
|
appUser.UpdatedAt = model.UpdatedAt;
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
if (appUser.Type != AppUserType.DogOwner)
|
|
{
|
|
await AppUserService.CreateWalkerProfileIfNotExistsAsync(appUser.Id);
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
}
|
|
|
|
var appUserDto = Mapper.Map<AppUserDto>(appUser);
|
|
var baseAddress = GetBaseAddress();
|
|
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
|
|
{
|
|
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
|
|
}
|
|
return Ok(appUserDto);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hinzufügen eines PaymentUsers zu einem AppUser
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("AddPaymentUser")]
|
|
public async Task<IActionResult> AddPaymentUser(AddPaymentUserDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.Id);
|
|
if (appUser != null)
|
|
{
|
|
appUser.NationalityCode = model.NationalityCode;
|
|
appUser.MainResidenceCode = model.MainResidenceCode;
|
|
appUser.PaymentTermsAccepted = model.PaymentTermsAccepted;
|
|
appUser.PaymentTermsAcceptedDate = model.PaymentTermsAcceptedDate;
|
|
appUser.UpdatedAt = DateTimeOffset.UtcNow;
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
//Nun für den Benutzer einen Mangopay User anlegen
|
|
var mangoPayResult = await _mangoPayService.CreateOwnerAsync(appUser.Id, false);
|
|
if (mangoPayResult.Success)
|
|
{
|
|
appUser.PaymentId = mangoPayResult.Value;
|
|
//Wallets anlegen
|
|
var walletCreditsResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Credits);
|
|
var walletFeesResult = await _mangoPayService.CreateWalletAsync(appUser.Id, WalletType.Fees);
|
|
}
|
|
|
|
var appUserDto = Mapper.Map<AppUserDto>(appUser);
|
|
var baseAddress = GetBaseAddress();
|
|
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
|
|
{
|
|
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
|
|
}
|
|
return Ok(appUserDto);
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DogWalker Profil
|
|
|
|
/// <summary>
|
|
/// Gibt ein DogWalker Profil zurück
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet]
|
|
[Route("GetWalkerProfile")]
|
|
public async Task<IActionResult> GetWalkerProfile()
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var walkerProfile = await AppUserService.GetWalkerProfileAsync(user.AppUserId);
|
|
if (walkerProfile != null)
|
|
{
|
|
var walkerProfileDto = Mapper.Map<DogWalkerProfileDto>(walkerProfile);
|
|
return Ok(walkerProfileDto);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt ein DogWalker Profil für die Background Sync zurück
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[HttpGet]
|
|
[Route("GetWalkerProfileSync")]
|
|
public async Task<IActionResult> GetWalkerProfileSync(DateTimeOffset? lastUpdate)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(user.AppUserId))
|
|
{
|
|
var walkerProfile = await AppUserService.GetWalkerProfileAsync(user.AppUserId);
|
|
if (walkerProfile != null && walkerProfile.UpdatedAt > lastUpdate)
|
|
{
|
|
var walkerProfileDto = Mapper.Map<DogWalkerProfileDto>(walkerProfile);
|
|
return Ok(walkerProfileDto);
|
|
}
|
|
|
|
return NoContent();
|
|
}
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aktualisieren eines Dogwalker Profils
|
|
/// </summary>
|
|
/// <param name="model">AppUserDto</param>
|
|
/// <returns></returns>
|
|
[HttpPost]
|
|
[Route("UpdateWalkerProfile")]
|
|
public async Task<IActionResult> UpdateWalkerProfile(DogWalkerProfileDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var walkerProfile = await AppUserService.GetWalkerProfileAsync(model.Id);
|
|
if (walkerProfile != null)
|
|
{
|
|
if (model.UpdatedAt > walkerProfile.UpdatedAt)
|
|
{
|
|
Mapper.Map(model, walkerProfile);
|
|
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
}
|
|
|
|
return Ok();
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Blocks
|
|
|
|
/// <summary>
|
|
/// Blockieren eines AppUsers durch einen anderen AppUser
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("BlockAppUser")]
|
|
public async Task<IActionResult> BlockAppUser(BlockCreateDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.BlockingAppUserId);
|
|
if (appUser != null)
|
|
{
|
|
//Nur dann zulassen, wenn der Benutzer der angemeldet ist auch der Benutzer ist der die Blockierung vornimmt
|
|
if (appUser.Id == user.AppUserId)
|
|
{
|
|
var block = await AppUserService.BlockAppUserAsync(model.BlockingAppUserId, model.BlockedAppUserId, User.Identity.Name);
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
//Stornieren der offenen Walks des blockierten Users für den Benutzer der die Blockierung vorgenommen hat
|
|
var canceled = await _walkService.CancelWalksForBlockAsync(model.BlockingAppUserId, model.BlockedAppUserId);
|
|
|
|
//Sehen ob der blockierte Benutzer noch offene Angebote für den blockierenden Benutzer hat und diese Ablehnen
|
|
var openRequests = await _publicWalkRequestService.GetByStatusAsync(model.BlockingAppUserId, PublicWalkRequestStatus.Open);
|
|
foreach (var publicWalkRequest in openRequests)
|
|
{
|
|
var respone = await _publicWalkResponseService.GetForWalkerAsync(model.BlockedAppUserId, publicWalkRequest.Id);
|
|
if (respone != null)
|
|
{
|
|
respone.Status = PublicWalkResponseStatus.Declined;
|
|
respone.UpdatedAt = DateTimeOffset.UtcNow;
|
|
await _publicWalkResponseService.CommitAsync(User.Identity.Name);
|
|
}
|
|
}
|
|
|
|
var dto = Mapper.Map<AppUserBlockDto>(block);
|
|
return Ok(dto);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Blockieren eines AppUsers durch einen anderen AppUser aufheben
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("UnblockAppUser")]
|
|
public async Task<IActionResult> UnblockAppUser(BlockRemoveDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var appUser = await AppUserService.GetAsync(model.BlockingAppUserId);
|
|
if (appUser != null)
|
|
{
|
|
//Nur dann zulassen, wenn der Benutzer der angemeldet ist auch der Benutzer ist der die Blockierung vorgenommen hat
|
|
if (appUser.Id == user.AppUserId)
|
|
{
|
|
var success = await AppUserService.UnblockAppUserAsync(model.BlockingAppUserId, model.BlockedAppUserId);
|
|
if(success)
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
return Ok(success);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Abfragen gesperrten Benutzern für einen App-User
|
|
/// </summary>
|
|
/// <param name="model">Abfragemodel</param>
|
|
/// <returns>Liste von gesperrten Benutzern - App-Users</returns>
|
|
[HttpPost]
|
|
[Route("GetBlockedAppUsers")]
|
|
public async Task<IActionResult> GetBlockedAppUsers(BlockedQueryDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var baseAddress = GetBaseAddress();
|
|
var response = new ListResponseDto<AppUserBlockWithNamesDto>();
|
|
|
|
var queryResult = await AppUserService.GetBlockedAppUsersAsync(model);
|
|
|
|
response.Total = queryResult.total;
|
|
var resultList = queryResult.list;
|
|
|
|
var dtoList = Mapper.Map<List<AppUserBlockWithNamesDto>>(resultList);
|
|
|
|
foreach (var dtoItem in dtoList)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(dtoItem.Photo))
|
|
dtoItem.Photo = $"{baseAddress}/file/documents/thumbnails/{400}/{dtoItem.Photo}";
|
|
}
|
|
|
|
response.List = dtoList;
|
|
response.Take = model.Take;
|
|
response.Skip = model.Skip;
|
|
|
|
return Ok(response);
|
|
}
|
|
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AppUserReports - Meldungen
|
|
|
|
/// <summary>
|
|
/// Melden eines AppUsers durch einen anderen AppUser
|
|
/// </summary>
|
|
/// <param name="model">Model</param>
|
|
/// <returns>200 OK</returns>
|
|
[HttpPost]
|
|
[Route("ReportAppUser")]
|
|
public async Task<IActionResult> ReportAppUser(AppUserReportDto model)
|
|
{
|
|
var clientOffset = GetClientDateOffset();
|
|
|
|
if (User?.Identity != null && User.Identity.IsAuthenticated)
|
|
{
|
|
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
|
|
if (user != null)
|
|
{
|
|
if (ModelState.IsValid)
|
|
{
|
|
var reportingAppUser = await AppUserService.GetAsync(model.ReportingAppUserId);
|
|
if (reportingAppUser != null)
|
|
{
|
|
//Nur dann zulassen, wenn der Benutzer der angemeldet ist auch der Benutzer ist der die Blockierung vornimmt
|
|
if (reportingAppUser.Id == user.AppUserId)
|
|
{
|
|
var reportedAppUser = await AppUserService.GetAsync(model.ReportedAppUserId);
|
|
if (reportedAppUser != null)
|
|
{
|
|
var report = _appUserReportService.Create();
|
|
Mapper.Map(model, report);
|
|
report.Status = AppUserReportStatus.Open;
|
|
|
|
_appUserReportService.Add(report);
|
|
await _appUserReportService.CommitAsync(User.Identity.Name);
|
|
|
|
//Jetzt Block behandeln...
|
|
if (model.BlockType != AppUserReportBlockTypeDto.NoBlock)
|
|
{
|
|
|
|
DateTimeOffset? blockUntil = null;
|
|
if (model.BlockType == AppUserReportBlockTypeDto.BlockForTime)
|
|
blockUntil = DateTimeOffset.UtcNow.AddHours(24);
|
|
|
|
var block = await AppUserService.BlockAppUserAsync(model.ReportingAppUserId, model.ReportedAppUserId, User.Identity.Name, blockUntil, report.Id);
|
|
await AppUserService.CommitAsync(User.Identity.Name);
|
|
|
|
if (model.BlockType == AppUserReportBlockTypeDto.BlockForever)
|
|
{
|
|
//Stornieren der offenen Walks des blockierten Users für den Benutzer der die Blockierung vorgenommen hat
|
|
var canceled = await _walkService.CancelWalksForBlockAsync(model.ReportingAppUserId, model.ReportedAppUserId);
|
|
|
|
//Sehen ob der blockierte Benutzer noch offene Angebote für den blockierenden Benutzer hat und diese Ablehnen
|
|
var openRequests = await _publicWalkRequestService.GetByStatusAsync(model.ReportingAppUserId, PublicWalkRequestStatus.Open);
|
|
foreach (var publicWalkRequest in openRequests)
|
|
{
|
|
var respone = await _publicWalkResponseService.GetForWalkerAsync(model.ReportedAppUserId, publicWalkRequest.Id);
|
|
if (respone != null)
|
|
{
|
|
respone.Status = PublicWalkResponseStatus.Declined;
|
|
respone.UpdatedAt = DateTimeOffset.UtcNow;
|
|
await _publicWalkResponseService.CommitAsync(User.Identity.Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ok(true);
|
|
}
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
return BadRequest(CommunicationErrors.Common_Model_Invalid);
|
|
}
|
|
}
|
|
return NotFound(CommunicationErrors.Common_NotFound);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private
|
|
|
|
/// <summary>
|
|
/// Generieren des Client-Secrets das Apple für die Prüfung des Benutzers benötigt
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task<string> GenerateAppleClientSecretAsync()
|
|
{
|
|
var clientSecret = await _memoryCache.GetStringAsync("AppleClientSecret", CancellationToken.None);
|
|
|
|
if (string.IsNullOrEmpty(clientSecret))
|
|
{
|
|
var rootPath = _environment.WebRootPath;
|
|
var path = Path.Combine(rootPath, $"app_files\\apple\\AuthKey_{_appleOptions.Value.KeyId}.p8");
|
|
|
|
var lines = System.IO.File.ReadLines(path);
|
|
var keyStart = String.Join(String.Empty, lines.Where(x => !x.Contains("PRIVATE KEY")));
|
|
var bytes = Convert.FromBase64String(keyStart);
|
|
|
|
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
|
|
|
|
//Import the key using a Pkcs8PrivateBlob.
|
|
var cngKey = CngKey.Import(bytes, CngKeyBlobFormat.Pkcs8PrivateBlob);
|
|
|
|
//Create new ECDsaCng object with the imported key.
|
|
var ecDsaCng = new ECDsaCng(cngKey);
|
|
ecDsaCng.HashAlgorithm = CngAlgorithm.ECDsaP256;
|
|
|
|
//Create new SigningCredentials instance which will be used for signing the token.
|
|
var signingCredentials = new SigningCredentials(new ECDsaSecurityKey(ecDsaCng), SecurityAlgorithms.EcdsaSha256);
|
|
|
|
var now = DateTime.UtcNow.AddHours(12);
|
|
|
|
//Create new list with the required claims.
|
|
var claims = new List<Claim>
|
|
{
|
|
new Claim("iss", _appleOptions.Value.TeamId),
|
|
new Claim("iat", EpochTime.GetIntDate(now).ToString(), ClaimValueTypes.Integer64),
|
|
new Claim("exp", EpochTime.GetIntDate(now.AddMinutes(5)).ToString(), ClaimValueTypes.Integer64),
|
|
new Claim("aud", "https://appleid.apple.com"),
|
|
new Claim("sub", _appleOptions.Value.ClientId)
|
|
};
|
|
|
|
//Create the JSON Web Token object.
|
|
var token = new JwtSecurityToken(
|
|
issuer: _appleOptions.Value.TeamId,
|
|
claims: claims,
|
|
expires: now.AddMinutes(5),
|
|
signingCredentials: signingCredentials);
|
|
|
|
token.Header.Add("kid", _appleOptions.Value.KeyId);
|
|
|
|
clientSecret = tokenHandler.WriteToken(token);
|
|
|
|
|
|
|
|
|
|
//var audience = "https://appleid.apple.com";
|
|
//var expiresAt = DateTimeOffset.UtcNow.AddSeconds(15777000).AddMinutes(-15).UtcDateTime; //apple max, but let's not get messed up with clock sync issues
|
|
//var subject = new System.Security.Claims.ClaimsIdentity(new[] { new System.Security.Claims.Claim("sub", _appleOptions.Value.ClientId) });
|
|
|
|
//var lines = System.IO.File.ReadLines(path);
|
|
//var keyStart = String.Join(String.Empty, lines.Where(x => !x.Contains("PRIVATE KEY")));
|
|
//var bytes = Convert.FromBase64String(keyStart);
|
|
|
|
//var ecd = ECDsa.Create();
|
|
//ecd.ImportPkcs8PrivateKey(bytes, out var _);
|
|
|
|
//var ecpStart = ecd.ExportParameters(true);
|
|
////var param = new { ecpStart.D, ecpStart.Q };
|
|
////var json = JsonSerializer.Serialize(param);
|
|
|
|
//var ecp = new ECParameters
|
|
//{
|
|
// D = ecpStart.D,
|
|
// Q = ecpStart.Q,
|
|
// Curve = ECCurve.NamedCurves.nistP256
|
|
//};
|
|
//var alg = ECDsa.Create(ecp);
|
|
|
|
//var key = new ECDsaSecurityKey(alg) { KeyId = _appleOptions.Value.KeyId };
|
|
//var sig = new SigningCredentials(key, SecurityAlgorithms.EcdsaSha256Signature);
|
|
|
|
//var tokenHandler = new JwtSecurityTokenHandler();
|
|
|
|
//var tokenDescriptor = new SecurityTokenDescriptor()
|
|
//{
|
|
// Audience = audience,
|
|
// Expires = expiresAt,
|
|
// Issuer = _appleOptions.Value.TeamId,
|
|
// Subject = subject,
|
|
// SigningCredentials = sig
|
|
//};
|
|
|
|
//clientSecret = tokenHandler.CreateEncodedJwt(tokenDescriptor);
|
|
|
|
var options = new DistributedCacheEntryOptions();
|
|
options.SetAbsoluteExpiration(now.AddMinutes(-15));
|
|
await _memoryCache.SetStringAsync("AppleClientSecret", clientSecret, options);
|
|
|
|
|
|
|
|
|
|
// Tokengültigkeit von 6 Monaten (das ist der Max-Wert laut Apple)
|
|
//var expiresAt = DateTime.UtcNow.Add(TimeSpan.FromSeconds(15777000));
|
|
|
|
//var tokenDescriptor = new SecurityTokenDescriptor()
|
|
//{
|
|
// Audience = "https://appleid.apple.com",
|
|
// Expires = expiresAt,
|
|
// Issuer = _appleOptions.Value.TeamId,
|
|
// Subject = new ClaimsIdentity(new[] { new Claim("sub", _appleOptions.Value.ClientId) }),
|
|
//};
|
|
|
|
//// Load the .p8 file from disk, removing the
|
|
//// `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----`
|
|
//// prefix and suffix, and joining `\n` characters between lines.
|
|
//var content = await System.IO.File.ReadAllTextAsync(path);
|
|
|
|
//string[] keyLines = content.Split('\n');
|
|
//content = string.Join(string.Empty, keyLines.Skip(1).Take(keyLines.Length - 2));
|
|
|
|
//byte[] keyBlob = Convert.FromBase64String(content);
|
|
|
|
//// Create an ECDSA 256 algorithm to sign the token
|
|
//using var privateKey = CngKey.Import(keyBlob, CngKeyBlobFormat.Pkcs8PrivateBlob);
|
|
//using var algorithm = new ECDsaCng(privateKey);
|
|
//{
|
|
// algorithm.HashAlgorithm = CngAlgorithm.Sha256;
|
|
|
|
// var key = new ECDsaSecurityKey(algorithm) { KeyId = _appleOptions.Value.KeyId };
|
|
|
|
// // Set the signing key for the token
|
|
// tokenDescriptor.SigningCredentials = new SigningCredentials(
|
|
// key,
|
|
// SecurityAlgorithms.EcdsaSha256Signature);
|
|
|
|
// // Create the token, which acts as the Client Secret
|
|
// var tokenHandler = new JwtSecurityTokenHandler();
|
|
// clientSecret = tokenHandler.CreateEncodedJwt(tokenDescriptor);
|
|
// var options = new DistributedCacheEntryOptions();
|
|
// options.SetAbsoluteExpiration(expiresAt.AddMinutes(-15));
|
|
// await _memoryCache.SetStringAsync("AppleClientSecret", clientSecret, options);
|
|
//}
|
|
}
|
|
|
|
return clientSecret;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|