Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e1e8a834b2 | |||
| 61f3d2889c | |||
| 66a7e633a9 | |||
| fff484d4ba | |||
| e69550048b | |||
| a29fb27b0d | |||
| c23cc4a03a | |||
| 1d2f96b2f4 | |||
| f1cdc5de19 | |||
| 4e06dc5f23 | |||
| 779acbe531 | |||
| e6021dcc61 | |||
| 4f994ba183 | |||
| 2bb1f730c9 | |||
| c92e134698 | |||
| 0b9e01c925 | |||
| c1bd8a12a9 | |||
| c120d34e62 | |||
| b7dad57cee | |||
| af1b14b0d2 | |||
| 7cfb3909b6 | |||
| ff317cc944 | |||
| 79a926bc2d | |||
| 431e96d9e4 | |||
| eb70f4b3de | |||
| 690d85009e | |||
| cec4437f2f | |||
| 33987f080e | |||
| c5b5ac6b84 | |||
| db72346683 | |||
| 70c4570b48 | |||
| 6b5084238c | |||
| 103010f59e | |||
| 719be662d2 | |||
| 84d0376138 | |||
| e8d5ac797b | |||
| d3aeb3abc8 | |||
| f40a37bc07 | |||
| 1ac93dae8d | |||
| 4fe072d837 | |||
| c6914f401c | |||
| 1044e150f4 | |||
| ba507463c7 | |||
| 1a3ca3fc2d | |||
| 07bd241e0c | |||
| 579f50a2de | |||
| df6e559f00 | |||
| 1c1f9b2fcc |
Generated
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="@romaric-thibault.fr" uuid="2e0ff1eb-4394-46d9-aa2d-362392df37df">
|
||||
<data-source source="LOCAL" name="@romaric-thibault.fr" uuid="821fc51f-62ea-4fa2-99b3-cb667f09e32a">
|
||||
<driver-ref>sqlserver.jb</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>com.jetbrains.jdbc.sqlserver.SqlServerDriver</jdbc-driver>
|
||||
|
||||
@@ -3,4 +3,9 @@ namespace Knots.DTO.Discussion;
|
||||
public class GetDiscussionDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public bool IsGroup { get; set; }
|
||||
public int? MembersCount { get; set; }
|
||||
|
||||
public int? GroupId { get; set; }
|
||||
}
|
||||
@@ -2,7 +2,11 @@ namespace Knots.DTO.Message;
|
||||
|
||||
public class GetMessageDetailsDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Contenu { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
public Boolean Type { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
public string AuthorName { get; set; } = "";
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Knots.DTO.Message;
|
||||
|
||||
public class UpdateMessageDto
|
||||
{
|
||||
public string? Contenu { get; set; }
|
||||
public DateTime Date { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Knots.DTO.User;
|
||||
|
||||
public class LoginResponseDto
|
||||
{
|
||||
public string? Token { get; set; }
|
||||
public int Id { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Tel { get; set; }
|
||||
public string? ProfilePicture { get; set; }
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Knots.DTO.User;
|
||||
|
||||
public class LoginUserDto
|
||||
{
|
||||
public string? Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
@@ -2,5 +2,6 @@ namespace Knots.DTO.User;
|
||||
|
||||
public class UpdateUserDescriptionDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Description {get; set;}
|
||||
}
|
||||
@@ -2,10 +2,5 @@ namespace Knots.DTO.User;
|
||||
|
||||
public class UpdateUserDto
|
||||
{
|
||||
public string? Username { get; set; }
|
||||
public string? Description {get; set;}
|
||||
public string? Password { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Tel { get; set; }
|
||||
public string? ProfilePicture { get; set; }
|
||||
public int Id { get; set; }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Knots.DTO.User;
|
||||
|
||||
public class UpdateUserTelDto
|
||||
{
|
||||
public string? Tel { get; set; }
|
||||
}
|
||||
@@ -3,6 +3,5 @@ namespace Knots.DTO.User;
|
||||
public class UpdateUsernameDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string? Username { get; set; }
|
||||
}
|
||||
@@ -1,32 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.User;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class CreateUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint<CreateDiscussionDto, GetDiscussionDto>
|
||||
public class CreateDiscussionEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateDiscussionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/users");
|
||||
Post("/discussions");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateDiscussionDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Discussion discussion = new()
|
||||
{
|
||||
|
||||
};
|
||||
knotsDbContext.Add(discussion);
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
|
||||
GetDiscussionDto response = new()
|
||||
{
|
||||
Id = discussion.Id,
|
||||
};
|
||||
|
||||
await Send.OkAsync(response, ct);
|
||||
|
||||
Models.Discussion? discussion = mapper.Map<Models.Discussion>(req);
|
||||
db.Discussions.Add(discussion);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Security.Claims;
|
||||
using Knots.Services;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class CreateGroupDiscussionEndpoint(KnotsDbContext db, EncryptionService encryption) : Endpoint<CreateGroupDiscussionRequest, GetDiscussionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/discussions/group");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateGroupDiscussionRequest req, CancellationToken ct)
|
||||
{
|
||||
int currentUserId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
|
||||
if (req.Usernames == null || req.Usernames.Count == 0)
|
||||
{
|
||||
await SendErrorsAsync(400, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Models.User> targets = await db.Users
|
||||
.Where(u => req.Usernames.Contains(u.Username!))
|
||||
.ToListAsync(ct);
|
||||
|
||||
if (targets.Count != req.Usernames.Count)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targets.Any(t => t.Id == currentUserId))
|
||||
{
|
||||
await SendErrorsAsync(400, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
int totalMembers = targets.Count + 1;
|
||||
|
||||
Models.Discussion discussion = new()
|
||||
{
|
||||
IsGroup = true,
|
||||
Key = new Models.Key { EnKey = encryption.GenerateKey() },
|
||||
UserDiscussions = targets
|
||||
.Select(t => new UserDiscussion { UserId = t.Id })
|
||||
.Append(new UserDiscussion { UserId = currentUserId })
|
||||
.ToList()
|
||||
};
|
||||
|
||||
db.Discussions.Add(discussion);
|
||||
await db.SaveChangesAsync(ct); // discussion.Id disponible
|
||||
|
||||
|
||||
Models.Group group = new()
|
||||
{
|
||||
Name = req.GroupName,
|
||||
MembersAmount = totalMembers,
|
||||
DiscussionId = discussion.Id,
|
||||
GroupUsers = targets
|
||||
.Select(t => new GroupUser { UserId = t.Id })
|
||||
.Append(new GroupUser { UserId = currentUserId })
|
||||
.ToList()
|
||||
};
|
||||
|
||||
db.Groups.Add(group);
|
||||
await db.SaveChangesAsync(ct); // group.Id disponible
|
||||
|
||||
|
||||
discussion.GroupId = group.Id;
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(new GetDiscussionDto
|
||||
{
|
||||
Id = discussion.Id,
|
||||
IsGroup = true,
|
||||
Name = group.Name,
|
||||
MembersCount = totalMembers
|
||||
}, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class CreateGroupDiscussionRequest
|
||||
{
|
||||
public string GroupName { get; set; } = "";
|
||||
public List<string> Usernames { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Security.Claims;
|
||||
using Knots.Services;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class CreatePrivateDiscussionEndpoint(KnotsDbContext db, EncryptionService encryption)
|
||||
: Endpoint<CreatePrivateDiscussionRequest, GetDiscussionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/discussions/private");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreatePrivateDiscussionRequest req, CancellationToken ct)
|
||||
{
|
||||
int currentUserId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
|
||||
// 1. retrouver l'utilisateur cible par son nom
|
||||
Models.User? target = await db.Users
|
||||
.SingleOrDefaultAsync(u => u.Username == req.Username, ct);
|
||||
|
||||
if (target is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct); // utilisateur introuvable
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.Id == currentUserId)
|
||||
{
|
||||
await SendErrorsAsync(400, ct); // pas de discussion avec soi-même
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. vérifier qu'une discussion privée entre les deux n'existe pas déjà
|
||||
Models.Discussion? existing = await db.Discussions
|
||||
.Where(d => d.GroupId == null
|
||||
&& d.UserDiscussions.Any(ud => ud.UserId == currentUserId)
|
||||
&& d.UserDiscussions.Any(ud => ud.UserId == target.Id))
|
||||
.FirstOrDefaultAsync(ct);
|
||||
|
||||
if (existing is not null)
|
||||
{
|
||||
await SendOkAsync(new GetDiscussionDto
|
||||
{
|
||||
Id = existing.Id,
|
||||
IsGroup = false,
|
||||
Name = target.Username!,
|
||||
MembersCount = null
|
||||
}, ct);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. créer la discussion + les deux participants
|
||||
Models.Discussion discussion = new()
|
||||
{
|
||||
IsGroup = false,
|
||||
Key = new Models.Key { EnKey = encryption.GenerateKey() },
|
||||
UserDiscussions =
|
||||
[
|
||||
new UserDiscussion { UserId = currentUserId },
|
||||
new UserDiscussion { UserId = target.Id }
|
||||
]
|
||||
};
|
||||
|
||||
db.Discussions.Add(discussion);
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(new GetDiscussionDto
|
||||
{
|
||||
Id = discussion.Id,
|
||||
IsGroup = false,
|
||||
Name = target.Username!,
|
||||
MembersCount = null
|
||||
}, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class CreatePrivateDiscussionRequest
|
||||
{
|
||||
public string Username { get; set; } = "";
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Discussion;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class DeleteDiscussionEndpoint
|
||||
public class DeleteDiscussionEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<DeleteDiscussionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/discussions");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteDiscussionDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Discussion? discussion = mapper.Map<Models.Discussion>(req);
|
||||
db.Discussions.Remove(discussion);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,29 @@
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.Key;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class GetDiscussionEndpoint
|
||||
public class GetDiscussionEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<GetDiscussionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/discussions");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetDiscussionDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Discussion? databaseDiscussion = await db.Discussions.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseDiscussion == null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var keyDto = mapper.Map<GetKeyDetailsDto>(databaseDiscussion);
|
||||
await SendOkAsync(keyDto, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Security.Claims;
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class GetDiscussionMembersEndpoint(KnotsDbContext db) : EndpointWithoutRequest<List<string>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/discussions/{discussionId}/members");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
int discussionId = Route<int>("discussionId");
|
||||
|
||||
Models.Discussion? discussion = await db.Discussions
|
||||
.Include(d => d.UserDiscussions)
|
||||
.ThenInclude(ud => ud.User)
|
||||
.SingleOrDefaultAsync(d => d.Id == discussionId, ct);
|
||||
|
||||
if (discussion is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> members = discussion.UserDiscussions
|
||||
.Select(ud => ud.User.Username!)
|
||||
.ToList();
|
||||
|
||||
await SendOkAsync(members, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using FastEndpoints;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class GetDiscussionMembersWithRolesEndpoint(KnotsDbContext db) : EndpointWithoutRequest<List<MemberWithRoleDto>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/discussions/{discussionId}/members/roles");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
int discussionId = Route<int>("discussionId");
|
||||
|
||||
Models.Discussion? discussion = await db.Discussions
|
||||
.Include(d => d.Group)
|
||||
.ThenInclude(g => g!.GroupUsers)
|
||||
.ThenInclude(gu => gu.User)
|
||||
.Include(d => d.Group)
|
||||
.ThenInclude(g => g!.GroupUsers)
|
||||
.ThenInclude(gu => gu.Role)
|
||||
.SingleOrDefaultAsync(d => d.Id == discussionId, ct);
|
||||
|
||||
if (discussion?.Group is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
List<MemberWithRoleDto> members = discussion.Group.GroupUsers
|
||||
.Select(gu => new MemberWithRoleDto
|
||||
{
|
||||
UserId = gu.UserId,
|
||||
Username = gu.User.Username!,
|
||||
RoleId = gu.RoleId,
|
||||
RoleLibelle = gu.Role?.Libelle
|
||||
})
|
||||
.ToList();
|
||||
|
||||
await SendOkAsync(members, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class MemberWithRoleDto
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string Username { get; set; } = "";
|
||||
public int? RoleId { get; set; }
|
||||
public string? RoleLibelle { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Security.Claims;
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Discussion;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Discussion;
|
||||
|
||||
public class GetMyDiscussionEndpoint(KnotsDbContext db) : EndpointWithoutRequest<List<GetDiscussionDto>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/discussions/my");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
int userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
|
||||
// Discussions privées : l'utilisateur est l'un des participants
|
||||
IQueryable<GetDiscussionDto> privees = db.Discussions
|
||||
.Where(d => d.GroupId == null && d.UserDiscussions.Any(ud => ud.UserId == userId))
|
||||
.Select(d => new GetDiscussionDto
|
||||
{
|
||||
Id = d.Id,
|
||||
IsGroup = false,
|
||||
Name = d.UserDiscussions
|
||||
.Where(ud => ud.UserId != userId)
|
||||
.Select(ud => ud.User.Username)
|
||||
.FirstOrDefault() ?? "",
|
||||
MembersCount = null,
|
||||
GroupId = null
|
||||
});
|
||||
|
||||
// Discussions de groupe : l'utilisateur est membre du groupe
|
||||
IQueryable<GetDiscussionDto> groupes = db.Discussions
|
||||
.Where(d => d.Group != null && d.Group.GroupUsers.Any(gu => gu.UserId == userId))
|
||||
.Select(d => new GetDiscussionDto
|
||||
{
|
||||
Id = d.Id,
|
||||
IsGroup = true,
|
||||
Name = d.Group!.Name!,
|
||||
MembersCount = d.Group.MembersAmount,
|
||||
GroupId = d.Group.Id
|
||||
});
|
||||
|
||||
List<GetDiscussionDto> discussions = await privees.Concat(groupes).ToListAsync(ct);
|
||||
|
||||
await SendOkAsync(discussions, ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using Knots.DTO.Group;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Knots.Endpoints.Group;
|
||||
|
||||
public class CreateGroupEndpoint
|
||||
public class CreateGroupEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateGroupDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/groups");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateGroupDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Group? group = mapper.Map<Models.Group>(req);
|
||||
db.Groups.Add(group);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Group;
|
||||
|
||||
namespace Knots.Endpoints.Group;
|
||||
|
||||
public class DeleteGroupEndpoint
|
||||
public class DeleteGroupEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<DeleteGroupDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/groups");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteGroupDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Group? group = mapper.Map<Models.Group>(req);
|
||||
db.Groups.Remove(group);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,29 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Group;
|
||||
using Knots.DTO.Key;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Group;
|
||||
|
||||
public class GetGroupEndpoint
|
||||
public class GetGroupEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<GetGroupDetailsDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/groups");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetGroupDetailsDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Group? databaseGroup = await db.Groups.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseGroup == null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var keyDto = mapper.Map<GetKeyDetailsDto>(databaseGroup);
|
||||
await SendOkAsync(keyDto, ct);
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ public class PatchGroupMembersAmountEndpoint(KnotsDbContext knotsDbContext) : En
|
||||
|
||||
if (databaseGroup is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseGroup.MembersAmount = req.MembersAmount;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ public class PatchGroupNameEndpoint(KnotsDbContext knotsDbContext) : Endpoint<Up
|
||||
|
||||
if (databaseGroup is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseGroup.Name = req.Name;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ public class PatchGroupProfilePictureEndpoint(KnotsDbContext knotsDbContext) : E
|
||||
|
||||
if (databaseGroup is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseGroup.ProfilePicture = req.ProfilePicture;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using Knots.DTO.Key;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Knots.Endpoints.Key;
|
||||
|
||||
public class CreateKeyEndpoint
|
||||
public class CreateKeyEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateKeyDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/keys");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateKeyDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Key? key = mapper.Map<Models.Key>(req);
|
||||
db.Keys.Add(key);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Key;
|
||||
|
||||
namespace Knots.Endpoints.Key;
|
||||
|
||||
public class DeleteKeyEndpoint
|
||||
public class DeleteKeyEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<DeleteKeyDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/keys");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteKeyDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Key? key = mapper.Map<Models.Key>(req);
|
||||
db.Keys.Remove(key);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,29 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Key;
|
||||
using Knots.DTO.User;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Key;
|
||||
|
||||
public class GetKeyEndpoint
|
||||
public class GetKeyEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint <GetKeyDetailsDto>
|
||||
{
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/keys/{@Id}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetKeyDetailsDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Key? databaseKey = await db.Keys.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseKey == null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
var keyDto = mapper.Map<GetKeyDetailsDto>(databaseKey);
|
||||
await SendOkAsync(keyDto, ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Message;
|
||||
|
||||
namespace Knots.Endpoints.Message;
|
||||
|
||||
public class CreateMessageEndpoint
|
||||
public class CreateMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateMessageDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/messages");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateMessageDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Message? message = mapper.Map<Models.Message>(req);
|
||||
db.Messages.Add(message);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Message;
|
||||
|
||||
namespace Knots.Endpoints.Message;
|
||||
|
||||
public class DeleteMessageEndpoint
|
||||
public class DeleteMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<DeleteMessageDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/messages");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteMessageDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Message? message = mapper.Map<Models.Message>(req);
|
||||
db.Messages.Remove(message);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,62 @@
|
||||
using System.Security.Claims;
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Message;
|
||||
using Knots.DTO.User;
|
||||
using Knots.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Message;
|
||||
|
||||
public class GetMessageEndpoint
|
||||
public class GetMessageEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper, EncryptionService encryption) : Endpoint<GetDiscussionMessagesRequest, List<GetMessageDetailsDto>>
|
||||
{
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/discussions/{DiscussionId}/messages");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetDiscussionMessagesRequest req, CancellationToken ct)
|
||||
{
|
||||
int userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
|
||||
|
||||
// l'utilisateur participe-t-il à cette discussion (privée ou via le groupe) ?
|
||||
bool autorise = await db.Discussions
|
||||
.Where(d => d.Id == req.DiscussionId)
|
||||
.AnyAsync(d =>
|
||||
d.UserDiscussions.Any(ud => ud.UserId == userId) ||
|
||||
(d.Group != null && d.Group.GroupUsers.Any(gu => gu.UserId == userId)), ct);
|
||||
|
||||
if (!autorise)
|
||||
{
|
||||
await SendForbiddenAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
string? key = await db.Discussions
|
||||
.Where(d => d.Id == req.DiscussionId)
|
||||
.Select(d => d.Key!.EnKey)
|
||||
.SingleAsync(ct);
|
||||
|
||||
var rows = await db.Messages
|
||||
.Where(m => m.DiscussionId == req.DiscussionId)
|
||||
.OrderBy(m => m.Date)
|
||||
.Select(m => new { m.Id, m.Contenu, m.Date, m.UserId, AuthorName = m.User.Username! })
|
||||
.ToListAsync(ct);
|
||||
|
||||
List<GetMessageDetailsDto> messages = rows.Select(m => new GetMessageDetailsDto
|
||||
{
|
||||
Id = m.Id,
|
||||
Contenu = encryption.Decrypt(m.Contenu!, key!),
|
||||
Date = m.Date,
|
||||
UserId = m.UserId,
|
||||
AuthorName = m.AuthorName
|
||||
}).ToList();
|
||||
|
||||
await SendOkAsync(messages, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class GetDiscussionMessagesRequest
|
||||
{
|
||||
public int DiscussionId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using FastEndpoints;
|
||||
using Knots.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Role;
|
||||
|
||||
public class AssignRoleEndpoint(KnotsDbContext db) : Endpoint<AssignRoleRequest>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/groups/{groupId}/members/{userId}/role");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(AssignRoleRequest req, CancellationToken ct)
|
||||
{
|
||||
int groupId = Route<int>("groupId");
|
||||
int userId = Route<int>("userId");
|
||||
|
||||
GroupUser? groupUser = await db.GroupUsers
|
||||
.SingleOrDefaultAsync(gu => gu.GroupId == groupId && gu.UserId == userId, ct);
|
||||
|
||||
if (groupUser is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
bool roleExists = await db.Roles.AnyAsync(r => r.Id == req.RoleId, ct);
|
||||
if (!roleExists)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
groupUser.RoleId = req.RoleId;
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class AssignRoleRequest
|
||||
{
|
||||
public int RoleId { get; set; }
|
||||
}
|
||||
@@ -1,32 +1,32 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Role;
|
||||
using Knots.DTO.User;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Endpoints.Role;
|
||||
|
||||
public class CreateRoleEndpoint(KnotsDbContext knotsDbContext) : Endpoint<CreateRoleDto, GetRoleDto>
|
||||
public class CreateRoleEndpoint(KnotsDbContext db) : Endpoint<CreateRoleRequest, RoleDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/roles");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(CreateRoleDto req, CancellationToken ct)
|
||||
|
||||
public override async Task HandleAsync(CreateRoleRequest req, CancellationToken ct)
|
||||
{
|
||||
Models.Role role = new()
|
||||
{
|
||||
Libelle = req.Libelle
|
||||
};
|
||||
knotsDbContext.Add(role);
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
|
||||
GetRoleDto response = new()
|
||||
{
|
||||
Libelle = role.Libelle
|
||||
};
|
||||
|
||||
await Send.OkAsync(response, ct);
|
||||
Models.Role role = new() { Libelle = req.Libelle };
|
||||
db.Roles.Add(role);
|
||||
await db.SaveChangesAsync(ct);
|
||||
|
||||
await SendOkAsync(new RoleDto { Id = role.Id, Libelle = role.Libelle! }, ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class CreateRoleRequest
|
||||
{
|
||||
public string Libelle { get; set; } = "";
|
||||
}
|
||||
|
||||
public class RoleDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Libelle { get; set; } = "";
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.Role;
|
||||
|
||||
namespace Knots.Endpoints.Role;
|
||||
|
||||
public class DeleteRoleEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<DeleteRoleDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/roles");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DeleteRoleDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Role? role = mapper.Map<Models.Role>(req);
|
||||
db.Roles.Remove(role);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.Role;
|
||||
|
||||
public class GetRoleEndpoint(KnotsDbContext knotsDbContext) : Endpoint <GetRoleDto>
|
||||
public class GetRoleEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint <GetRoleDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -15,19 +15,15 @@ public class GetRoleEndpoint(KnotsDbContext knotsDbContext) : Endpoint <GetRoleD
|
||||
|
||||
public override async Task HandleAsync(GetRoleDto req, CancellationToken ct)
|
||||
{
|
||||
Models.Role? databaseRole = await knotsDbContext.Roles.SingleOrDefaultAsync(x => x.Libelle == req.Libelle, cancellationToken: ct);
|
||||
Models.Role? databaseRole = await db.Roles.SingleOrDefaultAsync(x => x.Libelle == req.Libelle, cancellationToken: ct);
|
||||
|
||||
if (databaseRole == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
GetRoleDto dto = new()
|
||||
{
|
||||
Libelle = databaseRole.Libelle,
|
||||
};
|
||||
|
||||
await Send.OkAsync(dto, ct);
|
||||
var roleDto = mapper.Map<GetRoleDto>(databaseRole);
|
||||
await SendOkAsync(roleDto, ct);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.User;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class CreateUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint<CreateUserDto, GetUserDto>
|
||||
public class CreateUserEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<CreateUserDto, GetUserDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -13,24 +14,20 @@ public class CreateUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint<Create
|
||||
|
||||
public override async Task HandleAsync(CreateUserDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User user = new()
|
||||
bool usernameExists = await db.Users
|
||||
.AnyAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
|
||||
if (usernameExists)
|
||||
{
|
||||
Username = req.Username,
|
||||
Description = req.Description,
|
||||
Password = req.Password,
|
||||
Email = req.Email,
|
||||
Tel = req.Tel,
|
||||
ProfilePicture = req.ProfilePicture
|
||||
};
|
||||
knotsDbContext.Add(user);
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
|
||||
GetUserDto response = new()
|
||||
{
|
||||
Username = user.Username
|
||||
};
|
||||
|
||||
await Send.OkAsync(response, ct);
|
||||
|
||||
AddError(x => x.Username, "Ce nom d'utilisateur est déjà pris.");
|
||||
await SendErrorsAsync(cancellation: ct);
|
||||
return;
|
||||
}
|
||||
|
||||
req.Password = BCrypt.Net.BCrypt.HashPassword(req.Password);
|
||||
Models.User? user = mapper.Map<Models.User>(req);
|
||||
db.Users.Add(user);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,18 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class DeleteUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint <GetUserDto, GetUserDetailsDto>
|
||||
public class DeleteUserEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint <DeleteUserDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Delete ("/users/{@Id}", x => new { x.Username });
|
||||
Delete ("/users/{@Id}");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetUserDto req, CancellationToken ct)
|
||||
public override async Task HandleAsync(DeleteUserDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
|
||||
if (databaseUser == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
knotsDbContext.Users.Remove(databaseUser);
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
|
||||
await Send.NoContentAsync(ct);
|
||||
Models.User? user = mapper.Map<Models.User>(req);
|
||||
db.Users.Add(user);
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.User;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class GetAllUsersEndpoint(KnotsDbContext knotsDbContext) : EndpointWithoutRequest<List<GetUserDto>>
|
||||
public class GetAllUsersEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : EndpointWithoutRequest<List<GetUserDetailsDto>>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -14,11 +15,10 @@ public class GetAllUsersEndpoint(KnotsDbContext knotsDbContext) : EndpointWithou
|
||||
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
List<GetUserDto> users= await knotsDbContext.Users.Select(x => new GetUserDto()
|
||||
{
|
||||
Username = x.Username,
|
||||
}).ToListAsync(ct);
|
||||
var users = await db.Users
|
||||
.ProjectTo<GetUserDetailsDto>(mapper.ConfigurationProvider)
|
||||
.ToListAsync(ct);
|
||||
|
||||
await Send.OkAsync(users, ct);
|
||||
await SendOkAsync(users, ct);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class GetUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint <GetUserDto, GetUserDetailsDto>
|
||||
public class GetUserEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint <GetUserDetailsDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -12,26 +12,17 @@ public class GetUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint <GetUserD
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(GetUserDto req, CancellationToken ct)
|
||||
public override async Task HandleAsync(GetUserDetailsDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseLogin = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
|
||||
if (databaseLogin == null)
|
||||
if (databaseUser == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
GetUserDetailsDto dto = new()
|
||||
{
|
||||
Username = databaseLogin.Username,
|
||||
Description = databaseLogin.Description,
|
||||
Password = databaseLogin.Password,
|
||||
Email = databaseLogin.Email,
|
||||
Tel = databaseLogin.Tel,
|
||||
ProfilePicture = databaseLogin.ProfilePicture
|
||||
};
|
||||
|
||||
await Send.OkAsync(dto, ct);
|
||||
var userDto = mapper.Map<GetUserDetailsDto>(databaseUser);
|
||||
await SendOkAsync(userDto, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.User;
|
||||
using Knots.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class LoginEndpoint(KnotsDbContext db, JwtService jwtService) : Endpoint<LoginUserDto, LoginResponseDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/users/login");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(LoginUserDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? user = await db.Users
|
||||
.SingleOrDefaultAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
|
||||
if (user is null || !BCrypt.Net.BCrypt.Verify(req.Password, user.Password)) // hash à ajouter plus tard
|
||||
{
|
||||
await SendUnauthorizedAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
string token = jwtService.GenerateToken(user);
|
||||
|
||||
await SendOkAsync(new LoginResponseDto
|
||||
{
|
||||
Token = token,
|
||||
Id = user.Id,
|
||||
Username = user.Username!,
|
||||
Email = user.Email,
|
||||
Tel = user.Tel,
|
||||
ProfilePicture = user.ProfilePicture,
|
||||
Description = user.Description
|
||||
}, ct);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class PatchUserContactEndpoint(KnotsDbContext knotsDbContext) : Endpoint<UpdateUserContactDto>
|
||||
public class PatchUserContactEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<UpdateUserContactDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -14,11 +14,11 @@ public class PatchUserContactEndpoint(KnotsDbContext knotsDbContext) : Endpoint<
|
||||
|
||||
public override async Task HandleAsync(UpdateUserContactDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseUser is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ public class PatchUserContactEndpoint(KnotsDbContext knotsDbContext) : Endpoint<
|
||||
databaseUser.Tel = databaseUser.Tel;
|
||||
}
|
||||
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
mapper.Map(req, databaseUser);
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.User;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class PatchUserDescriptionEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<UpdateUserDescriptionDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Patch("/users/{@Id}/description/");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateUserDescriptionDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseUser is null)
|
||||
{
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
mapper.Map(req, databaseUser);
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class PatchUserPasswordEndpoint(KnotsDbContext knotsDbContext) : Endpoint<UpdateUserPasswordDto>
|
||||
public class PatchUserPasswordEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<UpdateUserPasswordDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
@@ -14,16 +14,17 @@ public class PatchUserPasswordEndpoint(KnotsDbContext knotsDbContext) : Endpoint
|
||||
|
||||
public override async Task HandleAsync(UpdateUserPasswordDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseUser is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseUser.Password = req.Password;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
mapper.Map(req, databaseUser);
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -4,26 +4,27 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class PatchUserProfilePictureEndpoint(KnotsDbContext knotsDbContext) : Endpoint<UpdateUserProfilePictureDto>
|
||||
public class PatchUserProfilePictureEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<UpdateUserProfilePictureDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Patch("/users/{@Id}/profilePicture/", x => new {x.Id});
|
||||
Patch("/users/{@Id}/profilepicture/");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateUserProfilePictureDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseUser is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseUser.ProfilePicture = req.ProfilePicture;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
mapper.Map(req, databaseUser);
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,37 @@ using Microsoft.EntityFrameworkCore;
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
|
||||
public class PatchUsernameEndpoint(KnotsDbContext knotsDbContext) : Endpoint<UpdateUsernameDto>
|
||||
public class PatchUsernameEndpoint(KnotsDbContext db, AutoMapper.IMapper mapper) : Endpoint<UpdateUsernameDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Patch("/users/{@Id}/username/", x => new {x.Id});
|
||||
Patch("/users/{@Id}/username/");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateUsernameDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
Models.User? databaseUser = await db.Users.SingleOrDefaultAsync(x => x.Id == req.Id, cancellationToken: ct);
|
||||
|
||||
if (databaseUser is null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
await SendNotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
|
||||
databaseUser.Username = req.Username;
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
await Send.NoContentAsync(ct);
|
||||
bool usernameExists = await db.Users
|
||||
.AnyAsync(x => x.Username == req.Username && x.Id != req.Id, cancellationToken: ct);
|
||||
|
||||
if (usernameExists)
|
||||
{
|
||||
AddError(x => x.Username, "Ce nom d'utilisateur est déjà pris.");
|
||||
await SendErrorsAsync(cancellation: ct);
|
||||
return;
|
||||
}
|
||||
|
||||
mapper.Map(req, databaseUser);
|
||||
|
||||
await db.SaveChangesAsync(ct);
|
||||
await SendNoContentAsync(ct);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using FastEndpoints;
|
||||
using Knots.DTO.User;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Endpoints.User;
|
||||
|
||||
public class UpdateUserEndpoint(KnotsDbContext knotsDbContext) : Endpoint <UpdateUserDto, GetUserDetailsDto>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Put ("/users/{@Id}", x => new { x.Username });
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(UpdateUserDto req, CancellationToken ct)
|
||||
{
|
||||
Models.User? databaseUser = await knotsDbContext.Users.SingleOrDefaultAsync(x => x.Username == req.Username, cancellationToken: ct);
|
||||
|
||||
if (databaseUser == null)
|
||||
{
|
||||
await Send.NotFoundAsync(ct);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
databaseUser.Username = req.Username;
|
||||
databaseUser.Password = req.Password;
|
||||
databaseUser.Description = req.Description;
|
||||
databaseUser.Tel = req.Tel;
|
||||
databaseUser.Email = req.Email;
|
||||
databaseUser.ProfilePicture = req.ProfilePicture;
|
||||
}
|
||||
await knotsDbContext.SaveChangesAsync(ct);
|
||||
|
||||
GetUserDetailsDto dto = new()
|
||||
{
|
||||
Username = databaseUser.Username,
|
||||
Password = databaseUser.Password,
|
||||
Description = databaseUser.Description,
|
||||
Tel = databaseUser.Tel,
|
||||
Email = databaseUser.Email,
|
||||
ProfilePicture = databaseUser.ProfilePicture
|
||||
};
|
||||
|
||||
await Send.OkAsync(dto, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Knots.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Knots.Hubs;
|
||||
|
||||
[Authorize]
|
||||
public class ChatHub(KnotsDbContext db, AutoMapper.IMapper mapper, EncryptionService encryption) : Hub
|
||||
{
|
||||
// Rejoindre une conversation (room)
|
||||
public async Task JoinConversation(string discussionId)
|
||||
{
|
||||
await Groups.AddToGroupAsync(Context.ConnectionId, discussionId);
|
||||
}
|
||||
|
||||
// Quitter une conversation
|
||||
public async Task LeaveConversation(string discussionId)
|
||||
{
|
||||
await Groups.RemoveFromGroupAsync(Context.ConnectionId, discussionId);
|
||||
}
|
||||
|
||||
// Envoyer un message à une conversation
|
||||
public async Task SendMessage(string discussionId, string content)
|
||||
{
|
||||
int id = int.Parse(discussionId);
|
||||
|
||||
Models.Discussion discussion = await db.Discussions
|
||||
.Include(d => d.Key)
|
||||
.SingleAsync(d => d.Id == id);
|
||||
|
||||
var message = new Models.Message
|
||||
{
|
||||
Contenu = encryption.Encrypt(content, discussion.Key!.EnKey!), // chiffré en base
|
||||
Date = DateTime.UtcNow,
|
||||
Type = false,
|
||||
UserId = int.Parse(Context.UserIdentifier!),
|
||||
DiscussionId = id
|
||||
};
|
||||
|
||||
db.Messages.Add(message);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// diffusion en clair, avec les noms de champs attendus par le front
|
||||
await Clients.Group(discussionId).SendAsync("ReceiveMessage", new
|
||||
{
|
||||
id = message.Id,
|
||||
contenu = content,
|
||||
date = message.Date,
|
||||
userId = message.UserId
|
||||
});
|
||||
}
|
||||
|
||||
// Notifier que l'utilisateur est en train d'écrire
|
||||
public async Task Typing(string discussionId)
|
||||
{
|
||||
await Clients.OthersInGroup(discussionId)
|
||||
.SendAsync("UserTyping", Context.UserIdentifier);
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -8,15 +8,20 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="16.1.1" />
|
||||
<PackageReference Include="FastEndpoints" Version="8.0.1" />
|
||||
<PackageReference Include="FastEndpoints.Swagger" Version="8.0.1" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.2.0" />
|
||||
<PackageReference Include="FastEndpoints" Version="5.33.0" />
|
||||
<PackageReference Include="FastEndpoints.Swagger" Version="5.33.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.3.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.28" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.25" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.25" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.25">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.25" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+58
-12
@@ -5,29 +5,75 @@ namespace Knots;
|
||||
|
||||
public class KnotsDbContext : DbContext
|
||||
{
|
||||
public DbSet<Discussion> Discussions { get; set; }
|
||||
public DbSet<Group> Groups { get; set; }
|
||||
public DbSet<Key> Keys { get; set; }
|
||||
public DbSet<Message> Messages { get; set; }
|
||||
public DbSet<Role> Roles { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<User> Users => Set<User>();
|
||||
public DbSet<Discussion> Discussions => Set<Discussion>();
|
||||
public DbSet<Group> Groups => Set<Group>();
|
||||
public DbSet<Message> Messages => Set<Message>();
|
||||
public DbSet<Role> Roles => Set<Role>();
|
||||
public DbSet<Key> Keys => Set<Key>();
|
||||
public DbSet<UserDiscussion> UserDiscussions => Set<UserDiscussion>();
|
||||
public DbSet<GroupUser> GroupUsers => Set<GroupUser>();
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
//Infos de connexion à la base de données
|
||||
string connectionString =
|
||||
"Server=romaric-thibault.fr;" +
|
||||
"Database=Knots;" +
|
||||
"User Id=mathieu;" +
|
||||
"Password=Onto9-Cage-Afflicted;" +
|
||||
"Database=knots;" +
|
||||
"User Id=knots;" +
|
||||
"Password=knots;" +
|
||||
"TrustServerCertificate=true;";
|
||||
|
||||
optionsBuilder.UseSqlServer(connectionString);
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
//Données à insérer
|
||||
modelBuilder.Entity<GroupUser>()
|
||||
.HasKey(gu => new { gu.GroupId, gu.UserId });
|
||||
|
||||
modelBuilder.Entity<GroupUser>()
|
||||
.HasOne(gu => gu.Group)
|
||||
.WithMany(g => g.GroupUsers)
|
||||
.HasForeignKey(gu => gu.GroupId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<GroupUser>()
|
||||
.HasOne(gu => gu.User)
|
||||
.WithMany()
|
||||
.HasForeignKey(gu => gu.UserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<GroupUser>()
|
||||
.HasOne(gu => gu.Role)
|
||||
.WithMany(r => r.GroupUsers)
|
||||
.HasForeignKey(gu => gu.RoleId);
|
||||
|
||||
modelBuilder.Entity<Discussion>()
|
||||
.HasOne(d => d.Group)
|
||||
.WithMany()
|
||||
.HasForeignKey(d => d.GroupId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<Group>()
|
||||
.HasOne(g => g.Discussion)
|
||||
.WithMany()
|
||||
.HasForeignKey(g => g.DiscussionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<UserDiscussion>()
|
||||
.HasKey(ud => new { ud.UserId, ud.DiscussionId });
|
||||
|
||||
modelBuilder.Entity<UserDiscussion>()
|
||||
.HasOne(ud => ud.Discussion)
|
||||
.WithMany(d => d.UserDiscussions)
|
||||
.HasForeignKey(ud => ud.DiscussionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<UserDiscussion>()
|
||||
.HasOne(ud => ud.User)
|
||||
.WithMany(u => u.UserDiscussions)
|
||||
.HasForeignKey(ud => ud.UserId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
}
|
||||
}
|
||||
+73
-6
@@ -12,8 +12,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
[DbContext(typeof(KnotsDbContext))]
|
||||
[Migration("20260312155557_Initial")]
|
||||
partial class Initial
|
||||
[Migration("20260505083044_InitialDatabase")]
|
||||
partial class InitialDatabase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@@ -33,6 +33,9 @@ namespace Knots.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Discussions");
|
||||
@@ -46,14 +49,17 @@ namespace Knots.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Nom")
|
||||
b.Property<int>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MembersAmount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("NombreMembres")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
@@ -96,11 +102,31 @@ namespace Knots.Migrations
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Type")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.HasIndex("KeyId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Messages");
|
||||
});
|
||||
|
||||
@@ -159,6 +185,47 @@ namespace Knots.Migrations
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", null)
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("DiscussionId");
|
||||
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Key", "Key")
|
||||
.WithMany()
|
||||
.HasForeignKey("KeyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Key");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
+75
-26
@@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
public partial class InitialDatabase : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
@@ -16,7 +16,8 @@ namespace Knots.Migrations
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1")
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
KeyId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -29,9 +30,10 @@ namespace Knots.Migrations
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Nom = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
NombreMembres = table.Column<int>(type: "int", nullable: false),
|
||||
ProfilePicture = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
MembersAmount = table.Column<int>(type: "int", nullable: false),
|
||||
ProfilePicture = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
KeyId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -51,21 +53,6 @@ namespace Knots.Migrations
|
||||
table.PrimaryKey("PK_Keys", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Messages",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Contenu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: false),
|
||||
Date = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Type = table.Column<bool>(type: "bit", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Messages", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Roles",
|
||||
columns: table => new
|
||||
@@ -96,11 +83,79 @@ namespace Knots.Migrations
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Messages",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Contenu = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: false),
|
||||
Date = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
Type = table.Column<bool>(type: "bit", nullable: false),
|
||||
GroupId = table.Column<int>(type: "int", nullable: false),
|
||||
KeyId = table.Column<int>(type: "int", nullable: false),
|
||||
UserId = table.Column<int>(type: "int", nullable: false),
|
||||
DiscussionId = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Messages", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Discussions_DiscussionId",
|
||||
column: x => x.DiscussionId,
|
||||
principalTable: "Discussions",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Groups_GroupId",
|
||||
column: x => x.GroupId,
|
||||
principalTable: "Groups",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Keys_KeyId",
|
||||
column: x => x.KeyId,
|
||||
principalTable: "Keys",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_Messages_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_DiscussionId",
|
||||
table: "Messages",
|
||||
column: "DiscussionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_GroupId",
|
||||
table: "Messages",
|
||||
column: "GroupId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_KeyId",
|
||||
table: "Messages",
|
||||
column: "KeyId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Messages_UserId",
|
||||
table: "Messages",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Messages");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Roles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Discussions");
|
||||
|
||||
@@ -110,12 +165,6 @@ namespace Knots.Migrations
|
||||
migrationBuilder.DropTable(
|
||||
name: "Keys");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Messages");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Roles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Knots;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
[DbContext(typeof(KnotsDbContext))]
|
||||
[Migration("20260610135459_AddRoleIdToUser")]
|
||||
partial class AddRoleIdToUser
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.25")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsGroup")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Discussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MembersAmount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Groups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("EnKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Keys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Contenu")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Type")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.HasIndex("KeyId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Libelle")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Roles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(70)
|
||||
.HasColumnType("nvarchar(70)");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Tel")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("UserId", "DiscussionId");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.ToTable("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithOne("Group")
|
||||
.HasForeignKey("Knots.Models.Group", "DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId");
|
||||
|
||||
b.HasOne("Knots.Models.Key", "Key")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("KeyId");
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Key");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Role", "Role")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId");
|
||||
|
||||
b.Navigation("Role");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Role", b =>
|
||||
{
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddRoleIdToUser : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Discussions_DiscussionId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Groups_GroupId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Keys_KeyId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "KeyId",
|
||||
table: "Discussions");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "RoleId",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "KeyId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "GroupId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "DiscussionId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "DiscussionId",
|
||||
table: "Groups",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "CreatedAt",
|
||||
table: "Discussions",
|
||||
type: "datetime2",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsGroup",
|
||||
table: "Discussions",
|
||||
type: "bit",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "UserDiscussions",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<int>(type: "int", nullable: false),
|
||||
DiscussionId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_UserDiscussions", x => new { x.UserId, x.DiscussionId });
|
||||
table.ForeignKey(
|
||||
name: "FK_UserDiscussions_Discussions_DiscussionId",
|
||||
column: x => x.DiscussionId,
|
||||
principalTable: "Discussions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_UserDiscussions_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_RoleId",
|
||||
table: "Users",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Groups_DiscussionId",
|
||||
table: "Groups",
|
||||
column: "DiscussionId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserDiscussions_DiscussionId",
|
||||
table: "UserDiscussions",
|
||||
column: "DiscussionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Groups_Discussions_DiscussionId",
|
||||
table: "Groups",
|
||||
column: "DiscussionId",
|
||||
principalTable: "Discussions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Discussions_DiscussionId",
|
||||
table: "Messages",
|
||||
column: "DiscussionId",
|
||||
principalTable: "Discussions",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Groups_GroupId",
|
||||
table: "Messages",
|
||||
column: "GroupId",
|
||||
principalTable: "Groups",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Keys_KeyId",
|
||||
table: "Messages",
|
||||
column: "KeyId",
|
||||
principalTable: "Keys",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Users_Roles_RoleId",
|
||||
table: "Users",
|
||||
column: "RoleId",
|
||||
principalTable: "Roles",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Groups_Discussions_DiscussionId",
|
||||
table: "Groups");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Discussions_DiscussionId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Groups_GroupId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Messages_Keys_KeyId",
|
||||
table: "Messages");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Users_Roles_RoleId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "UserDiscussions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Users_RoleId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Groups_DiscussionId",
|
||||
table: "Groups");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RoleId",
|
||||
table: "Users");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DiscussionId",
|
||||
table: "Groups");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedAt",
|
||||
table: "Discussions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsGroup",
|
||||
table: "Discussions");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "KeyId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "GroupId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "DiscussionId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "KeyId",
|
||||
table: "Discussions",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Discussions_DiscussionId",
|
||||
table: "Messages",
|
||||
column: "DiscussionId",
|
||||
principalTable: "Discussions",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Groups_GroupId",
|
||||
table: "Messages",
|
||||
column: "GroupId",
|
||||
principalTable: "Groups",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Messages_Keys_KeyId",
|
||||
table: "Messages",
|
||||
column: "KeyId",
|
||||
principalTable: "Keys",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Knots;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
[DbContext(typeof(KnotsDbContext))]
|
||||
[Migration("20260610224937_FixGroupDiscussion")]
|
||||
partial class FixGroupDiscussion
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.25")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsGroup")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.ToTable("Discussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MembersAmount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.ToTable("Groups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.GroupUser", b =>
|
||||
{
|
||||
b.Property<int>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("GroupId", "UserId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("GroupUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("EnKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Keys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AuthorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Contenu")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1000)
|
||||
.HasColumnType("nvarchar(1000)");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Type")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.HasIndex("KeyId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Libelle")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Roles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(70)
|
||||
.HasColumnType("nvarchar(70)");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Tel")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("UserId", "DiscussionId");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.ToTable("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany()
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.GroupUser", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany("GroupUsers")
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Role", "Role")
|
||||
.WithMany("GroupUsers")
|
||||
.HasForeignKey("RoleId");
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Role");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId");
|
||||
|
||||
b.HasOne("Knots.Models.Key", "Key")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("KeyId");
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Key");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Role", "Role")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId");
|
||||
|
||||
b.Navigation("Role");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.Navigation("GroupUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Role", b =>
|
||||
{
|
||||
b.Navigation("GroupUsers");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Knots.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixGroupDiscussion : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "AuthorId",
|
||||
table: "Messages",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,19 @@ namespace Knots.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsGroup")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.ToTable("Discussions");
|
||||
});
|
||||
|
||||
@@ -43,22 +54,47 @@ namespace Knots.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Nom")
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MembersAmount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("NombreMembres")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.ToTable("Groups");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.GroupUser", b =>
|
||||
{
|
||||
b.Property<int>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("GroupId", "UserId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("GroupUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -85,6 +121,9 @@ namespace Knots.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AuthorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Contenu")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1000)
|
||||
@@ -93,11 +132,31 @@ namespace Knots.Migrations
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("GroupId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("KeyId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Type")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.HasIndex("GroupId");
|
||||
|
||||
b.HasIndex("KeyId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Messages");
|
||||
});
|
||||
|
||||
@@ -143,6 +202,9 @@ namespace Knots.Migrations
|
||||
b.Property<string>("ProfilePicture")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Tel")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
@@ -154,8 +216,161 @@ namespace Knots.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("DiscussionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("UserId", "DiscussionId");
|
||||
|
||||
b.HasIndex("DiscussionId");
|
||||
|
||||
b.ToTable("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Group");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany()
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.GroupUser", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany("GroupUsers")
|
||||
.HasForeignKey("GroupId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Role", "Role")
|
||||
.WithMany("GroupUsers")
|
||||
.HasForeignKey("RoleId");
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Role");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Message", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.Group", "Group")
|
||||
.WithMany()
|
||||
.HasForeignKey("GroupId");
|
||||
|
||||
b.HasOne("Knots.Models.Key", "Key")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("KeyId");
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("Messages")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("Group");
|
||||
|
||||
b.Navigation("Key");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Role", "Role")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId");
|
||||
|
||||
b.Navigation("Role");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.UserDiscussion", b =>
|
||||
{
|
||||
b.HasOne("Knots.Models.Discussion", "Discussion")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("DiscussionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Knots.Models.User", "User")
|
||||
.WithMany("UserDiscussions")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Discussion");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Discussion", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Group", b =>
|
||||
{
|
||||
b.Navigation("GroupUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Key", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.Role", b =>
|
||||
{
|
||||
b.Navigation("GroupUsers");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Knots.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Messages");
|
||||
|
||||
b.Navigation("UserDiscussions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,15 @@ namespace Knots.Models;
|
||||
public class Discussion
|
||||
{
|
||||
[Key] public int Id { get; set; }
|
||||
public bool IsGroup { get; set; } = false;
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public int? GroupId { get; set; }
|
||||
public Group? Group { get; set; }
|
||||
|
||||
public int? KeyId { get; set; }
|
||||
public Key? Key { get; set; }
|
||||
|
||||
public List<Message> Messages { get; set; } = [];
|
||||
public List<UserDiscussion> UserDiscussions { get; set; } = [];
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net.Mime;
|
||||
|
||||
namespace Knots.Models;
|
||||
|
||||
@@ -9,4 +8,9 @@ public class Group
|
||||
[Required, MaxLength(50)] public string? Name { get; set; }
|
||||
[Required] public int MembersAmount { get; set; }
|
||||
public string? ProfilePicture { get; set; }
|
||||
|
||||
public List<GroupUser> GroupUsers { get; set; } = [];
|
||||
|
||||
public int DiscussionId { get; set; }
|
||||
public Discussion Discussion { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Knots.Models;
|
||||
|
||||
public class GroupUser
|
||||
{
|
||||
public int GroupId { get; set; }
|
||||
public Group Group { get; set; } = null!;
|
||||
|
||||
public int UserId { get; set; }
|
||||
public User User { get; set; } = null!;
|
||||
|
||||
public int? RoleId { get; set; }
|
||||
public Role? Role { get; set; }
|
||||
}
|
||||
@@ -8,4 +8,12 @@ public class Message
|
||||
[Required, MaxLength(1000)] public string? Contenu { get; set; }
|
||||
[Required] public DateTime Date { get; set; }
|
||||
[Required] public Boolean Type { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
public User User { get; set; } = null!;
|
||||
|
||||
public int DiscussionId { get; set; }
|
||||
public Discussion Discussion { get; set; } = null!;
|
||||
|
||||
public Group? Group { get; set; }
|
||||
}
|
||||
@@ -6,4 +6,6 @@ public class Role
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[Required, MaxLength(50)] public string? Libelle { get; set; }
|
||||
public List<User> Users { get; set; } = [];
|
||||
public List<GroupUser> GroupUsers { get; set; } = [];
|
||||
}
|
||||
@@ -6,9 +6,13 @@ public class User
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[Required, MaxLength(50)] public string? Username { get; set; }
|
||||
[MaxLength(200)] public string? Description {get; set;}
|
||||
[MaxLength(200)] public string? Description { get; set; }
|
||||
[Required, Length(12, 50)] public string? Password { get; set; }
|
||||
[Required, MaxLength(70)] public string? Email { get; set; }
|
||||
[Required, Length(10, 10)] public string? Tel { get; set; }
|
||||
public string? ProfilePicture { get; set; }
|
||||
public List<Message> Messages { get; set; } = [];
|
||||
public int? RoleId { get; set; }
|
||||
public Role? Role { get; set; }
|
||||
public List<UserDiscussion> UserDiscussions { get; set; } = [];
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Knots.Models;
|
||||
|
||||
public class UserDiscussion
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public User User { get; set; } = null!;
|
||||
|
||||
public int DiscussionId { get; set; }
|
||||
public Discussion Discussion { get; set; } = null!;
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
using AutoMapper;
|
||||
using Knots.DTO.Group;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Profiles;
|
||||
|
||||
public class GroupProfile
|
||||
public class GroupProfile : Profile
|
||||
{
|
||||
|
||||
public GroupProfile()
|
||||
{
|
||||
CreateMap<Group, GetGroupDto>();
|
||||
CreateMap<Group, GetGroupDetailsDto>();
|
||||
CreateMap<CreateGroupDto, Group>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
using AutoMapper;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.Key;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Profiles;
|
||||
|
||||
public class KeyProfile
|
||||
public class KeyProfile : Profile
|
||||
{
|
||||
|
||||
public KeyProfile()
|
||||
{
|
||||
CreateMap<Key, GetKeyDetailsDto>();
|
||||
CreateMap<Key, CreateKeyDto>();
|
||||
CreateMap<CreateKeyDto, Key>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
using AutoMapper;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.Message;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Profiles;
|
||||
|
||||
public class MessageProfile
|
||||
public class MessageProfile : Profile
|
||||
{
|
||||
|
||||
public MessageProfile()
|
||||
{
|
||||
CreateMap<Message, GetMessageDetailsDto>();
|
||||
CreateMap<Message, CreateMessageDto>();
|
||||
CreateMap<CreateMessageDto, Message>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
using AutoMapper;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.Role;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Profiles;
|
||||
|
||||
public class RoleProfile
|
||||
public class RoleProfile : Profile
|
||||
{
|
||||
|
||||
public RoleProfile()
|
||||
{
|
||||
CreateMap<Role, GetRoleDto>();
|
||||
CreateMap<Role, CreateRoleDto>();
|
||||
CreateMap<CreateRoleDto, Role>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,29 @@
|
||||
using AutoMapper;
|
||||
using Knots.DTO.Discussion;
|
||||
using Knots.DTO.User;
|
||||
using Knots.Models;
|
||||
|
||||
namespace Knots.Profiles;
|
||||
|
||||
public class UserProfile
|
||||
public class UserProfile : Profile
|
||||
{
|
||||
|
||||
public UserProfile()
|
||||
{
|
||||
CreateMap<User, GetUserDetailsDto>();
|
||||
CreateMap<User, GetUserDto>();
|
||||
CreateMap<CreateUserDto, User>();
|
||||
CreateMap<UpdateUserDto, User>();
|
||||
CreateMap<UpdateUserContactDto, User>();
|
||||
CreateMap<UpdateUserDescriptionDto, User>();
|
||||
CreateMap<UpdateUsernameDto, User>();
|
||||
CreateMap<UpdateUserProfilePictureDto, User>();
|
||||
CreateMap<UpdateUserPasswordDto, User>();
|
||||
|
||||
CreateMap<User, UpdateUserContactDto>();
|
||||
CreateMap<User, UpdateUserDto>();
|
||||
CreateMap<User, UpdateUserDescriptionDto>();
|
||||
CreateMap<User, UpdateUserProfilePictureDto>();
|
||||
CreateMap<User, UpdateUserPasswordDto>();
|
||||
CreateMap<User, CreateUserDto>();
|
||||
}
|
||||
}
|
||||
+63
-5
@@ -1,6 +1,13 @@
|
||||
using System.Text;
|
||||
using Knots;
|
||||
using FastEndpoints;
|
||||
using FastEndpoints.Swagger;
|
||||
using Knots.Hubs;
|
||||
using Knots.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http.Json;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi;
|
||||
|
||||
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -12,16 +19,69 @@ builder.Services.AddCors(options =>
|
||||
{ options.AddDefaultPolicy(policyBuilder =>
|
||||
{
|
||||
policyBuilder
|
||||
.WithOrigins("http://localhost:4200")
|
||||
.WithOrigins("http://localhost:5250", "http://localhost:4200")
|
||||
.WithMethods("GET", "POST", "PUT", "PATCH", "DELETE")
|
||||
.AllowAnyHeader();
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddFastEndpoints(o =>
|
||||
{
|
||||
o.DisableAutoDiscovery = false;
|
||||
});
|
||||
|
||||
builder.Services.SwaggerDocument();
|
||||
|
||||
builder.Services.AddScoped<JwtService>();
|
||||
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
||||
ValidAudience = builder.Configuration["Jwt:Audience"],
|
||||
IssuerSigningKey = new SymmetricSecurityKey(
|
||||
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
|
||||
|
||||
};
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var accessToken = context.Request.Query["access_token"];
|
||||
var path = context.HttpContext.Request.Path;
|
||||
if (!string.IsNullOrEmpty(accessToken) &&
|
||||
path.StartsWithSegments("/hubs"))
|
||||
{
|
||||
context.Token = accessToken;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
builder.Services.AddSignalR();
|
||||
|
||||
builder.Services.AddAutoMapper(cfg => { }, typeof(Program).Assembly);
|
||||
|
||||
builder.Services.AddSingleton<EncryptionService>();
|
||||
|
||||
// On construit l'application en lui donnant vie
|
||||
WebApplication app = builder.Build();
|
||||
|
||||
app.UseCors();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthentication()
|
||||
.UseAuthorization()
|
||||
.UseFastEndpoints(options =>
|
||||
@@ -31,8 +91,6 @@ app.UseAuthentication()
|
||||
}
|
||||
).UseSwaggerGen();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseCors();
|
||||
app.MapHub<ChatHub>("hubs/chat");
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Knots.Services;
|
||||
|
||||
public class EncryptionService
|
||||
{
|
||||
private const int NonceSize = 12; // AesGcm.NonceByteSizes.MaxSize
|
||||
private const int TagSize = 16; // AesGcm.TagByteSizes.MaxSize
|
||||
|
||||
// Génère une clé AES-256 (32 octets) encodée en Base64
|
||||
public string GenerateKey()
|
||||
=> Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
|
||||
|
||||
// Chiffre → renvoie Base64(nonce + tag + ciphertext)
|
||||
public string Encrypt(string plainText, string base64Key)
|
||||
{
|
||||
byte[] key = Convert.FromBase64String(base64Key);
|
||||
byte[] plain = Encoding.UTF8.GetBytes(plainText);
|
||||
|
||||
byte[] nonce = RandomNumberGenerator.GetBytes(NonceSize);
|
||||
byte[] cipher = new byte[plain.Length];
|
||||
byte[] tag = new byte[TagSize];
|
||||
|
||||
using AesGcm aes = new(key, TagSize);
|
||||
aes.Encrypt(nonce, plain, cipher, tag);
|
||||
|
||||
byte[] result = new byte[NonceSize + TagSize + cipher.Length];
|
||||
Buffer.BlockCopy(nonce, 0, result, 0, NonceSize);
|
||||
Buffer.BlockCopy(tag, 0, result, NonceSize, TagSize);
|
||||
Buffer.BlockCopy(cipher, 0, result, NonceSize + TagSize, cipher.Length);
|
||||
|
||||
return Convert.ToBase64String(result);
|
||||
}
|
||||
|
||||
// Déchiffre Base64(nonce + tag + ciphertext)
|
||||
public string Decrypt(string base64Cipher, string base64Key)
|
||||
{
|
||||
byte[] key = Convert.FromBase64String(base64Key);
|
||||
byte[] data = Convert.FromBase64String(base64Cipher);
|
||||
|
||||
byte[] nonce = new byte[NonceSize];
|
||||
byte[] tag = new byte[TagSize];
|
||||
byte[] cipher = new byte[data.Length - NonceSize - TagSize];
|
||||
|
||||
Buffer.BlockCopy(data, 0, nonce, 0, NonceSize);
|
||||
Buffer.BlockCopy(data, NonceSize, tag, 0, TagSize);
|
||||
Buffer.BlockCopy(data, NonceSize + TagSize, cipher, 0, cipher.Length);
|
||||
|
||||
byte[] plain = new byte[cipher.Length];
|
||||
using AesGcm aes = new(key, TagSize);
|
||||
aes.Decrypt(nonce, cipher, tag, plain);
|
||||
|
||||
return Encoding.UTF8.GetString(plain);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Knots.Services;
|
||||
|
||||
public class JwtService(IConfiguration configuration)
|
||||
{
|
||||
public string GenerateToken(Models.User user)
|
||||
{
|
||||
List<Claim> claims =
|
||||
[
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new Claim(ClaimTypes.Name, user.Username!)
|
||||
];
|
||||
|
||||
SymmetricSecurityKey key = new(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]!));
|
||||
SigningCredentials creds = new(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
JwtSecurityToken token = new(
|
||||
issuer: configuration["Jwt:Issuer"],
|
||||
audience: configuration["Jwt:Audience"],
|
||||
claims: claims,
|
||||
expires: DateTime.UtcNow.AddDays(7),
|
||||
signingCredentials: creds
|
||||
);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public class CreateMessageDtoValidator : Validator<CreateMessageDto>
|
||||
RuleFor(x => x.Contenu)
|
||||
.NotEmpty()
|
||||
.WithMessage("Le message ne peux pas être vide")
|
||||
.MaximumLength(1000)
|
||||
.MaximumLength(2000)
|
||||
.WithMessage("Le message ne doit pas faire plus de 1000 caractères");
|
||||
|
||||
RuleFor(x => x.Date)
|
||||
|
||||
@@ -5,5 +5,11 @@
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"Jwt": {
|
||||
"Key": "QmwiaGBl2FG8LtECB9c5x9t6637Aknw3KQcggKkeuh0",
|
||||
"Issuer": "knots",
|
||||
"Audience": "knots"
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user