diff --git a/gehGassi.Core/Services/WalkService.cs b/gehGassi.Core/Services/WalkService.cs index f9874ac..edb2571 100644 --- a/gehGassi.Core/Services/WalkService.cs +++ b/gehGassi.Core/Services/WalkService.cs @@ -592,81 +592,84 @@ namespace gehGassi.Core.Services walk.PaymentStatus = PaymentStatus.Paid; await CommitAsync("System"); - decimal feeDecimal = 0; - long feeFromUser = 0; - long feeFromVoucher = 0; - var gehGassiFee = await gehGassiTransactionService.GetMinGehGassiFeeAsync(walk.Price); - if (gehGassiFee != null) + if (walk.PaymentType == WalkPaymentType.MangoPay) { - if (gehGassiFee.Percent > 0) + decimal feeDecimal = 0; + long feeFromUser = 0; + long feeFromVoucher = 0; + var gehGassiFee = await gehGassiTransactionService.GetMinGehGassiFeeAsync(walk.Price); + if (gehGassiFee != null) { - var percent = walk.Price * gehGassiFee.Percent / 100; - feeDecimal = percent; - } - - if (gehGassiFee.Fixed > 0) - { - feeDecimal += gehGassiFee.Fixed; - } - } - if (feeDecimal > 0) - { - feeFromUser = (long)(feeDecimal * 100); - } - - - //Wenn es einen gutschein gibt, dann Geld vom Transferkontos des Gutscheins auf das transferkonto des Hundebesitzers überweisen - if (!string.IsNullOrWhiteSpace(walk.VoucherId) && walk.VoucherAmmount > 0) - { - var voucherUsed = await voucherCampaignService.GetUsageAsync(walk.VoucherId, walk.DogOwnerId, walk.Id); - if (voucherUsed != null) - { - var ammountFromVoucher = (long)(voucherUsed.VoucherAmmountUsed * 100); - voucherUsed.UsageStatus = VoucherUsageStatus.Used; - await CommitAsync("System"); - - var voucher = await voucherCampaignService.GetVoucherAsync(voucherUsed.VoucherId); - if (voucher != null) + if (gehGassiFee.Percent > 0) { - var campaign = await voucherCampaignService.GetAsync(voucher.VoucherCampaignId); - if (campaign != null) + var percent = walk.Price * gehGassiFee.Percent / 100; + feeDecimal = percent; + } + + if (gehGassiFee.Fixed > 0) + { + feeDecimal += gehGassiFee.Fixed; + } + } + if (feeDecimal > 0) + { + feeFromUser = (long)(feeDecimal * 100); + } + + + //Wenn es einen gutschein gibt, dann Geld vom Transferkontos des Gutscheins auf das transferkonto des Hundebesitzers überweisen + if (!string.IsNullOrWhiteSpace(walk.VoucherId) && walk.VoucherAmmount > 0) + { + var voucherUsed = await voucherCampaignService.GetUsageAsync(walk.VoucherId, walk.DogOwnerId, walk.Id); + if (voucherUsed != null) + { + var ammountFromVoucher = (long)(voucherUsed.VoucherAmmountUsed * 100); + voucherUsed.UsageStatus = VoucherUsageStatus.Used; + await CommitAsync("System"); + + var voucher = await voucherCampaignService.GetVoucherAsync(voucherUsed.VoucherId); + if (voucher != null) { - var customer = await customerService.GetAsync(campaign.CustomerId); - if (customer != null) + var campaign = await voucherCampaignService.GetAsync(voucher.VoucherCampaignId); + if (campaign != null) { - var dogOwner = await appUserService.GetAsync(walk.DogOwnerId); - if (dogOwner != null) + var customer = await customerService.GetAsync(campaign.CustomerId); + if (customer != null) { - var wallet = await walletService.GetAsync(walk.DogOwnerId, WalletType.Fees); - if (wallet != null) + var dogOwner = await appUserService.GetAsync(walk.DogOwnerId); + if (dogOwner != null) { - var transferResult = await mangoPayService.TransferMoneyAsync(customer.MangopayPaymentId, campaign.WalletFeeId, dogOwner.PaymentId, wallet.Id, walk.Id, ammountFromVoucher, 0, $"VoucherId_{voucher.Id}_WalkId_{walk.Id}", targetAppUserId: dogOwner.Id); + var wallet = await walletService.GetAsync(walk.DogOwnerId, WalletType.Fees); + if (wallet != null) + { + var transferResult = await mangoPayService.TransferMoneyAsync(customer.MangopayPaymentId, campaign.WalletFeeId, dogOwner.PaymentId, wallet.Id, walk.Id, ammountFromVoucher, 0, $"VoucherId_{voucher.Id}_WalkId_{walk.Id}", targetAppUserId: dogOwner.Id); + } } } } } } } - } - var sourceWallet = await walletService.GetAsync(walk.DogOwnerId, WalletType.Fees); - var targetWallet = await walletService.GetAsync(walk.DogWalkerId, WalletType.Credits); - if (sourceWallet != null && targetWallet != null) - { - var sourceUser = await appUserService.GetAsync(walk.DogOwnerId); - var targetUser = await appUserService.GetAsync(walk.DogWalkerId); - - if (sourceUser != null && targetUser != null) + var sourceWallet = await walletService.GetAsync(walk.DogOwnerId, WalletType.Fees); + var targetWallet = await walletService.GetAsync(walk.DogWalkerId, WalletType.Credits); + if (sourceWallet != null && targetWallet != null) { - var ammount = (long)(walk.Price * 100); - var transcationSuccess = await mangoPayService.TransferMoneyAsync(walk.DogOwnerId, walk.DogWalkerId, walk.Id, ammount, feeFromUser, $"WalkId_Payment_{walk.Id}"); + var sourceUser = await appUserService.GetAsync(walk.DogOwnerId); + var targetUser = await appUserService.GetAsync(walk.DogWalkerId); - //Wallets aktualisieren - await mangoPayService.GetWalletBalanceAsync(sourceUser.Id, WalletType.Credits); - await mangoPayService.GetWalletBalanceAsync(sourceUser.Id, WalletType.Fees); + if (sourceUser != null && targetUser != null) + { + var ammount = (long)(walk.Price * 100); + var transcationSuccess = await mangoPayService.TransferMoneyAsync(walk.DogOwnerId, walk.DogWalkerId, walk.Id, ammount, feeFromUser, $"WalkId_Payment_{walk.Id}"); - await mangoPayService.GetWalletBalanceAsync(targetUser.Id, WalletType.Credits); - await mangoPayService.GetWalletBalanceAsync(targetUser.Id, WalletType.Fees); + //Wallets aktualisieren + await mangoPayService.GetWalletBalanceAsync(sourceUser.Id, WalletType.Credits); + await mangoPayService.GetWalletBalanceAsync(sourceUser.Id, WalletType.Fees); + + await mangoPayService.GetWalletBalanceAsync(targetUser.Id, WalletType.Credits); + await mangoPayService.GetWalletBalanceAsync(targetUser.Id, WalletType.Fees); + } } } } diff --git a/gehGassi.Web/Controllers/Api/ApiAccountController.cs b/gehGassi.Web/Controllers/Api/ApiAccountController.cs index c3159af..dba3905 100644 --- a/gehGassi.Web/Controllers/Api/ApiAccountController.cs +++ b/gehGassi.Web/Controllers/Api/ApiAccountController.cs @@ -56,6 +56,7 @@ namespace gehGassi.Web.Controllers.Api [ApiController] [ApiVersion(1)] [ApiVersion(2)] + [ApiVersion(3)] [Route("api/account")] [Route("api/v{v:apiVersion}/account")] public class ApiAccountController : ApiBaseController @@ -465,6 +466,131 @@ namespace gehGassi.Web.Controllers.Api return BadRequest(CommunicationErrors.Common_Model_Invalid); } + /// + /// Registrieren eines App-Users + /// + /// Model + /// HTTP 200 OK wenn erfolgreich + [AllowAnonymous] + [HttpPost] + [MapToApiVersion(3)] + [Route("Register")] + public async Task 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); + } + /// /// Registrieren eines App-Users mittels external Provider /// @@ -958,6 +1084,254 @@ namespace gehGassi.Web.Controllers.Api return BadRequest(CommunicationErrors.Common_Model_Invalid); } + /// + /// Registrieren eines App-Users mittels external Provider + /// + /// Model + /// HTTP 200 OK wenn erfolgreich + [AllowAnonymous] + [HttpPost] + [MapToApiVersion(3)] + [Route("RegisterExternal")] + public async Task 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(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> + { + new KeyValuePair("client_id", _appleOptions.Value.ClientId), + new KeyValuePair("client_secret", clientSecret), + new KeyValuePair("refresh_token", model.AccessToken), + new KeyValuePair("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(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() + { + 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(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); + } + /// /// Anmelden via API. Erstellt ein Access-Token und ein Refresh-Token wenn erfolgreich /// @@ -2041,6 +2415,62 @@ namespace gehGassi.Web.Controllers.Api return NotFound(CommunicationErrors.Common_NotFound); } + /// + /// Setzt den Modus eines App-Users auf "Beides" - von Owner aufgerufen. + /// Erstellt keinen MangoPay User und legt keine Wallets an + /// + /// 200 OK + [HttpPost] + [Route("SetAppUserTypeNoMango")] + public async Task 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(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); + } + /// /// Hinzufügen eines PaymentUsers zu einem AppUser ///