Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f2c4ead
feat: implement blog management in graphql
dorisjenny27 Aug 31, 2024
8b16fd4
feat: implement category management in graphql
dorisjenny27 Aug 31, 2024
ad3c9e4
feat: implement category management in graphql
dorisjenny27 Aug 31, 2024
01a6857
Feat: Implement Category Management in Graphql (#379)
Godhanded Aug 31, 2024
b4bf308
Feat: Implement Blog Management in Graphql (#375)
Godhanded Aug 31, 2024
96d4b44
feat: implement comment management in graphql
dorisjenny27 Aug 31, 2024
ae58b59
feat: implement contact us endpoints in graphql
dorisjenny27 Aug 31, 2024
bbadf08
feat: implement contact us endpoints in graphql
dorisjenny27 Aug 31, 2024
0d2e3ea
feat: implement subscription endpoints in graphql
dorisjenny27 Aug 31, 2024
92a893b
feat: implement subscription endpoints in graphql
dorisjenny27 Aug 31, 2024
3780c7a
subscriptions
dorisjenny27 Aug 31, 2024
17bb394
feat: implement admin endpoints in graphql
dorisjenny27 Aug 31, 2024
fd9fab4
feat: implement admin endpoints in graphql
dorisjenny27 Aug 31, 2024
6b9a8fd
feat(graphql):Implement Authentication resolvers
Godhanded Aug 31, 2024
644f456
feat(graphql): Implement HelpCenterTopics Resolvers
Godhanded Aug 31, 2024
ce24ade
chore(graphql): Cleanup
Godhanded Aug 31, 2024
f35cc29
Feature(graphql): Implement Resolvers for authentication and Help Cen…
Godhanded Aug 31, 2024
a2f85d7
Feat: Implement Comment Management in Graphql (#380)
Godhanded Aug 31, 2024
3e10b8d
Update Mutations.ContactUs.cs
Godhanded Aug 31, 2024
1f4a822
Feat: Implement Contact Us Endpoints in Graphql (#381)
Godhanded Aug 31, 2024
df3750a
Implement Admin management in Graphql (#382)
Godhanded Aug 31, 2024
83f2098
feat(graphql): implement newsletter subscription resolver
Godhanded Aug 31, 2024
b1902ae
ci: fix configuration credential issue
alexindevs Aug 31, 2024
ad679c1
Merge branch 'dev' of github.com:hngprojects/hng_boilerplate_csharp_w…
alexindevs Aug 31, 2024
9ad93c0
feat(graphql): Implement Notifications resolvers
Godhanded Aug 31, 2024
ffecfb6
feat(graphql): setup notification setting resolvers
Godhanded Aug 31, 2024
f2cd9c6
Feature(graphql):Implement Notification and newsletter query and muta…
Godhanded Aug 31, 2024
c77dec6
partialfix(Tests): fix login test
Godhanded Aug 31, 2024
41229dd
chore(tests): code formatting
Godhanded Aug 31, 2024
eb0d96b
partialfix(Tests): fix login test (#388)
Godhanded Aug 31, 2024
067df43
Revert "Added C-sharp Run Postman Tests"
Godhanded Sep 6, 2024
f954459
Revert "Added C-sharp Run Postman Tests" (#395)
Godhanded Sep 6, 2024
0f696d4
Merge branch 'staging' into dev
chimaihueze Sep 7, 2024
c41fad0
Merge branch 'main' into dev
chimaihueze Sep 7, 2024
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
33 changes: 0 additions & 33 deletions .github/workflows/c-sharp-postman-test.yaml

This file was deleted.

2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ WORKDIR /app

# Copy the published output from the publish stage
COPY --from=publish /app/publish .
# Copy the EmailTemplates folder
COPY src/Hng.Infrastructure/EmailTemplates /app/EmailTemplates

# Command to run the application
ENTRYPOINT ["dotnet", "Hng.Web.dll"]
11 changes: 10 additions & 1 deletion docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ services:
- postgres
- redis
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.17'
memory: 170M
reservations:
cpus: '0.08'
memory: 85M

nginx:
image: nginx:latest
Expand All @@ -22,6 +30,7 @@ services:
- backend
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
restart: unless-stopped

postgres:
image: postgres:latest
Expand All @@ -35,6 +44,6 @@ services:

redis:
image: redis:latest

restart: unless-stopped
volumes:
postgres_data:
8 changes: 8 additions & 0 deletions docker-compose.staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ services:
- postgres
- redis
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.17'
memory: 170M
reservations:
cpus: '0.08'
memory: 85M

nginx:
image: nginx:latest
Expand Down
8 changes: 8 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ services:
- postgres
- redis
restart: unless-stopped
deploy:
resources:
limits:
cpus: '0.17'
memory: 170M
reservations:
cpus: '0.08'
memory: 85M

nginx:
image: nginx:latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Hng.Application.Features.Blogs.Dtos;
using Hng.Application.Features.Blogs.Handlers;
using Hng.Application.Features.Blogs.Queries;
using Hng.Application.Features.SuperAdmin.Dto;
using Hng.Application.Features.UserManagement.Dtos;
using Hng.Domain.Entities;
using Hng.Domain.Enums;
using Hng.Infrastructure.Repository.Interface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public GetUsersBySearchQueryHandlerShould()
var config = new MapperConfiguration(cfg =>
{
// Add your AutoMapper profiles here
cfg.CreateMap<User, UserDto>();
cfg.CreateMap<User, UserSuperDto>();
});

_mapper = config.CreateMapper();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
using AutoMapper;
using Hng.Application.Features.UserManagement.Commands;
using Hng.Application.Features.UserManagement.Dtos;
using Hng.Application.Features.UserManagement.Handlers;
using Hng.Domain.Entities;
using Hng.Infrastructure.Repository.Interface;
using Hng.Infrastructure.Services.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Moq;
using System.Linq.Expressions;
using Xunit;

namespace Hng.Application.Test.Features.UserManagement
{
public class LoginUserCommandShould
{
private readonly IMapper _mapper;
private readonly Mock<IRepository<User>> _userRepositoryMock;
private readonly Mock<IRepository<LastLogin>> _lastLoginMock;
private readonly Mock<IPasswordService> _passwordServiceMock;
private readonly Mock<ITokenService> _tokenServiceMock;
private readonly User _user;
Expand All @@ -27,6 +34,7 @@ public LoginUserCommandShould()
_userRepositoryMock = new Mock<IRepository<User>>();
_passwordServiceMock = new Mock<IPasswordService>();
_tokenServiceMock = new Mock<ITokenService>();
_lastLoginMock = new Mock<IRepository<LastLogin>>();

_user = new User
{
Expand All @@ -35,24 +43,28 @@ public LoginUserCommandShould()
FirstName = "John",
LastName = "Doe",
Password = "hashedpassword",
PasswordSalt = "salt"
PasswordSalt = "salt",

};
}

//[Fact]
//public async Task ReturnLoginResponseDtoForValidCredentials()
//{
// // Arrange
// _userRepositoryMock.Setup(repo => repo.GetBySpec(It.IsAny<Expression<Func<User, bool>>>(), It.IsAny<Expression<Func<User, object>>[]>()))
// .ReturnsAsync(_user);
// _userRepositoryMock.Setup(repo => repo.GetQueryableBySpec(It.IsAny<Expression<Func<User, bool>>>())
// .Include(It.IsAny<Expression<Func<User, ICollection<Hng.Domain.Entities.Organization>>>>())
// .ThenInclude(It.IsAny<Expression<Func<Hng.Domain.Entities.Organization, ICollection<UserRole>>>>())
// .ThenInclude(It.IsAny<Expression<Func<UserRole,Role>>>())
// .Include(It.IsAny<Expression<Func<User,ICollection<Subscription>>>>()).FirstOrDefaultAsync<User>(CancellationToken.None)).ReturnsAsync(_user);

// _passwordServiceMock.Setup(service => service.IsPasswordEqual("password", _user.PasswordSalt, _user.Password))
// .Returns(true);

// _tokenServiceMock.Setup(service => service.GenerateJwt(It.IsAny<User>()))
// _tokenServiceMock.Setup(service => service.GenerateJwt(It.IsAny<User>(), 5))
// .Returns("token");

// var handler = new LoginUserCommandHandler(_userRepositoryMock.Object, _mapper, _passwordServiceMock.Object, _tokenServiceMock.Object);
// var handler = new LoginUserCommandHandler(_userRepositoryMock.Object,_lastLoginMock.Object, _mapper, _passwordServiceMock.Object, _tokenServiceMock.Object,new HttpContextAccessor());

// var command = new CreateUserLoginCommand(new UserLoginRequestDto
// {
Expand Down
2 changes: 1 addition & 1 deletion src/Hng.Application/Features/SuperAdmin/Dto/UserDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Hng.Application.Features.SuperAdmin.Dto
{
public class UserDto
public class UserSuperDto
{
[JsonPropertyName("id")]
public Guid Id { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Hng.Application.Features.SuperAdmin.Handlers
{
public class GetUsersBySearchQueryHandler : IRequestHandler<GetUsersBySearchQuery, PagedListDto<UserDto>>
public class GetUsersBySearchQueryHandler : IRequestHandler<GetUsersBySearchQuery, PagedListDto<UserSuperDto>>
{
private readonly IRepository<User> _userRepository;
private readonly IMapper _mapper;
Expand All @@ -19,15 +19,15 @@ public GetUsersBySearchQueryHandler(IRepository<User> userRepository, IMapper ma
_mapper = mapper;
}

public async Task<PagedListDto<UserDto>> Handle(GetUsersBySearchQuery request, CancellationToken cancellationToken)
public async Task<PagedListDto<UserSuperDto>> Handle(GetUsersBySearchQuery request, CancellationToken cancellationToken)
{
var users = await _userRepository.GetAllAsync();
users = users.Where(v => request.usersQueryParameters.Email == null || v.Email.ToLower().Equals(request.usersQueryParameters.Email.ToLower())).ToList();
users = users.Where(v => request.usersQueryParameters.Firstname == null || v.FirstName.ToLower().Equals(request.usersQueryParameters.Firstname.ToLower())).ToList();
users = users.Where(v => request.usersQueryParameters.Lastname == null || v.LastName.ToLower().Equals(request.usersQueryParameters.Lastname.ToLower())).ToList();

var mappedusers = _mapper.Map<IEnumerable<UserDto>>(users);
var userSearchResult = PagedListDto<UserDto>.ToPagedList(mappedusers, request.usersQueryParameters.Offset, request.usersQueryParameters.Limit);
var mappedusers = _mapper.Map<IEnumerable<UserSuperDto>>(users);
var userSearchResult = PagedListDto<UserSuperDto>.ToPagedList(mappedusers, request.usersQueryParameters.Offset, request.usersQueryParameters.Limit);

return userSearchResult;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class AdminUsersMappingProfile : AutoMapper.Profile
{
public AdminUsersMappingProfile()
{
CreateMap<User, UserDto>().ReverseMap();
CreateMap<User, UserSuperDto>().ReverseMap();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Hng.Application.Features.SuperAdmin.Queries
{
public class GetUsersBySearchQuery : IRequest<PagedListDto<UserDto>>
public class GetUsersBySearchQuery : IRequest<PagedListDto<UserSuperDto>>
{
public GetUsersBySearchQuery(UsersQueryParameters parameters)
{
Expand Down
73 changes: 73 additions & 0 deletions src/Hng.Graphql/Features/Mutations/Mutations.Authentication.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Hng.Application.Features.UserManagement.Commands;
using Hng.Application.Features.UserManagement.Dtos;
using HotChocolate.Authorization;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace Hng.Graphql
{
public partial class Mutations
{
public async Task<UserLoginResponseDto<SignupResponseData>> Login(UserLoginRequestDto loginRequest, [FromServices] IMediator mediator)
{
var command = new CreateUserLoginCommand(loginRequest);
return await mediator.Send(command);
}

public async Task<UserLoginResponseDto<SignupResponseData>> GoogleLogin(GoogleLoginRequestDto googleLoginRequest, [FromServices] IMediator mediator)
{
var command = new GoogleLoginCommand(googleLoginRequest.IdToken);
return await mediator.Send(command);
}

public async Task<SignUpResponse> UserSignUp(UserSignUpDto body, [FromServices] IMediator mediator)
{
var command = new UserSignUpCommand(body);
return await mediator.Send(command);
}

[Authorize]
public async Task<ChangePasswordResponse> ChangePassword([FromBody] ChangePasswordCommand command, [FromServices] IMediator mediator)
{
var response = await mediator.Send(command);
return response.Value;
}

public async Task<ForgotPasswordResponse> ForgotPassword([FromBody] ForgotPasswordRequestDto request, [FromServices] IMediator mediator)
{
var response = await mediator.Send(new ForgotPasswordDto(request.Email, false));
return response.Value;
}

public async Task<ForgotPasswordResponse> ForgotPasswordMobile([FromBody] ForgotPasswordRequestDto request, [FromServices] IMediator mediator)
{
var response = await mediator.Send(new ForgotPasswordDto(request.Email, true));
return response.Value;
}

public async Task<VerifyForgotPasswordCodeResponse> VerifyForgotPasswordCode([FromBody] VerifyForgotPasswordCodeDto request, [FromServices] IMediator mediator)
{
var response = await mediator.Send(request);
return response.Value;
}

public async Task<PasswordResetMobileResponse> PasswordResetMobile([FromBody] PasswordResetMobileDto request, [FromServices] IMediator mediator)
{
var respone = await mediator.Send(new PasswordResetMobileCommand(request));
return respone.Value;
}

[Authorize]
public async Task<PasswordResetResponse> PasswordReset([FromBody] PasswordResetDto request, [FromServices] IMediator mediator)
{
var response = await mediator.Send(request);
return response.Value;
}

public async Task<UserLoginResponseDto<object>> FacebookLogin([FromBody] FacebookLoginRequestDto request, [FromServices] IMediator mediator)
{
var command = new FacebookLoginCommand(request.AccessToken);
return await mediator.Send(command);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Hng.Application.Features.BillingPlans.Commands;
using Hng.Application.Features.BillingPlans.Dtos;
using Hng.Application.Features.BillingPlans.Queries;
using Hng.Application.Shared.Dtos;
using HotChocolate.Authorization;
using MediatR;
Expand Down
32 changes: 32 additions & 0 deletions src/Hng.Graphql/Features/Mutations/Mutations.Blog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Hng.Application.Features.Blogs.Commands;
using Hng.Application.Features.Blogs.Dtos;
using HotChocolate.Authorization;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace Hng.Graphql
{
public partial class Mutations
{
[Authorize]
public async Task<CreateBlogResponseDto> CreateBlog(CreateBlogDto body, [FromServices] IMediator mediator)
{
var command = new CreateBlogCommand(body);
return await mediator.Send(command);
}

[Authorize]
public async Task<bool> DeleteBlogById(Guid id, [FromServices] IMediator mediator)
{
var command = (new DeleteBlogByIdCommand(id));
return await mediator.Send(command);
}

[Authorize]
public async Task<UpdateBlogResponseDto> UpdateBlog(Guid id, UpdateBlogDto updateBlogDto, [FromServices] IMediator mediator)
{
var command = new UpdateBlogCommand(updateBlogDto, id);
return await mediator.Send(command);
}
}
}
27 changes: 27 additions & 0 deletions src/Hng.Graphql/Features/Mutations/Mutations.Categories.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Hng.Application.Features.Categories.Commands;
using Hng.Application.Features.Categories.Dtos;
using Hng.Application.Shared.Dtos;
using HotChocolate.Authorization;
using MediatR;
using Microsoft.AspNetCore.Mvc;

namespace Hng.Graphql
{
public partial class Mutations
{
[Authorize]
public async Task<SuccessResponseDto<CategoryDto>> CreateCategory(CreateCategoryDto createCategoryDto, [FromServices] IMediator mediator)
{
var command = new CreateCategoryCommand(createCategoryDto.Name, createCategoryDto.Description, createCategoryDto.Slug);
return await mediator.Send(command);
}

[Authorize]
public async Task<SuccessResponseDto<bool>> DeleteCategory(Guid id, [FromServices] IMediator mediator)
{
var command = new DeleteCategoryCommand(id);
return await mediator.Send(command);
}

}
}
Loading
Loading