Skip to content

Commit 55e6b83

Browse files
authored
Merge pull request #65 from ApplETS/feature/fusion-utilisateurs
Fusion des utilisateurs
2 parents 633c467 + 25bc06c commit 55e6b83

60 files changed

Lines changed: 1794 additions & 861 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/dotnet-tools.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"csharpier": {
6+
"version": "0.30.6",
7+
"commands": [
8+
"dotnet-csharpier"
9+
],
10+
"rollForward": false
11+
}
12+
}
13+
}

core/.env.template

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ ASPNETCORE_HTTP_PORT=8080
55
ASPNETCORE_ENVIRONMENT=Development
66

77
CONNECTION_STRING=User ID=postgres;Password=test123;Host=host.docker.internal;Port=5432;Database=ps;
8-
SUPABASE_PROJECT_ID=
9-
SUPABASE_SECRET_KEY=
10-
SUPABASE_ANON_KEY=
118

129
EMAIL_SERVER=smtp.gmail.com
1310
EMAIL_PORT=587
@@ -21,6 +18,11 @@ REDIS_CONNECTION_STRING=host.docker.internal:6379,password=eYVX7EwVmmxKPCDmwMtyK
2118
CONTAINER_DIR=/app/volume
2219
CDN_URL=http://localhost:6464
2320

21+
OPENID_ISSUER=https://example.com
22+
OPENID_BASE_URL=[Insert your URL here]
23+
OPENID_CLIENT_ID=[Insert your client id here]
24+
OPENID_CLIENT_SECRET=[Insert your client secret here]
25+
2426
FRONTEND_BASE_URL=http://localhost:3000
2527

2628
RATE_LIMIT_TIME_WINDOW_SECONDS=10

