Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AutoPile.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
builder.Services.AddScoped<IReviewsCache, ReviewsCache>();
builder.Services.AddScoped<IUserInfoCache, UserInfoCache>();
builder.Services.AddScoped<IOrderCache, OrderCache>();
builder.Services.AddScoped<IStripeService, StripeService>();
// Add this to the service configuration section in Program.cs
// Register both QueueClients
// Register QueueClient for Email Queue
Expand Down
4 changes: 2 additions & 2 deletions AutoPile.DATA/Data/AutoPileMongoDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace AutoPile.DATA.Data
{
public class AutoPileMongoDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Review> Reviews { get; set; }
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<Review> Reviews { get; set; }

public static AutoPileMongoDbContext Create(IMongoDatabase database) =>
new(new DbContextOptionsBuilder<AutoPileMongoDbContext>()
Expand Down
9 changes: 9 additions & 0 deletions AutoPile.DOMAIN/Interface/IStripeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Stripe;

namespace AutoPile.SERVICE.Services
{
public interface IStripeService
{
Task<PaymentIntent> CreatePaymentIntentAsync(long amount, string currency);
}
}
24 changes: 6 additions & 18 deletions AutoPile.SERVICE/Services/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,13 @@ public AuthService(UserManager<ApplicationUser> userManager, ILogger<IAuthServic
throw new BadRequestException("Email already registered");
}

var existUserWithPhone = await _userManager.Users.AnyAsync(u => u.PhoneNumber == userSignupDTO.PhoneNumber);
var existUserWithPhone = _userManager.Users.Any(u => u.PhoneNumber == userSignupDTO.PhoneNumber);
if (existUserWithPhone)
{
throw new BadRequestException("Phone number already registered");
}

var user = new ApplicationUser
{
UserName = userSignupDTO.UserName,
Email = userSignupDTO.Email,
FirstName = userSignupDTO.FirstName,
LastName = userSignupDTO.LastName,
PhoneNumber = userSignupDTO.PhoneNumber
};
var user = _mapper.Map<ApplicationUser>(userSignupDTO);

var result = await _userManager.CreateAsync(user, userSignupDTO.Password);
if (!result.Succeeded)
Expand All @@ -144,13 +137,8 @@ public AuthService(UserManager<ApplicationUser> userManager, ILogger<IAuthServic

var token = _jwtTokenGenerator.GenerateJwtToken(user);

var responseDTO = new UserResponseDTO
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
Roles = await _userManager.GetRolesAsync(user)
};
var responseDTO = _mapper.Map<UserResponseDTO>(user);
responseDTO.Roles = await _userManager.GetRolesAsync(user);

return (responseDTO, token);
}
Expand All @@ -165,8 +153,8 @@ public AuthService(UserManager<ApplicationUser> userManager, ILogger<IAuthServic
UserResponseDTO userResponseDTO = _mapper.Map<UserResponseDTO>(user);

userResponseDTO.Roles = await _userManager.GetRolesAsync(user);
var userResponseInfoDTO = _mapper.Map<UserInfoResponseDTO>(user);
userResponseInfoDTO.Roles = userResponseDTO.Roles;
//var userResponseInfoDTO = _mapper.Map<UserInfoResponseDTO>(user);
//userResponseInfoDTO.Roles = userResponseDTO.Roles;
//await _userInfoCache.SetUserAsync(user.Id, userResponseInfoDTO);
_logger.LogInformation("Successfully cached user info for user {UserId}", user.Id);
return (userResponseDTO, token);
Expand Down
27 changes: 5 additions & 22 deletions AutoPile.SERVICE/Services/PaymentService.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
using AutoMapper;
using AutoPile.DATA.Data;
using AutoPile.DATA.Data;
using AutoPile.DATA.Exceptions;
using AutoPile.DOMAIN.DTOs.Requests;
using MongoDB.Bson;
using Stripe;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AutoPile.SERVICE.Services
{
public class PaymentService : IPaymentService
{
private readonly AutoPileManagementDbContext _autoPileManagementDbContext;
private readonly AutoPileMongoDbContext _autoPileMongoDbContext;
private readonly IMapper _mapper;
private readonly IStripeService _stripeService;

public PaymentService(AutoPileManagementDbContext autoPileManagementDbContext, AutoPileMongoDbContext autoPileMongoDbContext, IMapper mapper)
public PaymentService(AutoPileMongoDbContext autoPileMongoDbContext, IStripeService stripeService)
{
_autoPileManagementDbContext = autoPileManagementDbContext;
_autoPileMongoDbContext = autoPileMongoDbContext;
_mapper = mapper;
_stripeService = stripeService;
}

public async Task<PaymentIntent> PaymentIntentCreateAsync(PaymentIntentCreate paymentIntentCreate)
Expand All @@ -32,19 +27,7 @@ public async Task<PaymentIntent> PaymentIntentCreateAsync(PaymentIntentCreate pa
}

var totalAmount = await CalculateTotalAmountAsync(paymentIntentCreate.Items);

var options = new PaymentIntentCreateOptions
{
Amount = (long)(totalAmount * 100),
Currency = "aud",
AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
{
Enabled = true,
},
};

var service = new PaymentIntentService();
return await service.CreateAsync(options);
return await _stripeService.CreatePaymentIntentAsync((long)(totalAmount * 100), "aud");
}

private async Task<decimal> CalculateTotalAmountAsync(Item[] items)
Expand Down
27 changes: 27 additions & 0 deletions AutoPile.SERVICE/Services/StripeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Stripe;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoPile.SERVICE.Services
{
public class StripeService : IStripeService
{
public async Task<PaymentIntent> CreatePaymentIntentAsync(long amount, string currency)
{
var options = new PaymentIntentCreateOptions
{
Amount = amount,
Currency = currency,
AutomaticPaymentMethods = new PaymentIntentAutomaticPaymentMethodsOptions
{
Enabled = true,
},
};
var service = new PaymentIntentService();
return await service.CreateAsync(options);
}
}
}
236 changes: 236 additions & 0 deletions AutoPile.UnitTests/AuthServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
using AutoMapper;
using AutoPile.DATA.Cache;
using AutoPile.DATA.Exceptions;
using AutoPile.DOMAIN.DTOs.Requests;
using AutoPile.DOMAIN.DTOs.Responses;
using AutoPile.DOMAIN.Models.Entities;
using AutoPile.SERVICE.Services;
using AutoPile.SERVICE.Utilities;
using FluentAssertions;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Moq;
using Resend;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoPile.UnitTests
{
public class AuthServiceTests
{
private readonly Mock<UserManager<ApplicationUser>> _userManagerMock;
private readonly Mock<IMapper> _mapperMock;
private readonly Mock<IJwtTokenGenerator> _jwtTokenGeneratorMock;
private readonly Mock<IResend> _resendMock;
private readonly Mock<IConfiguration> _configurationMock;
private readonly Mock<IEmailQueueService> _emailQueueServiceMock;
private readonly Mock<IUserInfoCache> _userInfoCacheMock;
private readonly Mock<ILogger<IAuthService>> _loggerMock;
private readonly AuthService _authServiceMock;

public AuthServiceTests()
{
var storeMock = new Mock<IUserStore<ApplicationUser>>();
_userManagerMock = new Mock<UserManager<ApplicationUser>>(
storeMock.Object,
null, // IOptions<IdentityOptions>
null, // IPasswordHasher<ApplicationUser>
null, // IEnumerable<IUserValidator<ApplicationUser>>
null, // IEnumerable<IPasswordValidator<ApplicationUser>>
null, // ILookupNormalizer
null, // IdentityErrorDescriber
null, // IServiceProvider
null // ILogger<UserManager<ApplicationUser>>
);
_mapperMock = new Mock<IMapper>();
_userInfoCacheMock = new Mock<IUserInfoCache>();
_jwtTokenGeneratorMock = new Mock<IJwtTokenGenerator>();
_configurationMock = new Mock<IConfiguration>();
_resendMock = new Mock<IResend>();
_emailQueueServiceMock = new Mock<IEmailQueueService>();
_loggerMock = new Mock<ILogger<IAuthService>>();
_authServiceMock = new AuthService(_userManagerMock.Object, _loggerMock.Object, _emailQueueServiceMock.Object,
_configurationMock.Object, _mapperMock.Object, _userInfoCacheMock.Object, _jwtTokenGeneratorMock.Object, _resendMock.Object);
}

[Fact]
public async Task SignUpUser_ValidInput_ReturnUserResponseDTO()
{
// Arrange
var password = "TestPassword";
var userSignUpDTO = new UserSignupDTO()
{
FirstName = "firstName",
LastName = "lastName",
UserName = "TestUserName",
PhoneNumber = "TestPhoneNumber",
Email = "TestEmail",
Password = password
};

_mapperMock.Setup(m => m.Map<ApplicationUser>(It.IsAny<UserSignupDTO>()))
.Returns(new ApplicationUser
{
UserName = userSignUpDTO.UserName,
Email = userSignUpDTO.Email,
FirstName = userSignUpDTO.FirstName,
LastName = userSignUpDTO.LastName,
PhoneNumber = userSignUpDTO.PhoneNumber,
Id = "TestId"
});

_mapperMock.Setup(m => m.Map<UserResponseDTO>(It.IsAny<ApplicationUser>()))
.Returns(new UserResponseDTO
{
UserName = userSignUpDTO.UserName,
Email = userSignUpDTO.Email,
Id = "TestId"
});

_userManagerMock.Setup(u => u.FindByEmailAsync(userSignUpDTO.Email))
.ReturnsAsync(null as ApplicationUser);

_userManagerMock.Setup(u => u.Users)
.Returns(new List<ApplicationUser>().AsQueryable());

_userManagerMock.Setup(u => u.CreateAsync(It.IsAny<ApplicationUser>(), password))
.ReturnsAsync(IdentityResult.Success);

_userManagerMock.Setup(u => u.AddToRoleAsync(It.IsAny<ApplicationUser>(), "User"))
.ReturnsAsync(IdentityResult.Success);

_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<ApplicationUser>()))
.ReturnsAsync(["User"]);

_jwtTokenGeneratorMock.Setup(t => t.GenerateJwtToken(It.IsAny<ApplicationUser>()))
.Returns("test_access_token");

// Act
var result = await _authServiceMock.SignupUserAsync(userSignUpDTO);

// Assert
result.Should().NotBeNull();
var (userResponse, accessToken, refreshToken) = result;

userResponse.Should().NotBeNull();
userResponse.Should().BeOfType<UserResponseDTO>();
userResponse.UserName.Should().Be(userSignUpDTO.UserName);
userResponse.Email.Should().Be(userSignUpDTO.Email);
userResponse.Roles.Should().Contain("User");

accessToken.Should().Be("test_access_token");
refreshToken.Should().NotBeNull();

_userManagerMock.Verify(u => u.CreateAsync(It.IsAny<ApplicationUser>(), password), Times.Once);
_userManagerMock.Verify(u => u.AddToRoleAsync(It.IsAny<ApplicationUser>(), "User"), Times.Once);
_jwtTokenGeneratorMock.Verify(t => t.GenerateJwtToken(It.IsAny<ApplicationUser>()), Times.Once);
}

[Fact]
public async Task SignInUser_ValidInput_ReturnUserResponseDTO()
{
//Arrange
var password = "TestPassword";
var userSignUpDTO = new UserSignupDTO()
{
FirstName = "firstName",
LastName = "lastName",
UserName = "TestUserName",
PhoneNumber = "TestPhoneNumber",
Email = "TestEmail",
Password = password
};

var userSigninDTO = new UserSigninDTO()
{
Email = "TestEmail",
Password = password
};

var user = new ApplicationUser
{
UserName = userSignUpDTO.UserName,
Email = userSignUpDTO.Email,
FirstName = userSignUpDTO.FirstName,
LastName = userSignUpDTO.LastName,
PhoneNumber = userSignUpDTO.PhoneNumber,
Id = "TestId"
};
_userManagerMock.Setup(u => u.FindByEmailAsync(userSignUpDTO.Email)).ReturnsAsync(user);
_userManagerMock.Setup(u => u.CheckPasswordAsync(It.IsAny<ApplicationUser>(), password)).ReturnsAsync(true);
_jwtTokenGeneratorMock.Setup(t => t.GenerateJwtToken(It.IsAny<ApplicationUser>())).Returns("test_access_token");

_mapperMock.Setup(m => m.Map<UserResponseDTO>(user)).Returns(new UserResponseDTO
{
UserName = userSignUpDTO.UserName,
Email = userSignUpDTO.Email,
Id = "TestId",
});

_userManagerMock.Setup(u => u.GetRolesAsync(It.IsAny<ApplicationUser>()))
.ReturnsAsync(["User"]);

//Act
var result = await _authServiceMock.SigninAsync(userSigninDTO);

//Assert
result.Should().NotBeNull();
var (userResponse, accessToken, refreshToken) = result;

userResponse.Should().NotBeNull();
userResponse.Should().BeOfType<UserResponseDTO>();
userResponse.UserName.Should().Be(userSignUpDTO.UserName);
userResponse.Email.Should().Be(userSignUpDTO.Email);
userResponse.Roles.Should().Contain("User");

accessToken.Should().Be("test_access_token");
refreshToken.Should().NotBeNull();

_userManagerMock.Verify(u => u.CheckPasswordAsync(It.IsAny<ApplicationUser>(), password), Times.Once);
_jwtTokenGeneratorMock.Verify(t => t.GenerateJwtToken(It.IsAny<ApplicationUser>()), Times.Once);
_userManagerMock.Verify(u => u.GetRolesAsync(It.IsAny<ApplicationUser>()), Times.Once);
}

[Fact]
public async Task SigninUser_WrongCredentialInput_ReturnNoFoundException()
{
//Arrange
var password = "TestPassword";
var userSignUpDTO = new UserSignupDTO()
{
FirstName = "firstName",
LastName = "lastName",
UserName = "TestUserName",
PhoneNumber = "TestPhoneNumber",
Email = "TestEmail",
Password = password
};
var userSignInDTO = new UserSigninDTO()
{
Email = "TestEmail",
Password = password
};
var user = new ApplicationUser
{
UserName = userSignUpDTO.UserName,
Email = userSignUpDTO.Email,
FirstName = userSignUpDTO.FirstName,
LastName = userSignUpDTO.LastName,
PhoneNumber = userSignUpDTO.PhoneNumber,
Id = "TestId"
};
_userManagerMock.Setup(u => u.FindByEmailAsync(userSignUpDTO.Email)).ReturnsAsync(user);
_userManagerMock.Setup(u => u.CheckPasswordAsync(user, password)).ReturnsAsync(false);

//Act & Assert
await _authServiceMock.Invoking(x => x.SigninAsync(userSignInDTO))
.Should().ThrowAsync<NotFoundException>()
.WithMessage("Email does not exist or incorrect password");
}
}
}
Loading