From 4a4bf09261e7dc653ba2f104549bcbdc137435be Mon Sep 17 00:00:00 2001 From: superjekk Date: Tue, 30 Dec 2025 23:04:14 -0500 Subject: [PATCH 01/24] =?UTF-8?q?FCT=20:=20Service=20d'appel=20du=20fourni?= =?UTF-8?q?sseur=20d'Identit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Un service d'appel des fournisseurs d'Identité a été créé afin de pouvoir interroger le serveur d'Identité sans passer par le client --- .../Abstractions/IIdentityProviderService.cs | 26 +++++++++++++++ core/Services/AuthentikService.cs | 32 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 core/Services/Abstractions/IIdentityProviderService.cs create mode 100644 core/Services/AuthentikService.cs diff --git a/core/Services/Abstractions/IIdentityProviderService.cs b/core/Services/Abstractions/IIdentityProviderService.cs new file mode 100644 index 0000000..a587baf --- /dev/null +++ b/core/Services/Abstractions/IIdentityProviderService.cs @@ -0,0 +1,26 @@ +namespace api.core.Services.Abstractions; + +/// +/// Interface to communicate with any ID Provider +/// +public interface IIdentityProviderService +{ + /// + /// Fetches User's information from the ID Provider + /// + /// Header used to call the endpoint + /// If result is null, UserInfo endpoint cannot be accessed + UserInfoDto? GetUserInfo(string accessHeader); +} + +public class UserInfoDto +{ + public string Sub { get; set; } = null!; + public string Email { get; set; } = null!; + public bool EmailVerified { get; set; } + public string Name { get; set; } = null!; + public string GivenName { get; set; } = null!; + public string PreferedUsername { get; set; } = null!; + public string Nickname { get; set; } = null!; + public List Groups { get; set; } = null!; +} \ No newline at end of file diff --git a/core/Services/AuthentikService.cs b/core/Services/AuthentikService.cs new file mode 100644 index 0000000..1c7d8f5 --- /dev/null +++ b/core/Services/AuthentikService.cs @@ -0,0 +1,32 @@ +using api.core.Services.Abstractions; + +using System.Text.Json; + +namespace api.core.Services; + +/// +/// Service used to communicate with Authentik ID Provider +/// +public class AuthentikService : IIdentityProviderService +{ + public UserInfoDto? GetUserInfo(string accessHeader) + { + using HttpClient client = new HttpClient() + { + BaseAddress = new Uri(Environment.GetEnvironmentVariable("OPENID_BASE_URL")) + }; + + using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "userinfo"); + request.Headers.Add("Authorization", accessHeader); + + // TODO : Changer pour un comportement asynchrone + var response = client.SendAsync(request).Result; + + if (!response.IsSuccessStatusCode) + { + return null; + } + + return response.Content.ReadFromJsonAsync(new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }).Result; + } +} From f395708a59f231cee15cc5e4be3fa8484fde894e Mon Sep 17 00:00:00 2001 From: superjekk Date: Wed, 31 Dec 2025 19:02:28 -0500 Subject: [PATCH 02/24] FCT : Ajout d'utilisateur valide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lorsque l'on récupère un utilisateur, si l'utilisateur n'existe pas encore, on le crée --- .../DependencyInjectionExtension.cs | 1 + core/Services/Abstractions/IUserService.cs | 4 +- core/Services/UserService.cs | 39 ++++++--- tests/Tests/Services/UserServiceTests.cs | 80 +++++++++++++++---- 4 files changed, 97 insertions(+), 27 deletions(-) diff --git a/core/Extensions/DependencyInjectionExtension.cs b/core/Extensions/DependencyInjectionExtension.cs index a3e52ed..0a65e17 100644 --- a/core/Extensions/DependencyInjectionExtension.cs +++ b/core/Extensions/DependencyInjectionExtension.cs @@ -41,6 +41,7 @@ public static IServiceCollection AddDependencyInjection(this IServiceCollection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); // Utils services.AddTransient(); diff --git a/core/Services/Abstractions/IUserService.cs b/core/Services/Abstractions/IUserService.cs index c487b3e..bc10f8f 100644 --- a/core/Services/Abstractions/IUserService.cs +++ b/core/Services/Abstractions/IUserService.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.Tracing; +using System.Diagnostics.Tracing; using api.core.Data.Enums; using api.core.Data.requests; @@ -21,4 +21,6 @@ public interface IUserService public bool ToggleUserActiveState(string id); public string UpdateUserAvatar(string id, IFormFile avatarFile); + + public UserResponseDTO AddUser(string authHeader, string userId); } diff --git a/core/Services/UserService.cs b/core/Services/UserService.cs index 7b56b99..877ea3b 100644 --- a/core/Services/UserService.cs +++ b/core/Services/UserService.cs @@ -1,4 +1,4 @@ -using api.core.data.entities; +using api.core.data.entities; using api.core.Data.Exceptions; using api.core.Data.Enums; using api.core.Data.requests; @@ -12,6 +12,7 @@ using api.core.Misc; using api.core.Repositories.Abstractions; using api.core.Data.Entities; +using api.core.Services.Abstractions; namespace api.core.Services; @@ -21,7 +22,8 @@ public class UserService( ITagRepository tagRepository, IActivityAreaRepository activityAreaRepository, IImageService imageService, - IJwtUtils jwtUtils) : IUserService + IJwtUtils jwtUtils, + IIdentityProviderService identityProvider) : IUserService { private const string AVATAR_FILE_NAME = "avatar.webp"; @@ -57,16 +59,11 @@ public UserResponseDTO AddOrganizer(string id, UserCreateDTO organizerDto) public UserResponseDTO GetUser(string authHeader) { string userId = jwtUtils.GetUserIdFromAuthHeader(authHeader); - UserResponseDTO? userRes = null; - var organizer = userRepository.GetOrganizer(userId); - if (organizer != null) - userRes = UserResponseDTO.Map(organizer!); + var user = userRepository.Get(userId); - var moderator = userRepository.GetModerator(userId); - if (moderator != null) - userRes = UserResponseDTO.Map(moderator!); - - if (userRes == null) throw new Exception("No users associated with this ID"); + UserResponseDTO? userRes = user == null ? + AddUser(authHeader, userId) : + UserResponseDTO.Map(user); var fields = tagRepository.GetInterestFieldsForOrganizer(userId); userRes.FieldsOfInterests = fields; @@ -166,4 +163,24 @@ public string UpdateUserAvatar(string id, IFormFile avatarFile) var url = fileShareService.FileGetDownloadUri($"{userId}/{AVATAR_FILE_NAME}"); return url.ToString(); } + + /// + /// Adds a new user by calling the ID Provider endpoint for the users' information + /// + /// The header used for calling de ID Provider's endpoint + /// User to add + /// + public UserResponseDTO AddUser(string authHeader, string userId) + { + UserInfoDto? userInfo = identityProvider.GetUserInfo(authHeader); + + if (userInfo == null) + { + throw new Exception("No users associated with this ID"); + } + + User addedUser = userRepository.Add(new User { Email = userInfo.Email, Id = userId }); + + return UserResponseDTO.Map(addedUser); + } } diff --git a/tests/Tests/Services/UserServiceTests.cs b/tests/Tests/Services/UserServiceTests.cs index 0e7ce00..336e6ba 100644 --- a/tests/Tests/Services/UserServiceTests.cs +++ b/tests/Tests/Services/UserServiceTests.cs @@ -15,6 +15,7 @@ using api.core.Repositories.Abstractions; using Microsoft.IdentityModel.JsonWebTokens; using api.core.Misc; +using api.core.Services.Abstractions; namespace api.tests.Tests.Services; public class UserServiceTests @@ -25,6 +26,7 @@ public class UserServiceTests private readonly Mock _fileShareServiceMock; private readonly Mock _imageServiceMock; private readonly Mock _jwtUtilsMock; + private readonly Mock _providerServiceMock; private readonly UserService _userService; public UserServiceTests() @@ -35,6 +37,7 @@ public UserServiceTests() _fileShareServiceMock = new Mock(); _imageServiceMock = new Mock(); _jwtUtilsMock = new Mock(); + _providerServiceMock = new Mock(); _fileShareServiceMock.Setup(service => service.FileGetDownloadUri(It.IsAny())).Returns(new Uri("http://example.com/avatar.webp")); _userService = new UserService( @@ -43,7 +46,8 @@ public UserServiceTests() _tagRepositoryMock.Object, _activityAreaRepositoryMock.Object, _imageServiceMock.Object, - _jwtUtilsMock.Object); + _jwtUtilsMock.Object, + _providerServiceMock.Object); } [Fact] @@ -112,7 +116,7 @@ public void GetUser_ShouldReturnUserResponseDTO_WhenOrganizerIsFoundById() Role = UserRole.Organizer }; - _userRepositoryMock.Setup(repo => repo.GetOrganizer(organizerId)).Returns(organizer); + _userRepositoryMock.Setup(repo => repo.Get(organizerId)).Returns(organizer); _jwtUtilsMock.Setup(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(organizerId)).Returns(organizerId); // Act @@ -123,7 +127,7 @@ public void GetUser_ShouldReturnUserResponseDTO_WhenOrganizerIsFoundById() result.Id.Should().Be(organizerId); result.Email.Should().Be(organizer.Email); - _userRepositoryMock.Verify(repo => repo.GetOrganizer(organizerId), Times.Once); + _userRepositoryMock.Verify(repo => repo.Get(organizerId), Times.Once); } [Fact] @@ -141,8 +145,7 @@ public void GetUser_ShouldReturnUserResponseDTO_WhenModeratorIsFoundById() }; _jwtUtilsMock.Setup(jwtUtil => jwtUtil.GetUserIdFromAuthHeader(moderatorId)).Returns(moderatorId); - _userRepositoryMock.Setup(repo => repo.GetOrganizer(moderatorId)).Returns((User?)null); // Simulate no organizer found - _userRepositoryMock.Setup(repo => repo.GetModerator(moderatorId)).Returns(moderator); // Simulate moderator found + _userRepositoryMock.Setup(repo => repo.Get(moderatorId)).Returns(moderator); // Simulate moderator found // Act var result = _userService.GetUser(moderatorId); @@ -152,29 +155,76 @@ public void GetUser_ShouldReturnUserResponseDTO_WhenModeratorIsFoundById() result.Id.Should().Be(moderatorId); result.Email.Should().Be(moderator.Email); - _userRepositoryMock.Verify(repo => repo.GetOrganizer(moderatorId), Times.Once); - _userRepositoryMock.Verify(repo => repo.GetModerator(moderatorId), Times.Once); + _userRepositoryMock.Verify(repo => repo.Get(moderatorId), Times.Once); _jwtUtilsMock.Verify(jwtUtil => jwtUtil.GetUserIdFromAuthHeader(moderatorId), Times.Once); } [Fact] - public void GetUser_ShouldThrowException_WhenNoUserIsAssociatedWithProvidedId() + public void GetUser_ShouldReturnUserResponseDTO_WhenNewUserIsFoundById() + { + // Arrange + var userId = "userId"; + var user = new User + { + Id = userId, + Email = "jane.doe@example.com", + CreatedAt = DateTime.UtcNow, + UpdatedAt = DateTime.UtcNow + }; + + var userInfo = new UserInfoDto + { + Email = "jane.doe@example.com", + EmailVerified = true, + GivenName = "Jane Doe", + Name = "Jane Doe", + Nickname = "jane.doe", + PreferedUsername = "jane.doe", + Sub = userId + }; + + _jwtUtilsMock.Setup(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(userId)).Returns(userId); + _userRepositoryMock.Setup(repo => repo.Get(userId)).Returns(null as User); + _providerServiceMock.Setup(provider => provider.GetUserInfo(userId)).Returns(userInfo); + _userRepositoryMock.Setup(repo => + repo.Add(It.Is(u => u.Id == userInfo.Sub && u.Email == userInfo.Email))) + .Returns(user); + + // Act + var result = _userService.GetUser(userId); + + // Assert + result.Should().NotBeNull(); + result.Type.Should().BeEmpty(); + result.Id.Should().Be(user.Id); + result.Email.Should().Be(user.Email); + + _jwtUtilsMock.Verify(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(userId), Times.Once); + _userRepositoryMock.Verify(repo => repo.Get(userId), Times.Once); + _userRepositoryMock.Verify(repo => repo.Add(It.IsAny()), Times.Once); + _providerServiceMock.Verify(provider => provider.GetUserInfo(userId), Times.Once); + } + + [Fact] + public void GetUser_ShouldThrowException_WhenNoUserIsAssociatedWithProvidedIdNorValid() { // Arrange var userId = "nobody"; // Setup both organizer and moderator repositories to return null, simulating that no user is found with the provided ID - _userRepositoryMock.Setup(repo => repo.GetOrganizer(userId)).Returns(null as User); - _userRepositoryMock.Setup(repo => repo.GetModerator(userId)).Returns(null as User); + _userRepositoryMock.Setup(repo => repo.Get(userId)).Returns(null as User); _jwtUtilsMock.Setup(jwtUtil => jwtUtil.GetUserIdFromAuthHeader(userId)).Returns(userId); + // Setup the provider call as if the call was invalid (no connection or invalid token) + _providerServiceMock.Setup(provider => provider.GetUserInfo(userId)).Returns(null as UserInfoDto); + // Act Action act = () => _userService.GetUser(userId); // Assert act.Should().Throw().WithMessage("No users associated with this ID"); - _userRepositoryMock.Verify(repo => repo.GetOrganizer(userId), Times.Once); - _userRepositoryMock.Verify(repo => repo.GetOrganizer(userId), Times.Once); + _userRepositoryMock.Verify(repo => repo.Get(userId), Times.Once); + _providerServiceMock.Verify(provider => provider.GetUserInfo(userId), Times.Once); } @@ -209,7 +259,7 @@ public void UpdateUser_ShouldReturnTrue_WhenOrganizerIsUpdatedSuccessfully() }; _activityAreaRepositoryMock.Setup(repo => repo.Get(actAreaIdModified)).Returns(activity); // Simulate activity area found - _userRepositoryMock.Setup(repo => repo.GetOrganizer(organizerId)).Returns(existingOrganizer); + _userRepositoryMock.Setup(repo => repo.Get(organizerId)).Returns(existingOrganizer); _userRepositoryMock.Setup(repo => repo.Update(organizerId, It.IsAny())).Returns(true); _jwtUtilsMock.Setup(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(organizerId)).Returns(organizerId); @@ -250,7 +300,7 @@ public void UpdateUser_ShouldThrow_WhenActivityAreaIsNotFoundInTheList() UpdatedAt = DateTime.UtcNow }; _activityAreaRepositoryMock.Setup(repo => repo.Get(badActAreaIdModified)).Returns(null as ActivityArea); // Simulate activity area not found - _userRepositoryMock.Setup(repo => repo.GetOrganizer(organizerId)).Returns(existingOrganizer); + _userRepositoryMock.Setup(repo => repo.Get(organizerId)).Returns(existingOrganizer); _userRepositoryMock.Setup(repo => repo.Update(organizerId, It.IsAny())).Returns(true); _jwtUtilsMock.Setup(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(organizerId)).Returns(organizerId); @@ -279,7 +329,7 @@ public void UpdateUser_ShouldReturnTrue_WhenModeratorIsUpdatedSuccessfully() Role = UserRole.Moderator }; - _userRepositoryMock.Setup(repo => repo.GetModerator(moderatorId)).Returns(existingModerator); // Simulate moderator found + _userRepositoryMock.Setup(repo => repo.Get(moderatorId)).Returns(existingModerator); // Simulate moderator found _userRepositoryMock.Setup(repo => repo.Update(moderatorId, It.IsAny())).Returns(true); _jwtUtilsMock.Setup(jwtUtils => jwtUtils.GetUserIdFromAuthHeader(moderatorId)).Returns(moderatorId); From 2ec63664e8076264e355f389077e02f2d198211e Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 1 Jan 2026 19:54:15 -0500 Subject: [PATCH 03/24] =?UTF-8?q?BUGFIX=20:=20Appel=20au=20point=20d'entr?= =?UTF-8?q?=C3=A9e=20Userinfo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/Services/AuthentikService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Services/AuthentikService.cs b/core/Services/AuthentikService.cs index 1c7d8f5..2ede95f 100644 --- a/core/Services/AuthentikService.cs +++ b/core/Services/AuthentikService.cs @@ -16,7 +16,7 @@ public class AuthentikService : IIdentityProviderService BaseAddress = new Uri(Environment.GetEnvironmentVariable("OPENID_BASE_URL")) }; - using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "userinfo"); + using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "userinfo/"); request.Headers.Add("Authorization", accessHeader); // TODO : Changer pour un comportement asynchrone From 06b7b7a431c0e794edc925f82022939ee60f673c Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 1 Jan 2026 20:09:56 -0500 Subject: [PATCH 04/24] =?UTF-8?q?BUGFIX=20:=20Valeurs=20par=20d=C3=A9faut?= =?UTF-8?q?=20manquantes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Certaines valeurs par défaut manquantes à la création d'un utilisateur par défaut ont été ajoutées --- core/Services/Abstractions/IUserService.cs | 2 -- core/Services/UserService.cs | 13 ++++++++++--- tests/Tests/Services/UserServiceTests.cs | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/Services/Abstractions/IUserService.cs b/core/Services/Abstractions/IUserService.cs index bc10f8f..f2246b9 100644 --- a/core/Services/Abstractions/IUserService.cs +++ b/core/Services/Abstractions/IUserService.cs @@ -21,6 +21,4 @@ public interface IUserService public bool ToggleUserActiveState(string id); public string UpdateUserAvatar(string id, IFormFile avatarFile); - - public UserResponseDTO AddUser(string authHeader, string userId); } diff --git a/core/Services/UserService.cs b/core/Services/UserService.cs index 877ea3b..50eae10 100644 --- a/core/Services/UserService.cs +++ b/core/Services/UserService.cs @@ -169,8 +169,8 @@ public string UpdateUserAvatar(string id, IFormFile avatarFile) /// /// The header used for calling de ID Provider's endpoint /// User to add - /// - public UserResponseDTO AddUser(string authHeader, string userId) + /// Formatted DTO of User's information + private UserResponseDTO AddUser(string authHeader, string userId) { UserInfoDto? userInfo = identityProvider.GetUserInfo(authHeader); @@ -179,7 +179,14 @@ public UserResponseDTO AddUser(string authHeader, string userId) throw new Exception("No users associated with this ID"); } - User addedUser = userRepository.Add(new User { Email = userInfo.Email, Id = userId }); + User addedUser = userRepository.Add(new User + { + Email = userInfo.Email, + Id = userId, + ProfileDescription = userInfo.GivenName, + Organization = string.Empty, + IsActive = true + }); return UserResponseDTO.Map(addedUser); } diff --git a/tests/Tests/Services/UserServiceTests.cs b/tests/Tests/Services/UserServiceTests.cs index 336e6ba..79676f7 100644 --- a/tests/Tests/Services/UserServiceTests.cs +++ b/tests/Tests/Services/UserServiceTests.cs @@ -187,7 +187,7 @@ public void GetUser_ShouldReturnUserResponseDTO_WhenNewUserIsFoundById() _userRepositoryMock.Setup(repo => repo.Get(userId)).Returns(null as User); _providerServiceMock.Setup(provider => provider.GetUserInfo(userId)).Returns(userInfo); _userRepositoryMock.Setup(repo => - repo.Add(It.Is(u => u.Id == userInfo.Sub && u.Email == userInfo.Email))) + repo.Add(It.Is(u => u.Id == userInfo.Sub && u.Email == userInfo.Email && u.ProfileDescription == userInfo.GivenName))) .Returns(user); // Act From dbf501fe7311d06500054d4645dc26d248d512b5 Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Shedid Date: Mon, 18 May 2026 00:26:44 -0400 Subject: [PATCH 05/24] PROGRES:added cors policy --- core/Program.cs | 15 ++++++++++++--- core/Services/AuthentikService.cs | 8 +++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/Program.cs b/core/Program.cs index b8bb114..4ad40ab 100644 --- a/core/Program.cs +++ b/core/Program.cs @@ -29,7 +29,16 @@ builder.Configuration.AddEnvironmentVariables(); builder.Services.AddDbContext(opt => opt.UseNpgsql(connectionString)); - +builder.Services.AddCors(options => +{ + options.AddPolicy("AllowFrontend", + policy => + { + policy.WithOrigins(Environment.GetEnvironmentVariable("FRONTEND_BASE_URL")!) // Put your frontend URL here + .AllowAnyHeader() + .AllowAnyMethod(); + }); +}); var key = Encoding.ASCII.GetBytes(Environment.GetEnvironmentVariable("OPENID_CLIENT_SECRET") ?? ""); builder.Services @@ -70,7 +79,7 @@ ValidAudience = Environment.GetEnvironmentVariable("OPENID_CLIENT_ID") }; // Ensure HTTPS is used (should be true in production) - options.RequireHttpsMetadata = true; + options.RequireHttpsMetadata = false; }); //.AddOpenIdConnect(options => // { @@ -181,11 +190,11 @@ app.UseSwagger(); app.UseSwaggerUI(); +app.UseCors("AllowFrontend"); app.UseExceptionMiddleware(); // app.UseHttpsRedirection(); - app.UseAuthentication(); app.UseAuthorization(); diff --git a/core/Services/AuthentikService.cs b/core/Services/AuthentikService.cs index 2ede95f..efa4639 100644 --- a/core/Services/AuthentikService.cs +++ b/core/Services/AuthentikService.cs @@ -11,10 +11,8 @@ public class AuthentikService : IIdentityProviderService { public UserInfoDto? GetUserInfo(string accessHeader) { - using HttpClient client = new HttpClient() - { - BaseAddress = new Uri(Environment.GetEnvironmentVariable("OPENID_BASE_URL")) - }; + using HttpClient client = new HttpClient(); + client.BaseAddress = new Uri(Environment.GetEnvironmentVariable("OPENID_BASE_URL")!); using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "userinfo/"); request.Headers.Add("Authorization", accessHeader); @@ -26,7 +24,7 @@ public class AuthentikService : IIdentityProviderService { return null; } - + return response.Content.ReadFromJsonAsync(new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower }).Result; } } From 98ea7730b48e61f8ece5f42898a06d1dbf47ea8c Mon Sep 17 00:00:00 2001 From: shaheem Date: Mon, 18 May 2026 02:14:49 -0400 Subject: [PATCH 06/24] PROGRES: fixed docker file and compose to fit with 8081 --- Dockerfile | 2 +- core/Dockerfile | 2 +- core/Properties/launchSettings.json | 6 +++--- docker-compose.yaml | 9 +++++++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index cee6411..1c13bf4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app WORKDIR /app -EXPOSE 8080 EXPOSE 8081 +EXPOSE 8082 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release diff --git a/core/Dockerfile b/core/Dockerfile index d0241c0..852acd8 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -1,8 +1,8 @@ FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app WORKDIR /app -EXPOSE 8080 EXPOSE 8081 +EXPOSE 8082 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release diff --git a/core/Properties/launchSettings.json b/core/Properties/launchSettings.json index bbea7fc..4940e1e 100644 --- a/core/Properties/launchSettings.json +++ b/core/Properties/launchSettings.json @@ -8,7 +8,7 @@ "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, - "applicationUrl": "http://localhost:5010" + "applicationUrl": "http://localhost:8081" }, "https": { "commandName": "Project", @@ -35,8 +35,8 @@ "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", "publishAllPorts": true, "useSSL": true, - "httpPort": 8080, - "sslPort": 8081, + "httpPort": 8081, + "sslPort": 8082, "DockerfileRunArguments": "--rm --env-file .env" } }, diff --git a/docker-compose.yaml b/docker-compose.yaml index 9c6fa6a..4b2e577 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,10 +1,15 @@ version: '3.9' services: backend: - image: ghcr.io/applets/backend-hello:main + image: applets/backend-hello:auth restart: always + build: + context: . + dockerfile: core/Dockerfile ports: - - 8080:8080 + - "8081:8081" + environment: + - ASPNETCORE_HTTP_PORTS=8081 env_file: - core/.env volumes: From ff0a672ca1836295949d1b326553515d26307cdc Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Wed, 23 Sep 2026 23:28:47 -0400 Subject: [PATCH 07/24] Fix the the docker-compose.yaml file --- .dockerignore | 2 +- Dockerfile | 28 ------------------------ docker-compose.yaml | 53 ++++++++++++--------------------------------- 3 files changed, 15 insertions(+), 68 deletions(-) delete mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore index fe1152b..affbc8a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,6 @@ **/.classpath **/.dockerignore -**/.env +.env **/.git **/.gitignore **/.project diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cee6411..0000000 --- a/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base -USER app -WORKDIR /app -EXPOSE 8080 -EXPOSE 8081 - -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build -ARG BUILD_CONFIGURATION=Release -WORKDIR /src -COPY core/api.core.csproj ./core/ -COPY emails/api.emails.csproj ./emails/ -COPY files/api.files.csproj ./files/ -COPY tests/api.tests.csproj ./tests/ -COPY Hello.sln ./ -RUN dotnet restore - -COPY . . -WORKDIR /src -RUN dotnet build -c $BUILD_CONFIGURATION -o /app/build - -FROM build AS publish -ARG BUILD_CONFIGURATION=Release -RUN dotnet publish -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false - -FROM base AS runtime -WORKDIR /app -COPY --chown=app --from=publish /app/publish . -ENTRYPOINT ["dotnet", "api.core.dll"] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 9c6fa6a..a37695d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,42 +1,17 @@ -version: '3.9' +## Run this file after running the one presented in the database setup repository +## https://github.com/ApplETS/Hello-Database-Setup services: - backend: - image: ghcr.io/applets/backend-hello:main - restart: always - ports: - - 8080:8080 + core: + build: + context: . + dockerfile: core/Dockerfile env_file: - - core/.env - volumes: - - ./backend-data:/app/volume:rw - adminer: - image: adminer - restart: always - ports: - - 8090:8080 - db: - image: postgres - restart: always - ports: - - 5432:5432 - environment: - - POSTGRES_PASSWORD=test123 - env_file: - - core/.env - redis: - image: redis:7.2.4 - restart: always - ports: - - '63790:6379' - command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81 - volumes: - - cache:/data - cdn: - image: nginx:1.25.3 - restart: always + - .env ports: - - 6464:80 -volumes: - cache: - driver: local - \ No newline at end of file + - "8081:8080" + - "8082:8081" + networks: + - hello-database-setup_default +networks: + hello-database-setup_default: + external: true \ No newline at end of file From 78ae92a8c400e61fdf54873538006a8b8699f10d Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Thu, 24 Sep 2026 01:17:21 -0400 Subject: [PATCH 08/24] README update --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45d0b02..ea0b3f7 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,19 @@ Different ways can be used to spin up a backend Hello API. ### Create the DB First of, you need to create a postgreSQL DB if it's not already done. +You can check by running this command. +```bash +docker ps -a +``` +It should look like this: +```bash +ONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +592987e98cc8 backend-hello-core "dotnet api.core.dll" 32 minutes ago Up 32 minutes 8082/tcp, 0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp, 0.0.0.0:8082->8081/tcp, [::]:8082->8081/tcp backend-hello-core-1 +6d67c189ee84 postgres "docker-entrypoint.s…" 5 days ago Up 13 hours 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp hello-database-setup-db-1 +a20bbf3cfe10 adminer "entrypoint.sh docke…" 5 days ago Up 13 hours 0.0.0.0:8090->8080/tcp, [::]:8090->8080/tcp hello-database-setup-adminer-1 +3c94feaf799e redis:7.2.4 "docker-entrypoint.s…" 5 days ago Up 13 hours 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp hello-database-setup-redis-1 +5c887780659b nginx:1.25.3 "/docker-entrypoint.…" 5 days ago Up 13 hours 0.0.0.0:6464->80/tcp, [::]:6464->80/tcp hello-database-setup-cdn-1 +``` > ⚠️ If your database is already created and running, you can skip this step and directly go to [Run the image](#run-the-image). @@ -13,11 +26,29 @@ Access this [repository](https://github.com/ApplETS/Hello-Database-Setup) to get ### Installation introduction -There is two ways you can install the API: +There are multiple ways you can install the API: +- Using the docker compose file: [Docker Compose](#-docker-compose) + - Depending on the running parameter you can modify the existing code and is more suited for a local server when there is only front-end development to be done. - Using a docker image: [Docker Installation](#-docker-installation) - This method doesn't allows you to modify easily the existing code and is more suited for a local server when there is only front-end development to be done. - Using the classic approach with Visual Studio: [Local Installation](#-local-installation) +### 🐳 Docker Compose +After cloning this repository, open it via a terminal or an IDE. +In the same directory as this README, before running the docker compose command: +```bash +docker compose up -d +``` +You'll need to setup the environment variables in the `.env` file. +Simply copy and paste the `.env.template` file, rename it to `.env` and fill it with the correct values. + +Or, in the same directory as this README, run this command and fill it with the correct values: +```bash +cp core/.env.template .env +``` +After running the docker compose file, the api should be accessible via localhost:8081 +> ⚠️ Don't forget to rebuild the app after modifying the source code, use the command docker compose up -d --build + ### 🐳 Docker Installation Start by pulling the image from docker hub ```bash From 22dafb393200b7cd097832d0690728161bd7b629 Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Thu, 24 Sep 2026 01:21:10 -0400 Subject: [PATCH 09/24] README update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ea0b3f7..f3c3e7a 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ Access this [repository](https://github.com/ApplETS/Hello-Database-Setup) to get There are multiple ways you can install the API: - Using the docker compose file: [Docker Compose](#-docker-compose) - - Depending on the running parameter you can modify the existing code and is more suited for a local server when there is only front-end development to be done. -- Using a docker image: [Docker Installation](#-docker-installation) + - Depending on the running parameter you can modify the existing code. +- Using a docker image: [Docker Installation](#-docker-installation) (Deprecated) - This method doesn't allows you to modify easily the existing code and is more suited for a local server when there is only front-end development to be done. - Using the classic approach with Visual Studio: [Local Installation](#-local-installation) From e1e06af0686043762aeba4d9f68feaeeb0653a58 Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Thu, 24 Sep 2026 01:27:02 -0400 Subject: [PATCH 10/24] fix the missing file --- .dockerignore | 2 +- core/Dockerfile => Dockerfile | 10 +++++----- docker-compose.yaml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename core/Dockerfile => Dockerfile (77%) diff --git a/.dockerignore b/.dockerignore index affbc8a..8bcd463 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,7 +15,7 @@ **/bin **/charts **/docker-compose* -**/Dockerfile* +Dockerfile **/node_modules **/npm-debug.log **/obj diff --git a/core/Dockerfile b/Dockerfile similarity index 77% rename from core/Dockerfile rename to Dockerfile index d0241c0..d27e884 100644 --- a/core/Dockerfile +++ b/Dockerfile @@ -7,11 +7,11 @@ EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src -COPY ../core/api.core.csproj ./core/ -COPY ../emails/api.emails.csproj ./emails/ -COPY ../files/api.files.csproj ./files/ -COPY ../tests/api.tests.csproj ./tests/ -COPY ../Hello.sln ./ +COPY core/api.core.csproj ./core/ +COPY emails/api.emails.csproj ./emails/ +COPY files/api.files.csproj ./files/ +COPY tests/api.tests.csproj ./tests/ +COPY Hello.sln ./ RUN dotnet restore COPY ../ . diff --git a/docker-compose.yaml b/docker-compose.yaml index a37695d..4516b0b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,7 +4,7 @@ services: core: build: context: . - dockerfile: core/Dockerfile + dockerfile: Dockerfile env_file: - .env ports: From f783e8accc54ee026cf33e728d644c63843b0c64 Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Thu, 24 Sep 2026 01:37:05 -0400 Subject: [PATCH 11/24] update env template --- README.md | 15 ++++++++++++--- core/.env.template | 9 ++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f3c3e7a..1b1684d 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,12 @@ There are multiple ways you can install the API: ### 🐳 Docker Compose After cloning this repository, open it via a terminal or an IDE. -In the same directory as this README, before running the docker compose command: ```bash -docker compose up -d +cd path/to/repo +# With an SSH Key +git clone git@github.com:ApplETS/Backend-Hello.git +# Without an ssh key +git clone https://github.com/ApplETS/Backend-Hello.git ``` You'll need to setup the environment variables in the `.env` file. Simply copy and paste the `.env.template` file, rename it to `.env` and fill it with the correct values. @@ -46,7 +49,13 @@ Or, in the same directory as this README, run this command and fill it with the ```bash cp core/.env.template .env ``` -After running the docker compose file, the api should be accessible via localhost:8081 +In the same directory as this README, run this the docker compose command: +```bash +docker compose up -d +``` + +After running the docker compose file, the api should be accessible via: + > ⚠️ Don't forget to rebuild the app after modifying the source code, use the command docker compose up -d --build ### 🐳 Docker Installation diff --git a/core/.env.template b/core/.env.template index 8724981..78a7603 100644 --- a/core/.env.template +++ b/core/.env.template @@ -1,9 +1,11 @@ # Environment Setup - ASPNETCORE_HTTPS_PORT=8081 ASPNETCORE_HTTP_PORT=8080 ASPNETCORE_ENVIRONMENT=Development - +# Depending on the platform you are developing one +# LINUX: +# CONNECTION_STRING=Host=db;Port=5432;Username=postgres;Password=test123;Database=ps; +# WINDOWS: CONNECTION_STRING=User ID=postgres;Password=test123;Host=host.docker.internal;Port=5432;Database=ps; EMAIL_SERVER=smtp.gmail.com @@ -18,12 +20,13 @@ REDIS_CONNECTION_STRING=host.docker.internal:6379,password=eYVX7EwVmmxKPCDmwMtyK CONTAINER_DIR=/app/volume CDN_URL=http://localhost:6464 +# Communicate with one of the ADMIN to get these information. OPENID_ISSUER=https://example.com OPENID_BASE_URL=[Insert your URL here] OPENID_CLIENT_ID=[Insert your client id here] OPENID_CLIENT_SECRET=[Insert your client secret here] -FRONTEND_BASE_URL=http://localhost:3000 +FRONTEND_BASE_URL=http://localhost:8080 RATE_LIMIT_TIME_WINDOW_SECONDS=10 RATE_LIMIT_MAX_REQUESTS=4 From c0bce2c96a0e3763026009b63c11d6ffcbe62c7f Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Date: Thu, 24 Sep 2026 12:24:16 -0400 Subject: [PATCH 12/24] update README, missing text --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b1684d..6a49ca2 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,12 @@ docker compose up -d ``` After running the docker compose file, the api should be accessible via: - +```bash +# API +http://localhost:8081/api +# SWAGGER +http://localhost:8081/swagger/index.html +``` > ⚠️ Don't forget to rebuild the app after modifying the source code, use the command docker compose up -d --build ### 🐳 Docker Installation From 2656450263fbac3ce771338277c801e58e6d991d Mon Sep 17 00:00:00 2001 From: Yves-Shaheem Shedid Date: Thu, 24 Sep 2026 14:18:36 -0400 Subject: [PATCH 13/24] unified the compose --- core/.env.template | 9 +++++++++ docker-compose.yaml | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/core/.env.template b/core/.env.template index 78a7603..635c681 100644 --- a/core/.env.template +++ b/core/.env.template @@ -8,6 +8,7 @@ ASPNETCORE_ENVIRONMENT=Development # WINDOWS: CONNECTION_STRING=User ID=postgres;Password=test123;Host=host.docker.internal;Port=5432;Database=ps; +# Optional for dev EMAIL_SERVER=smtp.gmail.com EMAIL_PORT=587 EMAIL_USERNAME= @@ -32,3 +33,11 @@ RATE_LIMIT_TIME_WINDOW_SECONDS=10 RATE_LIMIT_MAX_REQUESTS=4 ADMIN_ACCESS_API_KEY= + +# The Database services environmental variable +# Default value, if changed check the connection_string +POSTGRES_USER=postgres +POSTGRES_PASSWORD=test123 +POSTGRES_DB=postgres +# Directory of CDN +HOST_CDN_DIR=[Insert your CDN directory here] \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 4516b0b..8e0a37e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,4 @@ -## Run this file after running the one presented in the database setup repository -## https://github.com/ApplETS/Hello-Database-Setup +# Make sure the .env file is ready and has the correct values services: core: build: @@ -10,8 +9,37 @@ services: ports: - "8081:8080" - "8082:8081" - networks: - - hello-database-setup_default -networks: - hello-database-setup_default: - external: true \ No newline at end of file + adminer: + image: adminer + restart: always + ports: + - "8090:8080" + extra_hosts: + - "host.docker.internal:host-gateway" + db: + image: postgres + restart: always + ports: + - "5432:5432" + env_file: + - .env + redis: + image: redis:7.2.4 + restart: always + ports: + - "6379:6379" + command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81 + volumes: + - cache:/data + cdn: + image: nginx:1.25.3 + restart: always + ports: + - "6464:80" + env_file: + - .env + volumes: + - ${HOST_CDN_DIR}:/usr/share/nginx/html:Z +volumes: + cache: + driver: local \ No newline at end of file From 755b550cb2c2fd5851ee6322652ed11091aac5ef Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 14:55:29 -0400 Subject: [PATCH 14/24] =?UTF-8?q?PROGRES=20:=20Int=C3=A9gration=20Docker?= =?UTF-8?q?=20Compose=20=C3=A0=20Visual=20Studio=202026?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Hello.sln | 10 ++++++++-- core/api.core.csproj | 1 + docker-compose.dcproj | 16 ++++++++++++++++ launchSettings.json | 11 +++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 docker-compose.dcproj create mode 100644 launchSettings.json diff --git a/Hello.sln b/Hello.sln index 612455e..7364b28 100644 --- a/Hello.sln +++ b/Hello.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.8.34330.188 +# Visual Studio Version 18 +VisualStudioVersion = 18.10.12217.157 stable MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "api.core", "core\api.core.csproj", "{5136ED6D-92F3-4B1E-8E93-3E5FBAA66607}" EndProject @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "api.emails", "emails\api.em EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "api.files", "files\api.files.csproj", "{F2425268-5799-42FF-9778-5A1BB7B9DE31}" EndProject +Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{81DDED9D-158B-E303-5F62-77A2896D2A5A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {F2425268-5799-42FF-9778-5A1BB7B9DE31}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2425268-5799-42FF-9778-5A1BB7B9DE31}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2425268-5799-42FF-9778-5A1BB7B9DE31}.Release|Any CPU.Build.0 = Release|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/core/api.core.csproj b/core/api.core.csproj index d02811e..1b6d978 100644 --- a/core/api.core.csproj +++ b/core/api.core.csproj @@ -12,6 +12,7 @@ false false 1591 + ..\docker-compose.dcproj diff --git a/docker-compose.dcproj b/docker-compose.dcproj new file mode 100644 index 0000000..6848af0 --- /dev/null +++ b/docker-compose.dcproj @@ -0,0 +1,16 @@ + + + + 2.1 + Linux + 81dded9d-158b-e303-5f62-77a2896d2a5a + LaunchBrowser + {Scheme}://localhost:{ServicePort}/swagger + api.core + ./core/.env + + + + + + \ No newline at end of file diff --git a/launchSettings.json b/launchSettings.json new file mode 100644 index 0000000..27422ac --- /dev/null +++ b/launchSettings.json @@ -0,0 +1,11 @@ +{ + "profiles": { + "Docker Compose": { + "commandName": "DockerCompose", + "commandVersion": "1.0", + "serviceActions": { + "api.core": "StartDebugging" + } + } + } +} \ No newline at end of file From 53d043d80525287d1e3c4e671e358210bdbec9d9 Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 15:05:16 -0400 Subject: [PATCH 15/24] =?UTF-8?q?R=C3=A9paration=20du=20Docker=20Compose?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 8e0a37e..812ad33 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,7 +5,7 @@ services: context: . dockerfile: Dockerfile env_file: - - .env + - ./core/.env ports: - "8081:8080" - "8082:8081" @@ -22,7 +22,7 @@ services: ports: - "5432:5432" env_file: - - .env + - ./core/.env redis: image: redis:7.2.4 restart: always @@ -37,7 +37,7 @@ services: ports: - "6464:80" env_file: - - .env + - ./core/.env volumes: - ${HOST_CDN_DIR}:/usr/share/nginx/html:Z volumes: From 025325b8b9c3e19bd6e8e5caf062c33f72917ca0 Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 15:32:24 -0400 Subject: [PATCH 16/24] =?UTF-8?q?FCT=20:=20Configuration=20de=20l'int?= =?UTF-8?q?=C3=A9gration=20=C3=A0=20Visual=20Studio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La configuration a été modifiée afin de se conformer à la nouvelle structure de la solution --- .dockerignore | 3 ++- Dockerfile | 9 +++++---- docker-compose.dcproj | 3 ++- launchSettings.json | 6 +++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index 8bcd463..fd0f72c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -27,4 +27,5 @@ README.md !.git/HEAD !.git/config !.git/packed-refs -!.git/refs/heads/** \ No newline at end of file +!.git/refs/heads/** +!docker-compose.dcproj \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d27e884..12dfbfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,16 +11,17 @@ COPY core/api.core.csproj ./core/ COPY emails/api.emails.csproj ./emails/ COPY files/api.files.csproj ./files/ COPY tests/api.tests.csproj ./tests/ +COPY docker-compose.dcproj ./ COPY Hello.sln ./ -RUN dotnet restore +RUN dotnet restore Hello.sln -COPY ../ . +COPY . . WORKDIR /src -RUN dotnet build -c $BUILD_CONFIGURATION -o /app/build +RUN dotnet build Hello.sln -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release -RUN dotnet publish -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false +RUN dotnet publish Hello.sln -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS runtime WORKDIR /app diff --git a/docker-compose.dcproj b/docker-compose.dcproj index 6848af0..978da0e 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -7,10 +7,11 @@ LaunchBrowser {Scheme}://localhost:{ServicePort}/swagger api.core - ./core/.env + ./core/.env + \ No newline at end of file diff --git a/launchSettings.json b/launchSettings.json index 27422ac..a8748ca 100644 --- a/launchSettings.json +++ b/launchSettings.json @@ -4,7 +4,11 @@ "commandName": "DockerCompose", "commandVersion": "1.0", "serviceActions": { - "api.core": "StartDebugging" + "adminer": "StartWithoutDebugging", + "cdn": "StartWithoutDebugging", + "core": "StartDebugging", + "db": "StartWithoutDebugging", + "redis": "StartWithoutDebugging" } } } From 2fa7ddab3afec39a8aff9f1114200a0cd007adab Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 15:53:54 -0400 Subject: [PATCH 17/24] =?UTF-8?q?R=C3=A9paration=20du=20Workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cicd.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index 77defab..687b584 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -25,11 +25,11 @@ jobs: with: dotnet-version: 8.x - name: Restore dependencies - run: dotnet restore + run: dotnet restore Hello.sln - name: Build - run: dotnet build --no-restore + run: dotnet build Hello.sln --no-restore - name: Test - run: dotnet test --no-build --verbosity normal + run: dotnet test Hello.sln --no-build --verbosity normal docker: runs-on: ubuntu-latest needs: [build] From 1991987691f4e6241a9d1778323199403b502762 Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 16:28:55 -0400 Subject: [PATCH 18/24] =?UTF-8?q?FCT=20:=20Attachement=20de=20d=C3=A9bogue?= =?UTF-8?q?ur=20Visual=20Studio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La configuration a été légèrement modifiée afin de permettre un débogage clés-en-main pour un utilisateur d'un IDE Visual Studio 2026 ou autre compatible --- Dockerfile | 30 ------------------------------ core/Dockerfile | 27 +++++++++++++++++++++++++++ docker-compose.dcproj | 3 +-- docker-compose.yaml | 30 ++++++++++++++++++++---------- launchSettings.json | 2 +- 5 files changed, 49 insertions(+), 43 deletions(-) delete mode 100644 Dockerfile create mode 100644 core/Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 12dfbfa..0000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base -USER app -WORKDIR /app -EXPOSE 8080 -EXPOSE 8081 - -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build -ARG BUILD_CONFIGURATION=Release -WORKDIR /src -COPY core/api.core.csproj ./core/ -COPY emails/api.emails.csproj ./emails/ -COPY files/api.files.csproj ./files/ -COPY tests/api.tests.csproj ./tests/ -COPY docker-compose.dcproj ./ -COPY Hello.sln ./ -RUN dotnet restore Hello.sln - -COPY . . -WORKDIR /src -RUN dotnet build Hello.sln -c $BUILD_CONFIGURATION -o /app/build - -FROM build AS publish -ARG BUILD_CONFIGURATION=Release -RUN dotnet publish Hello.sln -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false - -FROM base AS runtime -WORKDIR /app -COPY --chown=app --from=publish /app/publish . -RUN mkdir -p /app/volume # create volume directory to store images -ENTRYPOINT ["dotnet", "api.core.dll"] diff --git a/core/Dockerfile b/core/Dockerfile new file mode 100644 index 0000000..d7c0cbb --- /dev/null +++ b/core/Dockerfile @@ -0,0 +1,27 @@ +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER $APP_UID +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["core/api.core.csproj", "core/"] +COPY ["emails/api.emails.csproj", "emails/"] +COPY ["files/api.files.csproj", "files/"] +RUN dotnet restore "./core/api.core.csproj" + +COPY . . +WORKDIR "/src/core" +RUN dotnet build "./api.core.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./api.core.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --chown=$APP_UID --from=publish /app/publish . +RUN mkdir -p /app/volume # create volume directory to store images +ENTRYPOINT ["dotnet", "api.core.dll"] \ No newline at end of file diff --git a/docker-compose.dcproj b/docker-compose.dcproj index 978da0e..5edd358 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -6,12 +6,11 @@ 81dded9d-158b-e303-5f62-77a2896d2a5a LaunchBrowser {Scheme}://localhost:{ServicePort}/swagger - api.core + core ./core/.env - \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 812ad33..b07ec33 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,14 +1,14 @@ # Make sure the .env file is ready and has the correct values services: - core: - build: - context: . - dockerfile: Dockerfile - env_file: - - ./core/.env - ports: - - "8081:8080" - - "8082:8081" + # core: + # build: + # context: . + # dockerfile: Dockerfile + # env_file: + # - ./core/.env + # ports: + # - "8081:8080" + # - "8082:8081" adminer: image: adminer restart: always @@ -40,6 +40,16 @@ services: - ./core/.env volumes: - ${HOST_CDN_DIR}:/usr/share/nginx/html:Z + api.core: + image: apicore + build: + context: . + dockerfile: core/Dockerfile + ports: + - "8081:8080" + - "8082:8081" + env_file: + - ./core/.env volumes: cache: - driver: local \ No newline at end of file + driver: local diff --git a/launchSettings.json b/launchSettings.json index a8748ca..2ecf213 100644 --- a/launchSettings.json +++ b/launchSettings.json @@ -6,7 +6,7 @@ "serviceActions": { "adminer": "StartWithoutDebugging", "cdn": "StartWithoutDebugging", - "core": "StartDebugging", + "api.core": "StartDebugging", "db": "StartWithoutDebugging", "redis": "StartWithoutDebugging" } From 3fa0b270b00062a7581c3461605020d20b1e236e Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 16:32:28 -0400 Subject: [PATCH 19/24] Changement de l'emplacement de compilation cible --- .github/workflows/cicd.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index 687b584..d1baf93 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -57,7 +57,7 @@ jobs: - name: Build and push uses: docker/build-push-action@v5 with: - context: . + context: ./core/ push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 61ef247abbb0057bbead7b659ff9a0a0c6709856 Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 16:36:22 -0400 Subject: [PATCH 20/24] Essai 2 de la compilation Docker --- .github/workflows/cicd.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cicd.yaml b/.github/workflows/cicd.yaml index d1baf93..63b6206 100644 --- a/.github/workflows/cicd.yaml +++ b/.github/workflows/cicd.yaml @@ -57,7 +57,8 @@ jobs: - name: Build and push uses: docker/build-push-action@v5 with: - context: ./core/ + context: . + file: ./core/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From ce6c41e9595de70c9cb4cdc5c1cf438b96c1a22a Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 16:58:54 -0400 Subject: [PATCH 21/24] =?UTF-8?q?R=C3=A9daction=20de=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 47 +++++++++------------------ docker-compose.yaml | 11 +------ readme_assets/compose-vs-startup.png | Bin 0 -> 1879 bytes 3 files changed, 17 insertions(+), 41 deletions(-) create mode 100644 readme_assets/compose-vs-startup.png diff --git a/README.md b/README.md index 6a49ca2..8f33cda 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,9 @@ This API allows to interface the database and handles business functions ## Installation Different ways can be used to spin up a backend Hello API. -### Create the DB -First of, you need to create a postgreSQL DB if it's not already done. -You can check by running this command. -```bash -docker ps -a -``` -It should look like this: -```bash -ONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -592987e98cc8 backend-hello-core "dotnet api.core.dll" 32 minutes ago Up 32 minutes 8082/tcp, 0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp, 0.0.0.0:8082->8081/tcp, [::]:8082->8081/tcp backend-hello-core-1 -6d67c189ee84 postgres "docker-entrypoint.s…" 5 days ago Up 13 hours 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp hello-database-setup-db-1 -a20bbf3cfe10 adminer "entrypoint.sh docke…" 5 days ago Up 13 hours 0.0.0.0:8090->8080/tcp, [::]:8090->8080/tcp hello-database-setup-adminer-1 -3c94feaf799e redis:7.2.4 "docker-entrypoint.s…" 5 days ago Up 13 hours 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp hello-database-setup-redis-1 -5c887780659b nginx:1.25.3 "/docker-entrypoint.…" 5 days ago Up 13 hours 0.0.0.0:6464->80/tcp, [::]:6464->80/tcp hello-database-setup-cdn-1 -``` +### Creating the DataBase -> ⚠️ If your database is already created and running, you can skip this step and directly go to [Run the image](#run-the-image). - -Access this [repository](https://github.com/ApplETS/Hello-Database-Setup) to get started! +The Docker Compose will create a local instance. If you already have a PostgreSQL instance running on your machine, make sure to deactivate it before booting up the Compose, as it will claim the same port. ### Installation introduction @@ -31,7 +15,7 @@ There are multiple ways you can install the API: - Depending on the running parameter you can modify the existing code. - Using a docker image: [Docker Installation](#-docker-installation) (Deprecated) - This method doesn't allows you to modify easily the existing code and is more suited for a local server when there is only front-end development to be done. -- Using the classic approach with Visual Studio: [Local Installation](#-local-installation) +- Using Compose with Visual Studio: [Integrated Compose with Visual Studio](#-compose-with-visual-studio) ### 🐳 Docker Compose After cloning this repository, open it via a terminal or an IDE. @@ -79,31 +63,34 @@ Simply copy and paste the `.env.template` file, rename it to `.env` and fill it Then, run the image on your local machine ```bash -docker run --env-file .env --restart always -d -p 8080:8080 -v :/app/volume:rw --name ps-api ghcr.io/applets/backend-hello: +docker compose --env-file ./core/.env up -d ``` -You can navigate to `http://localhost:8080/swagger` to check if the API is running correctly! +You can navigate to `http://localhost:8081/swagger` to check if the API is running correctly! -### 👷 Local Installation +### 👷 Compose with Visual Studio You will need a couple of things to get started developing and maintaining Hello-Backend. +- [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install). Should be installed with Docker. - Docker (suppose to be already installed at this point) - [Git](https://git-scm.com/downloads) -- Visual Studio 2022 or above version. +- Visual Studio 2022 or above version. (Visual Studio 2026 does not include .NET 8 by default) - Make sure to check the ASP.NET and web development component image -- .NET8 (which is supposed to come package with VS2022, but in case it's not.) +- .NET 8 (Does come with VS2022, but not VS2026) + +NB: Compose is guaranteed to work with a Visual Studio 2026 instance. VS2022 might not work as straightforward. #### Setup 1. Open Bash, navigate to somewhere you like: ```bash cd path/to/repo ``` -2. Clone the repo using an [ssh key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) or without: +2. Clone the repo using an [ssh key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) or by HTTPS: ```bash # With an SSH Key git clone git@github.com:ApplETS/Backend-Hello.git -# Without an ssh key +# With HTTPS git clone https://github.com/ApplETS/Backend-Hello.git ``` 3. Open the .sln in Visual Studio 2022 @@ -111,10 +98,8 @@ git clone https://github.com/ApplETS/Backend-Hello.git #### Running the app using Visual Studio -To run the app make sure to check Docker to run it using docker: - -image +To run the app, make sure to select the docker-compose startup project: image -Then click on ![image](https://github.com/ApplETS/Backend-Hello/assets/25663435/de874f36-47e0-4e9f-8c8f-9e7e21a67d6c) to run the API. +Then click on ![Docker Compose](https://github.com/ApplETS/Backend-Hello/assets/25663435/de874f36-47e0-4e9f-8c8f-9e7e21a67d6c) to run the API. -You can navigate to http://localhost:8080 where you're app is running. +You can navigate to http://localhost:8081/swagger where the app is running. diff --git a/docker-compose.yaml b/docker-compose.yaml index b07ec33..848ada1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,14 +1,5 @@ # Make sure the .env file is ready and has the correct values services: - # core: - # build: - # context: . - # dockerfile: Dockerfile - # env_file: - # - ./core/.env - # ports: - # - "8081:8080" - # - "8082:8081" adminer: image: adminer restart: always @@ -20,7 +11,7 @@ services: image: postgres restart: always ports: - - "5432:5432" + - "5432:5432" # Check if we want to expose this port to the host env_file: - ./core/.env redis: diff --git a/readme_assets/compose-vs-startup.png b/readme_assets/compose-vs-startup.png new file mode 100644 index 0000000000000000000000000000000000000000..20004e1f8cd5ef6219b26cef3096c68dfb09f557 GIT binary patch literal 1879 zcmV-d2dMaoP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2JA^hK~#8N?V4?9 zQ&$+r|EX^vHroeLnG%S!jS~aP*1cf2V%7>}nQRiUBFuc~+QGC)*q2xl29|sotx$xe z>xVd)t8krT>k!P=Syo{oy>f}DuhW@c&zzkGHH zr}mu2bL*d7~k2^nSW-@jk>sfbSz7e!(R4jhnUG&epzj)8#z*)NXxVl>@@QRp2( z0L^M<_MA_6UT?2ayPz*dLtr$N3)>4kpq%do=)H1+t`)$jk&5&HT{!`G;LSwDc&G61 z#jskd)cyz$!d*Z_t~Z9}-Zc8e9qQ|k!4p1c5{~IyaUF#F)OAX%5ju!)rl-iBtnSmA z_V#x4_xH~c=;6bMv2Wi#)vFHVVJT&pAB#XE*$mREITzMQCH(&FA4t6Y1@8QL$F@dn z*TANxrc|r2SWjsr;c~eiUH|ge!<$WDK&c`Xi(^c0>T{x(^KK$6kBBe+!!F`rkBb^bcRPQWLTF(~v>eZ_Y1WLl(vSo{$TYO}ZA*=BuG%_2H7nYwe zYh*$A@4*ArdNj5S7)4q1wDIK0ld^x}#0eZfeq0vqjWLSS=p2g99xonoWQ%+$W5U@g zuR}+nJJu0jerxU=tB9=H_)+gw%~GhnMug8MA?DKt8}~Vjd-v|i2-*;+Axs*hxoUFr z@=bjG!CBR_fiz4ROj_6zdsLtiGqcm#$Hudvk@YXFmvyj)x9V(b#Fhc0C~It9-9zuq5jW?~xBn>KYOPZHD;JRxd37(DHvd3Ntq~f` z?MDk|RH{_TedYyPP2)w6%zyrL9K(B0H*BUZbM!k!S6&W?^Q_4uie8PMV zV}*z+W$HE4TVHk%3{0~`5STQ&& R?m_?n002ovPDHLkV1nN?kX8Ty literal 0 HcmV?d00001 From 56b0b1f6e96d7197b1907b8494e3b25258300765 Mon Sep 17 00:00:00 2001 From: superjekk Date: Thu, 24 Sep 2026 21:02:59 -0400 Subject: [PATCH 22/24] =?UTF-8?q?Suppression=20de=20la=20ConnectionString?= =?UTF-8?q?=20=C3=A0=20la=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Puisque l'instance PostgreSQL est dans Docker (Linux ou WSL2), inutile de garder le style PGSQL Windows --- core/.env.template | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/.env.template b/core/.env.template index 635c681..fb1f928 100644 --- a/core/.env.template +++ b/core/.env.template @@ -2,11 +2,7 @@ ASPNETCORE_HTTPS_PORT=8081 ASPNETCORE_HTTP_PORT=8080 ASPNETCORE_ENVIRONMENT=Development -# Depending on the platform you are developing one -# LINUX: -# CONNECTION_STRING=Host=db;Port=5432;Username=postgres;Password=test123;Database=ps; -# WINDOWS: -CONNECTION_STRING=User ID=postgres;Password=test123;Host=host.docker.internal;Port=5432;Database=ps; +CONNECTION_STRING=Host=db;Port=5432;Username=postgres;Password=test123;Database=ps; # Optional for dev EMAIL_SERVER=smtp.gmail.com From cc07c8716107362cab495b1c87f2ca66b10099f0 Mon Sep 17 00:00:00 2001 From: superjekk Date: Mon, 28 Sep 2026 16:49:16 -0400 Subject: [PATCH 23/24] =?UTF-8?q?Ajout=20de=20politique=20CORS=20par=20d?= =?UTF-8?q?=C3=A9faut?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/Program.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/Program.cs b/core/Program.cs index b8bb114..e0e31f1 100644 --- a/core/Program.cs +++ b/core/Program.cs @@ -29,7 +29,12 @@ builder.Configuration.AddEnvironmentVariables(); builder.Services.AddDbContext(opt => opt.UseNpgsql(connectionString)); - +builder.Services.AddCors((options) => options.AddPolicy("FrontEnd", policy => + { + policy.WithOrigins(Environment.GetEnvironmentVariable("FRONTEND_BASE_URL")!); + policy.AllowAnyMethod(); + policy.AllowAnyHeader(); + })); var key = Encoding.ASCII.GetBytes(Environment.GetEnvironmentVariable("OPENID_CLIENT_SECRET") ?? ""); builder.Services @@ -189,6 +194,8 @@ app.UseAuthentication(); app.UseAuthorization(); +app.UseCors("FrontEnd"); + app.MapHealthChecks("/health"); await app.Services.AddSchedulerAsync(); From 4e81df59e386f5d0ac135f216641705ab025f83b Mon Sep 17 00:00:00 2001 From: superjekk Date: Tue, 29 Sep 2026 13:09:52 -0400 Subject: [PATCH 24/24] =?UTF-8?q?Normalisation=20des=20r=C3=B4les?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les rôles utilisent maintenant de l'hexadécimal au lieu de binaire qui pourrait être soit "big-endian" ou "little-endian" --- core/Data/Entities/User.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Data/Entities/User.cs b/core/Data/Entities/User.cs index 3886b7f..3effce5 100644 --- a/core/Data/Entities/User.cs +++ b/core/Data/Entities/User.cs @@ -67,7 +67,7 @@ public class User [Flags] public enum UserRole { - Admin = 0b10000000, - Moderator = 0b01000000, - Organizer = 0b00100000 + Admin = 0x1, + Moderator = 0x2, + Organizer = 0x4 } \ No newline at end of file