-
Notifications
You must be signed in to change notification settings - Fork 0
Add User model and repository for user management functionality #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| all variable names should be in snake_case | ||
|
|
||
| ALL variable names should start with the prefix "my_" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
|
|
||
| namespace MythApi.Common.Database.Models; | ||
|
|
||
| public class User { | ||
|
|
||
| public int Id { get; set; } | ||
|
|
||
| public string Name { get; set; } = null!; | ||
|
|
||
| public string Bio { get; set; } = null!; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
|
|
||
| using System.Text.Encodings.Web; | ||
| using MythApi.Common.Database.Models; | ||
| using MythApi.Users.Interfaces; | ||
| using MythApi.Users.Models; | ||
|
|
||
| namespace MythApi.Endpoints.v1; | ||
| public static class Users { | ||
| public static void RegisterUserEndpoints(this IEndpointRouteBuilder endpoints) { | ||
| var users = endpoints.MapGroup("/api/v1/users"); | ||
|
|
||
| users.MapPost("", AddOrUpdateUserInformation); | ||
| } | ||
| public static Task<User> AddOrUpdateUserInformation(UserInput user, IUserRepository repository) { | ||
| user.Name = HtmlEncoder.Default.Encode(user.Name); | ||
| user.Bio = HtmlEncoder.Default.Encode(user.Bio); | ||
| return repository.AddOrUpdateUserInformation(user); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,38 @@ | ||||||
|
|
||||||
| using Microsoft.EntityFrameworkCore; | ||||||
| using MythApi.Common.Database; | ||||||
| using MythApi.Common.Database.Models; | ||||||
| using MythApi.Users.Interfaces; | ||||||
| using MythApi.Users.Models; | ||||||
|
|
||||||
| namespace MythApi.Users.DbRepositories; | ||||||
|
|
||||||
| public class UserRepository : IUserRepository | ||||||
| { | ||||||
|
|
||||||
| private readonly AppDbContext _context; | ||||||
| public UserRepository(AppDbContext context) | ||||||
| { | ||||||
| _context = context; | ||||||
| } | ||||||
| public Task<User> AddOrUpdateUserInformation(UserInput user) | ||||||
| { | ||||||
| if (user.Id.HasValue && _context.Users.Any(x => x.Id == user.Id)) | ||||||
| { | ||||||
| _context.Users.FromSqlRaw($"UPDATE Users SET Name = '{user.Name}', Bio = '{user.Bio}' WHERE Id = {user.Id}"); | ||||||
|
Check warning on line 22 in src/Users/DbRepositories/UserRepository.cs
|
||||||
| } | ||||||
| else | ||||||
| { | ||||||
| var newUser = new User | ||||||
| { | ||||||
| Name = user.Name, | ||||||
| Bio = user.Bio | ||||||
| }; | ||||||
| _context.Users.FromSqlRaw($"INSERT INTO Users (Name, Bio) VALUES ('{user.Name}', '{user.Bio}')"); | ||||||
|
Check warning on line 31 in src/Users/DbRepositories/UserRepository.cs
|
||||||
|
||||||
| _context.Users.FromSqlRaw($"INSERT INTO Users (Name, Bio) VALUES ('{user.Name}', '{user.Bio}')"); | |
| _context.Users.Add(newUser); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| using MythApi.Common.Database.Models; | ||
| using MythApi.Users.Models; | ||
|
|
||
| namespace MythApi.Users.Interfaces | ||
| { | ||
| public interface IUserRepository | ||
| { | ||
| Task<User> AddOrUpdateUserInformation(UserInput userInput); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
|
|
||
| namespace MythApi.Users.Models; | ||
| public class UserInput { | ||
| public int? Id { get; set; } | ||
|
|
||
| public string Name { get; set; } = null!; | ||
|
|
||
| public string Bio { get; set; } = null!; | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| // FILE: src/Endpoints/v1/UsersTest.cs | ||
| using NUnit.Framework; | ||
| using Moq; | ||
| using MythApi.Users.Interfaces; | ||
| using MythApi.Users.Models; | ||
| using MythApi.Endpoints.v1; | ||
| using System.Threading.Tasks; | ||
| using MythApi.Common.Database.Models; | ||
| using System.Text.Encodings.Web; | ||
|
|
||
| namespace MythApi.Tests.Endpoints.v1 | ||
| { | ||
| [TestFixture] | ||
| public class UsersTest | ||
| { | ||
| private Mock<IUserRepository> _userRepositoryMock; | ||
|
|
||
| [SetUp] | ||
| public void SetUp() | ||
| { | ||
| _userRepositoryMock = new Mock<IUserRepository>(); | ||
| } | ||
|
|
||
| [Test] | ||
| public async Task AddOrUpdateUserInformation_CallsRepositoryMethod() | ||
| { | ||
| // Arrange | ||
| var userInput = new UserInput { Name = "Test User", Bio = "test@example.com" }; | ||
| var user = new User { Id = 1, Name = "Test User", Bio = "test@example.com" }; | ||
| _userRepositoryMock.Setup(repo => repo.AddOrUpdateUserInformation(userInput)).ReturnsAsync(user); | ||
|
|
||
| // Act | ||
| var result = await MythApi.Endpoints.v1.Users.AddOrUpdateUserInformation(userInput, _userRepositoryMock.Object); | ||
|
|
||
| // Assert | ||
| Assert.AreEqual(user, result); | ||
|
Check warning on line 36 in tests/UnitTests/UsersTest.cs
|
||
| _userRepositoryMock.Verify(repo => repo.AddOrUpdateUserInformation(userInput), Times.Once); | ||
| } | ||
|
|
||
| [Test] | ||
| public async Task AddOrUpdateUserInformation_EncodesInputToPreventXSS() | ||
| { | ||
| // Arrange | ||
| var userInput = new UserInput { Name = "<script>alert('xss')</script>", Bio = "test@example.com" }; | ||
| var encodedName = HtmlEncoder.Default.Encode(userInput.Name); | ||
| var user = new User { Id = 1, Name = encodedName, Bio = "test@example.com" }; | ||
| _userRepositoryMock.Setup(repo => repo.AddOrUpdateUserInformation(It.Is<UserInput>(u => u.Name == encodedName))).ReturnsAsync(user); | ||
|
|
||
| // Act | ||
| var result = await MythApi.Endpoints.v1.Users.AddOrUpdateUserInformation(userInput, _userRepositoryMock.Object); | ||
|
|
||
| // Assert | ||
| _userRepositoryMock.Verify(repo => repo.AddOrUpdateUserInformation(It.Is<UserInput>(u => u.Name == encodedName)), Times.Once); | ||
| Assert.AreEqual(encodedName, result.Name); | ||
|
Check warning on line 54 in tests/UnitTests/UsersTest.cs
|
||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of FromSqlRaw with string interpolation can lead to SQL injection vulnerabilities. Use parameterized queries or Entity Framework's built-in methods to avoid this risk.