core/Controllers/DraftEventsController.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace api.core.Controllers;
2828
[ApiController]
2929
[Authorize(Policy = AuthPolicies.OrganizerIsActive)]
3030
[Route("api/organizer-drafts")] // TODO : Change route to /api/me/drafts
31-
public class DraftEventsController(ILogger<DraftEventsController> logger, IDraftEventService draftService) : ControllerBase
31+
public class DraftEventsController(ILogger<DraftEventsController> logger, IDraftEventService draftService, IJwtUtils jwtUtils) : ControllerBase
3232
{
3333
/// <summary>
3434
/// Add a draft event to the database. This event will be saved as a draft and will not be visible
@@ -41,7 +41,7 @@ public IActionResult AddDraft([FromForm] DraftEventRequestDTO draftEvent)
4141
{
4242
logger.LogInformation($"Adding new draft");
4343

44-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
44+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
4545
var evnt = draftService.AddDraftEvent(userId, draftEvent);
4646

4747
return new OkObjectResult(
@@ -61,7 +61,7 @@ public IActionResult AddDraft([FromForm] DraftEventRequestDTO draftEvent)
6161
[HttpPatch("{id}")] // TODO: Change this to a HttpPut instead
6262
public IActionResult UpdateDraft(Guid id, [FromForm] DraftEventRequestDTO draftEvent)
6363
{
64-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
64+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
6565
return draftService.UpdateDraftEvent(userId, id, draftEvent) ? Ok() : BadRequest();
6666
}
6767
}

core/Controllers/EventsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class EventsController(
4646
public ActionResult<IEnumerable<EventResponseDTO>> GetEvents(
4747
[FromQuery] DateTime? startDate,
4848
[FromQuery] DateTime? endDate,
49-
[FromQuery] Guid? organizerId,
49+
[FromQuery] string? organizerId,
5050
[FromQuery] string? title,
5151
[FromQuery] IEnumerable<Guid>? activityAreas,
5252
[FromQuery] IEnumerable<Guid>? tags,

core/Controllers/MeController.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ namespace api.core.controllers;
1818
/// your JWT token.
1919
/// </summary>
2020
/// <param name="userService">The User Service will allows managing your user's data</param>
21+
/// <param name="jwtUtils">The JWT Utils allow to retrieve the ID from the user</param>
2122
[Authorize]
2223
[ApiController]
2324
[Route("api/me")]
24-
public class MeController(IUserService userService) : ControllerBase
25+
public class MeController(IUserService userService, IJwtUtils jwtUtils) : ControllerBase
2526
{
2627
/// <summary>
2728
/// Get the user connected to the API using the JWT token
@@ -30,8 +31,8 @@ public class MeController(IUserService userService) : ControllerBase
3031
[HttpGet]
3132
public IActionResult GetUser()
3233
{
33-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
34-
var organizer = userService.GetUser(userId);
34+
//var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers.Authorization!);
35+
var organizer = userService.GetUser(Request.Headers.Authorization!);
3536

3637
return new OkObjectResult(
3738
new Response<UserResponseDTO>
@@ -48,7 +49,7 @@ public IActionResult GetUser()
4849
[HttpPatch]
4950
public IActionResult UpdateUser([FromBody] UserUpdateDTO user)
5051
{
51-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
52+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
5253
return userService.UpdateUser(userId, user) ? Ok() : BadRequest();
5354
}
5455

@@ -60,7 +61,7 @@ public IActionResult UpdateUser([FromBody] UserUpdateDTO user)
6061
[HttpPatch("avatar")]
6162
public IActionResult UpdateUserAvatar([FromForm] UserAvatarUpdateDTO avatarReq)
6263
{
63-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
64+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
6465
var url = userService.UpdateUserAvatar(userId, avatarReq.avatarFile);
6566

6667
return new OkObjectResult(

core/Controllers/ModeratorEventsController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ namespace api.core.Controllers;
2525
public class ModeratorEventsController(
2626
ILogger<ModeratorEventsController> logger,
2727
IEventService eventService,
28-
IUserService userService) : ControllerBase
28+
IUserService userService,
29+
IJwtUtils jwtUtils) : ControllerBase
2930
{
3031
/// <summary>
3132
/// Update the state of an event. This is used for a moderator that needs to
@@ -41,7 +42,7 @@ public class ModeratorEventsController(
4142
[HttpPatch("{id}/state")]
4243
public IActionResult UpdateEventState(Guid id, [FromQuery] State newState, [FromQuery] string? reason)
4344
{
44-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
45+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
4546
return eventService.UpdateEventState(userId, id, newState, reason) ? Ok() : BadRequest();
4647
}
4748

core/Controllers/OrganizerEventsController.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace api.core.Controllers;
2020
[ApiController]
2121
[Authorize(Policy = AuthPolicies.OrganizerIsActive)]
2222
[Route("api/organizer-events")]
23-
public class OrganizerEventsController(ILogger<OrganizerEventsController> logger, IEventService eventService) : ControllerBase
23+
public class OrganizerEventsController(ILogger<OrganizerEventsController> logger, IEventService eventService, IJwtUtils jwtUtils) : ControllerBase
2424
{
2525
/// <summary>
2626
/// Fetch events for the currently connected organizer
@@ -46,7 +46,7 @@ public IActionResult MyEvents(
4646
[FromQuery] State state = State.All
4747
)
4848
{
49-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
49+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
5050

5151
logger.LogInformation("Getting events");
5252
var validFilter = new PaginationRequest(pagination.PageNumber, pagination.PageSize);
@@ -72,7 +72,7 @@ public IActionResult AddEvent([FromForm] EventCreationRequestDTO dto)
7272
{
7373
logger.LogInformation($"Adding new event");
7474

75-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
75+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
7676
var evnt = eventService.AddEvent(userId, dto);
7777

7878
return new OkObjectResult(
@@ -85,15 +85,15 @@ public IActionResult AddEvent([FromForm] EventCreationRequestDTO dto)
8585
[HttpDelete("{id}")]
8686
public IActionResult DeleteEvent(Guid id)
8787
{
88-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
88+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
8989
var isDeleted = eventService.DeleteEvent(userId, id);
9090
return isDeleted ? Ok() : BadRequest();
9191
}
9292

9393
[HttpPatch("{id}")]
9494
public IActionResult UpdateEvent(Guid id, [FromForm] EventUpdateRequestDTO dto)
9595
{
96-
var userId = JwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
96+
var userId = jwtUtils.GetUserIdFromAuthHeader(HttpContext.Request.Headers["Authorization"]!);
9797
return eventService.UpdateEvent(userId, id, dto) ? Ok() : BadRequest();
9898
}
9999
}

core/Controllers/OrganizersController.cs

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using api.core.data.entities;
22
using api.core.Data;
3+
using api.core.Data.Entities;
34
using api.core.Data.Enums;
45
using api.core.Data.Exceptions;
56
using api.core.Data.requests;
@@ -26,15 +27,13 @@ namespace api.core.controllers;
2627
/// for this to work.
2728
/// </summary>
2829
/// <param name="userService">Used to fetch and manage the organizers</param>
29-
/// <param name="authService">Used to create a new user in the Supabase database</param>
3030
/// <param name="emailService">Used to send an email to the newly created organizer</param>
3131
/// <param name="configuration">Used to fetch the FRONTEND_BASE_URL from the environments variables</param>
3232
[Authorize(Policy = AuthPolicies.IsModerator)]
3333
[ApiController]
3434
[Route("api/organizers")]
3535
public class ModeratorUserController(
3636
IUserService userService,
37-
IAuthService authService,
3837
IEmailService emailService,
3938
IConfiguration configuration) : ControllerBase
4039
{
@@ -49,15 +48,15 @@ public class ModeratorUserController(
4948
/// <exception cref="NotFoundException{Organizer}"></exception>
5049
[AllowAnonymous]
5150
[HttpGet("{organizerId}")]
52-
public IActionResult GetOrganizer(Guid organizerId)
51+
public IActionResult GetOrganizer(string organizerId)
5352
{
5453
var user = userService.GetUser(organizerId);
5554
return user.Type == "Organizer" ?
5655
Ok(new Response<UserResponseDTO>
5756
{
5857
Data = user
5958
})
60-
: throw new NotFoundException<Organizer>();
59+
: throw new NotFoundException<User>();
6160
}
6261

6362
/// <summary>
@@ -68,32 +67,32 @@ public IActionResult GetOrganizer(Guid organizerId)
6867
/// <param name="organizer"></param>
6968
/// <returns></returns>
7069
/// <exception cref="ArgumentNullException"></exception>
71-
[HttpPost]
72-
public async Task<IActionResult> CreateOrganizer([FromBody] UserCreateDTO organizer)
73-
{
74-
var strongPassword = GenerateRandomPassword(12);
75-
var supabaseUser = authService.SignUp(organizer.Email, strongPassword);
76-
_ = Guid.TryParse(supabaseUser, out Guid userId);
77-
var created = userService.AddOrganizer(userId, organizer);
78-
var frontBaseUrl = configuration.GetValue<string>("FRONTEND_BASE_URL") ?? throw new ArgumentNullException("FRONTEND_BASE_URL is not set");
79-
await emailService.SendEmailAsync(
80-
organizer.Email,
81-
"Votre compte Hello!",
82-
new UserCreationModel
83-
{
84-
Title = "Création de votre compte Hello!",
85-
Salutation = $"Bonjour {organizer.Organization},",
86-
AccountCreatedText = "Votre compte Hello a été créé!",
87-
TemporaryPasswordHeader = "Votre mot de passe temporaire est: ",
88-
TemporaryPassword = strongPassword,
89-
LoginButtonText = "Se connecter",
90-
ButtonLink = new Uri($"{frontBaseUrl}/fr/login")
91-
},
92-
emails.EmailsUtils.UserCreationTemplate
93-
);
94-
95-
return Ok(new Response<UserResponseDTO> { Data = created });
96-
}
70+
//[HttpPost]
71+
//public async Task<IActionResult> CreateOrganizer([FromBody] UserCreateDTO organizer)
72+
//{
73+
// var strongPassword = GenerateRandomPassword(12);
74+
// var supabaseUser = authService.SignUp(organizer.Email, strongPassword);
75+
// _ = Guid.TryParse(supabaseUser, out Guid userId);
76+
// var created = userService.AddOrganizer(userId, organizer);
77+
// var frontBaseUrl = configuration.GetValue<string>("FRONTEND_BASE_URL") ?? throw new ArgumentNullException("FRONTEND_BASE_URL is not set");
78+
// await emailService.SendEmailAsync(
79+
// organizer.Email,
80+
// "Votre compte Hello!",
81+
// new UserCreationModel
82+
// {
83+
// Title = "Création de votre compte Hello!",
84+
// Salutation = $"Bonjour {organizer.Organization},",
85+
// AccountCreatedText = "Votre compte Hello a été créé!",
86+
// TemporaryPasswordHeader = "Votre mot de passe temporaire est: ",
87+
// TemporaryPassword = strongPassword,
88+
// LoginButtonText = "Se connecter",
89+
// ButtonLink = new Uri($"{frontBaseUrl}/fr/login")
90+
// },
91+
// emails.EmailsUtils.UserCreationTemplate
92+
// );
93+
94+
// return Ok(new Response<UserResponseDTO> { Data = created });
95+
//}
9796

9897
/// <summary>
9998
/// Get all users with pagination and search term
@@ -131,7 +130,7 @@ public IActionResult GetUsers(string? search, OrganizerAccountActiveFilter filte
131130
/// <param name="reason">pass a reason for the toggle active change, will be send by email</param>
132131
/// <returns></returns>
133132
[HttpPatch("{organizerId}/toggle")]
134-
public async Task<IActionResult> ToggleOrganizer(Guid organizerId, [FromQuery] string? reason)
133+
public async Task<IActionResult> ToggleOrganizer(string organizerId, [FromQuery] string? reason)
135134
{
136135
var success = userService.ToggleUserActiveState(organizerId);
137136
var organizer = userService.GetUser(organizerId);

core/Controllers/TestController.cs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using api.core.Data.Requests;
1+
using System.Runtime.Serialization.Json;
2+
using System.Text;
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
25

36
using Microsoft.AspNetCore.Mvc;
47

@@ -14,14 +17,71 @@ namespace api.core.controllers;
1417
public class TestController(IConfiguration configuration) : ControllerBase
1518
{
1619

17-
[HttpPost("login")]
18-
public async Task<IActionResult> Login([FromBody] LoginRequestDTO req, CancellationToken ct)
20+
[HttpGet]
21+
public IActionResult Login()
1922
{
20-
var projectId = configuration.GetValue<string>("SUPABASE_PROJECT_ID");
21-
var anonKey = configuration.GetValue<string>("SUPABASE_ANON_KEY");
23+
var redirectionURL = Environment.GetEnvironmentVariable("OPENID_BASE_URL") + "authorize/?";
24+
Dictionary<string, string> queryParameters = new()
25+
{
26+
["client_id"] = Environment.GetEnvironmentVariable("OPENID_CLIENT_ID"),
27+
["response_type"] = "code",
28+
["redirect_uri"] = "https://localhost:8081/callback/code",
29+
["scope"] = "email,profile,openid",
30+
["state"] = "1234"
31+
};
32+
33+
return Redirect(redirectionURL + string.Join('&', queryParameters.Select(qp => qp.Key + '=' + qp.Value)));
34+
}
35+
36+
[HttpGet]
37+
[Route("/callback/code")]
38+
public async Task<IActionResult> Reception([FromQuery] string code, [FromQuery] string? state)
39+
{
40+
using HttpClient client = new();
41+
string claimUrl = Environment.GetEnvironmentVariable("OPENID_BASE_URL") + "token/";
42+
43+
Dictionary<string, string> body = new()
44+
{
45+
["grant_type"] = "authorization_code",
46+
["redirect_uri"] = Request.Scheme + "://" + Request.Host.Value,
47+
["code"] = code
48+
};
49+
50+
string clientId = Environment.GetEnvironmentVariable("OPENID_CLIENT_ID");
51+
string clientSecret = Environment.GetEnvironmentVariable("OPENID_CLIENT_SECRET");
52+
53+
using HttpRequestMessage request = new(HttpMethod.Post, claimUrl);
54+
55+
request.Content = new FormUrlEncodedContent(body);
56+
request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}")));
57+
58+
HttpResponseMessage response = await client.SendAsync(request);
2259

23-
var client = new Supabase.Client($"https://{projectId}.supabase.co", anonKey);
24-
var response = await client.Auth.SignInWithPassword(req.Email, req.Password);
25-
return Ok(response);
60+
if (! response.IsSuccessStatusCode)
61+
{
62+
return BadRequest();
63+
}
64+
65+
string contenu = await response.Content.ReadAsStringAsync();
66+
67+
JsonSerializerOptions settings = new()
68+
{
69+
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
70+
};
71+
72+
TokenResponse token = JsonSerializer.Deserialize<TokenResponse>(contenu, settings)!;
73+
74+
return Ok(token);
2675
}
76+
}
77+
78+
[JsonSerializable(typeof(TokenResponse))]
79+
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)]
80+
public record class TokenResponse
81+
{
82+
public string AccessToken { get; set; }
83+
public string TokenType { get; set; }
84+
public string Scope { get; set; }
85+
public string IdToken { get; set; }
86+
public int ExpiresIn { get; set; }
2787
}

core/Data/Entities/ActivityArea.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@ public partial class ActivityArea : BaseEntity
1212

1313
public string NameEn { get; set; } = null!;
1414

15-
[InverseProperty("ActivityArea")]
16-
public virtual ICollection<Organizer> Organizers { get; set; } = new List<Organizer>();
15+
/// <summary>
16+
/// Groups all Users, no matter their role
17+
/// </summary>
18+
[InverseProperty(nameof(User.ActivityArea))]
19+
public virtual ICollection<User> Users { get; set; } = new List<User>();
1720

18-
[InverseProperty("ActivityArea")]
19-
public virtual ICollection<Moderator> Moderators { get; set; } = new List<Moderator>();
21+
[NotMapped]
22+
public ICollection<User> Organizers => Users.Where(u => u.Role.HasFlag(UserRole.Organizer)).ToList();
23+
24+
[NotMapped]
25+
public ICollection<User> Moderators => Users.Where(u => u.Role.HasFlag(UserRole.Moderator)).ToList();
2026
}

0 commit comments

Comments
 (0)