diff --git a/backend/IMTest/Service/FriendServiceTest.cs b/backend/IMTest/Service/FriendServiceTest.cs index 05ff1da..4a3ac23 100644 --- a/backend/IMTest/Service/FriendServiceTest.cs +++ b/backend/IMTest/Service/FriendServiceTest.cs @@ -1,25 +1,30 @@ -using Xunit; -using Microsoft.EntityFrameworkCore; -using Moq; -using AutoMapper; -using Microsoft.Extensions.Logging; -using System.Collections.Generic; -using System.Threading.Tasks; -using System; -using IM_API.Services; -using IM_API.Models; +using AutoMapper; +using IM_API.Domain.Events; using IM_API.Dtos; using IM_API.Exceptions; -using IM_API.Tools; +using IM_API.Models; +using IM_API.Services; +using MassTransit; // 必须引入 +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Moq; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit; public class FriendServiceTests { + private readonly Mock _mockEndpoint = new(); + private readonly Mock> _mockLogger = new(); + + #region 辅助构造方法 private ImContext CreateDbContext() { var options = new DbContextOptionsBuilder() - .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .UseInMemoryDatabase(Guid.NewGuid().ToString()) // 确保每个测试数据库隔离 .Options; - return new ImContext(options); } @@ -27,132 +32,115 @@ public class FriendServiceTests { var config = new MapperConfiguration(cfg => { + // 补充你业务中实际需要的映射规则 cfg.CreateMap(); cfg.CreateMap(); - cfg.CreateMap(); cfg.CreateMap() - .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.ResponseUser)) - .ForMember(dest => dest.FriendId, opt => opt.MapFrom(src => src.RequestUser)) - .ForMember(dest => dest.RemarkName, opt => opt.MapFrom(src => "AutoAdded")); + .ForMember(d => d.UserId, o => o.MapFrom(s => s.ResponseUser)) + .ForMember(d => d.FriendId, o => o.MapFrom(s => s.RequestUser)); }); - return config.CreateMapper(); } private FriendService CreateService(ImContext context) { - var logger = new Mock>(); - return new FriendService(context, logger.Object, CreateMapper()); + // 注入 Mock 对象和真实的 Mapper/Context + return new FriendService(context, _mockLogger.Object, CreateMapper(), _mockEndpoint.Object); } + #endregion - // --------------------------- 测试 BlockFriendAsync --------------------------- [Fact] - public async Task BlockFriendAsync_Should_Set_Status_To_Blocked() + public async Task SendFriendRequestAsync_Success_ShouldSaveAndPublish() { + // Arrange var context = CreateDbContext(); - context.Friends.Add(new Friend - { - Id = 1, - UserId = 10, - FriendId = 20, - StatusEnum = FriendStatus.Added, - RemarkName = "test remark" - }); + context.Users.AddRange( + new User { Id = 1, Username = "Sender", Password = "..." }, + new User { Id = 2, Username = "Receiver", Password = "..." } + ); await context.SaveChangesAsync(); - var service = CreateService(context); + var dto = new FriendRequestDto { ToUserId = 2, Description = "Hello" }; - var result = await service.BlockeFriendAsync(1); - - Assert.True(result); - Assert.Equal(FriendStatus.Blocked, context.Friends.Find(1).StatusEnum); - } - - [Fact] - public async Task BlockFriendAsync_Should_Throw_When_NotFound() - { - var service = CreateService(CreateDbContext()); - - await Assert.ThrowsAsync(() => service.BlockeFriendAsync(99)); - } - - // --------------------------- 删除好友关系 --------------------------- - [Fact] - public async Task DeleteFriendAsync_Should_Remove_Friend() - { - var context = CreateDbContext(); - context.Friends.Add(new Friend - { - Id = 2, - UserId = 1, - FriendId = 3, - RemarkName = "remark", - StatusEnum = FriendStatus.Added - }); - await context.SaveChangesAsync(); - - var service = CreateService(context); - - var result = await service.DeleteFriendAsync(2); - - Assert.True(result); - Assert.Empty(context.Friends); - } - - // --------------------------- 获取好友列表 --------------------------- - [Fact] - public async Task GetFriendListAsync_Should_Return_Only_Added_Friends() - { - var context = CreateDbContext(); - context.Friends.AddRange(new List - { - new Friend{ UserId = 1, FriendId = 2, RemarkName ="a1", StatusEnum = FriendStatus.Added }, - new Friend{ UserId = 1, FriendId = 3, RemarkName ="a2", StatusEnum = FriendStatus.Blocked } - }); - await context.SaveChangesAsync(); - - var service = CreateService(context); - - var result = await service.GetFriendListAsync(1, 1, 10, false); - - Assert.Single(result); - } - - // --------------------------- 发起好友请求 --------------------------- - [Fact] - public async Task SendFriendRequestAsync_Should_Succeed() - { - var context = CreateDbContext(); - context.Users.Add(new User { Id = 10, Username = "A", Password = "123" }); - context.Users.Add(new User { Id = 20, Username = "B", Password = "123" }); - await context.SaveChangesAsync(); - - var service = CreateService(context); - - var result = await service.SendFriendRequestAsync(new FriendRequestDto - { - FromUserId = 10, - ToUserId = 20 - }); + // Act + var result = await service.SendFriendRequestAsync(dto); + // Assert Assert.True(result); Assert.Single(context.FriendRequests); - Assert.Single(context.Friends); + + // 验证事件是否发布到了 MQ + _mockEndpoint.Verify(x => x.Publish( + It.Is(e => e.FromUserId == 1 && e.ToUserId == 2), + It.IsAny()), + Times.Once); } [Fact] - public async Task SendFriendRequestAsync_Should_Throw_When_User_NotFound() + public async Task SendFriendRequestAsync_UserNotFound_ShouldThrow() { + // Arrange var context = CreateDbContext(); - context.Users.Add(new User { Id = 10, Username = "A", Password = "123" }); - await context.SaveChangesAsync(); + var service = CreateService(context); + var dto = new FriendRequestDto { ToUserId = 99 }; // 不存在的用户 + // Act & Assert + await Assert.ThrowsAsync(() => service.SendFriendRequestAsync(dto)); + } + + [Fact] + public async Task SendFriendRequestAsync_AlreadyExists_ShouldThrow() + { + // Arrange + var context = CreateDbContext(); + context.Users.Add(new User { Id = 2 }); + context.FriendRequests.Add(new FriendRequest + { + RequestUser = 1, + ResponseUser = 2, + State = (sbyte)FriendRequestState.Pending + }); + await context.SaveChangesAsync(); var service = CreateService(context); - await Assert.ThrowsAsync(() => service.SendFriendRequestAsync(new FriendRequestDto - { - FromUserId = 10, - ToUserId = 99 - })); + // Act & Assert + await Assert.ThrowsAsync(() => service.SendFriendRequestAsync(new FriendRequestDto { ToUserId = 2 })); } -} + + [Fact] + public async Task BlockFriendAsync_ValidId_ShouldUpdateStatus() + { + // Arrange + var context = CreateDbContext(); + var friend = new Friend { Id = 50, UserId = 1, FriendId = 2, StatusEnum = FriendStatus.Added }; + context.Friends.Add(friend); + await context.SaveChangesAsync(); + var service = CreateService(context); + + // Act + await service.BlockeFriendAsync(50); + + // Assert + var updated = await context.Friends.FindAsync(50); + Assert.Equal(FriendStatus.Blocked, updated.StatusEnum); + } + + [Fact] + public async Task GetFriendListAsync_ShouldFilterByStatus() + { + // Arrange + var context = CreateDbContext(); + context.Friends.AddRange( + new Friend { UserId = 1, FriendId = 2, StatusEnum = FriendStatus.Added }, + new Friend { UserId = 1, FriendId = 3, StatusEnum = FriendStatus.Blocked } + ); + await context.SaveChangesAsync(); + var service = CreateService(context); + + // Act + var result = await service.GetFriendListAsync(1, 1, 10, false); + + // Assert + Assert.Single(result); // 只应该拿到 Added 状态的 + } +} \ No newline at end of file diff --git a/backend/IMTest/bin/Debug/net8.0/IMTest.deps.json b/backend/IMTest/bin/Debug/net8.0/IMTest.deps.json index ffb6077..63c1c96 100644 --- a/backend/IMTest/bin/Debug/net8.0/IMTest.deps.json +++ b/backend/IMTest/bin/Debug/net8.0/IMTest.deps.json @@ -55,6 +55,42 @@ } }, "coverlet.collector/6.0.0": {}, + "MassTransit/8.5.5": { + "dependencies": { + "MassTransit.Abstractions": "8.5.5", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Diagnostics.HealthChecks": "8.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "8.0.1", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2" + }, + "runtime": { + "lib/net8.0/MassTransit.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, + "MassTransit.Abstractions/8.5.5": { + "runtime": { + "lib/net8.0/MassTransit.Abstractions.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, + "MassTransit.RabbitMQ/8.5.5": { + "dependencies": { + "MassTransit": "8.5.5", + "RabbitMQ.Client": "7.1.2" + }, + "runtime": { + "lib/net8.0/MassTransit.RabbitMqTransport.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, "Microsoft.AspNetCore.Authentication.Abstractions/2.3.0": { "dependencies": { "Microsoft.AspNetCore.Http.Abstractions": "2.3.0", @@ -326,6 +362,15 @@ } } }, + "Microsoft.Extensions.Diagnostics.HealthChecks/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions": "8.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "8.0.1", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2" + } + }, + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions/8.0.0": {}, "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "dependencies": { "Microsoft.Extensions.Primitives": "8.0.0" @@ -843,6 +888,18 @@ } } }, + "RabbitMQ.Client/7.1.2": { + "dependencies": { + "System.IO.Pipelines": "8.0.0", + "System.Threading.RateLimiting": "8.0.0" + }, + "runtime": { + "lib/net8.0/RabbitMQ.Client.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.1.2.0" + } + } + }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": {}, @@ -1455,6 +1512,7 @@ } }, "System.Threading.Channels/8.0.0": {}, + "System.Threading.RateLimiting/8.0.0": {}, "System.Threading.Tasks/4.3.0": { "dependencies": { "Microsoft.NETCore.Platforms": "1.1.0", @@ -1573,6 +1631,7 @@ "dependencies": { "AutoMapper": "12.0.1", "AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.0", + "MassTransit.RabbitMQ": "8.5.5", "Microsoft.AspNetCore.Authentication.JwtBearer": "8.0.21", "Microsoft.AspNetCore.SignalR": "1.2.0", "Microsoft.VisualStudio.Azure.Containers.Tools.Targets": "1.22.1", @@ -1625,6 +1684,27 @@ "path": "coverlet.collector/6.0.0", "hashPath": "coverlet.collector.6.0.0.nupkg.sha512" }, + "MassTransit/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bSg8k5q+rP1s+dIGXLLbctqDGdIkfDjdxwNWtCUH7xNCN9ZuM7mqSPQPIFgaYIi34e81m4FqAqo4CAHuWPkhRA==", + "path": "masstransit/8.5.5", + "hashPath": "masstransit.8.5.5.nupkg.sha512" + }, + "MassTransit.Abstractions/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0mn2Ay17dD6z5tgSLjbVRlldSbL9iowzFEfVgVfBXVG5ttz9dSWeR4TrdD6pqH93GWXp4CvSmF8i1HqxLX7DZw==", + "path": "masstransit.abstractions/8.5.5", + "hashPath": "masstransit.abstractions.8.5.5.nupkg.sha512" + }, + "MassTransit.RabbitMQ/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UxWn4o90YVMF9PBkJeoskOFPneh6YtnI1fLJHtvZiSAG0eoiRrWPGa+6FQCvjkQ/ljCKfjzok2eGZc/vmNZ01A==", + "path": "masstransit.rabbitmq/8.5.5", + "hashPath": "masstransit.rabbitmq.8.5.5.nupkg.sha512" + }, "Microsoft.AspNetCore.Authentication.Abstractions/2.3.0": { "type": "package", "serviceable": true, @@ -1870,6 +1950,20 @@ "path": "microsoft.extensions.diagnostics.abstractions/8.0.1", "hashPath": "microsoft.extensions.diagnostics.abstractions.8.0.1.nupkg.sha512" }, + "Microsoft.Extensions.Diagnostics.HealthChecks/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-P9SoBuVZhJPpALZmSq72aQEb9ryP67EdquaCZGXGrrcASTNHYdrUhnpgSwIipgM5oVC+dKpRXg5zxobmF9xr5g==", + "path": "microsoft.extensions.diagnostics.healthchecks/8.0.0", + "hashPath": "microsoft.extensions.diagnostics.healthchecks.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AT2qqos3IgI09ok36Qag9T8bb6kHJ3uT9Q5ki6CySybFsK6/9JbvQAgAHf1pVEjST0/N4JaFaCbm40R5edffwg==", + "path": "microsoft.extensions.diagnostics.healthchecks.abstractions/8.0.0", + "hashPath": "microsoft.extensions.diagnostics.healthchecks.abstractions.8.0.0.nupkg.sha512" + }, "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "type": "package", "serviceable": true, @@ -2073,6 +2167,13 @@ "path": "pomelo.entityframeworkcore.mysql/8.0.3", "hashPath": "pomelo.entityframeworkcore.mysql.8.0.3.nupkg.sha512" }, + "RabbitMQ.Client/7.1.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y3c6ulgULScWthHw5PLM1ShHRLhxg0vCtzX/hh61gRgNecL3ZC3WoBW2HYHoXOVRqTl99Br9E7CZEytGZEsCyQ==", + "path": "rabbitmq.client/7.1.2", + "hashPath": "rabbitmq.client.7.1.2.nupkg.sha512" + }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl/4.3.0": { "type": "package", "serviceable": true, @@ -2605,6 +2706,13 @@ "path": "system.threading.channels/8.0.0", "hashPath": "system.threading.channels.8.0.0.nupkg.sha512" }, + "System.Threading.RateLimiting/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7mu9v0QDv66ar3DpGSZHg9NuNcxDaaAcnMULuZlaTpP9+hwXhrxNGsF5GmLkSHxFdb5bBc1TzeujsRgTrPWi+Q==", + "path": "system.threading.ratelimiting/8.0.0", + "hashPath": "system.threading.ratelimiting.8.0.0.nupkg.sha512" + }, "System.Threading.Tasks/4.3.0": { "type": "package", "serviceable": true, diff --git a/backend/IMTest/bin/Debug/net8.0/IMTest.dll b/backend/IMTest/bin/Debug/net8.0/IMTest.dll index a4a7827..697ced0 100644 Binary files a/backend/IMTest/bin/Debug/net8.0/IMTest.dll and b/backend/IMTest/bin/Debug/net8.0/IMTest.dll differ diff --git a/backend/IMTest/bin/Debug/net8.0/IMTest.pdb b/backend/IMTest/bin/Debug/net8.0/IMTest.pdb index d7f873d..fd1edfb 100644 Binary files a/backend/IMTest/bin/Debug/net8.0/IMTest.pdb and b/backend/IMTest/bin/Debug/net8.0/IMTest.pdb differ diff --git a/backend/IMTest/bin/Debug/net8.0/IM_API.deps.json b/backend/IMTest/bin/Debug/net8.0/IM_API.deps.json index edb2cfb..28566e9 100644 --- a/backend/IMTest/bin/Debug/net8.0/IM_API.deps.json +++ b/backend/IMTest/bin/Debug/net8.0/IM_API.deps.json @@ -10,6 +10,7 @@ "dependencies": { "AutoMapper": "12.0.1", "AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.0", + "MassTransit.RabbitMQ": "8.5.5", "Microsoft.AspNetCore.Authentication.JwtBearer": "8.0.21", "Microsoft.AspNetCore.SignalR": "1.2.0", "Microsoft.EntityFrameworkCore.Design": "8.0.21", @@ -56,6 +57,42 @@ } } }, + "MassTransit/8.5.5": { + "dependencies": { + "MassTransit.Abstractions": "8.5.5", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Diagnostics.HealthChecks": "8.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "8.0.1", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2" + }, + "runtime": { + "lib/net8.0/MassTransit.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, + "MassTransit.Abstractions/8.5.5": { + "runtime": { + "lib/net8.0/MassTransit.Abstractions.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, + "MassTransit.RabbitMQ/8.5.5": { + "dependencies": { + "MassTransit": "8.5.5", + "RabbitMQ.Client": "7.1.2" + }, + "runtime": { + "lib/net8.0/MassTransit.RabbitMqTransport.dll": { + "assemblyVersion": "8.5.5.0", + "fileVersion": "8.5.5.0" + } + } + }, "Microsoft.AspNetCore.Authentication.Abstractions/2.3.0": { "dependencies": { "Microsoft.AspNetCore.Http.Abstractions": "2.3.0", @@ -565,6 +602,15 @@ } } }, + "Microsoft.Extensions.Diagnostics.HealthChecks/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions": "8.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "8.0.1", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2" + } + }, + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions/8.0.0": {}, "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "dependencies": { "Microsoft.Extensions.Primitives": "8.0.0" @@ -764,6 +810,18 @@ } } }, + "RabbitMQ.Client/7.1.2": { + "dependencies": { + "System.IO.Pipelines": "8.0.0", + "System.Threading.RateLimiting": "8.0.0" + }, + "runtime": { + "lib/net8.0/RabbitMQ.Client.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.1.2.0" + } + } + }, "StackExchange.Redis/2.9.32": { "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "8.0.2", @@ -922,7 +980,8 @@ } }, "System.Text.Encodings.Web/8.0.0": {}, - "System.Threading.Channels/8.0.0": {} + "System.Threading.Channels/8.0.0": {}, + "System.Threading.RateLimiting/8.0.0": {} } }, "libraries": { @@ -952,6 +1011,27 @@ "path": "humanizer.core/2.14.1", "hashPath": "humanizer.core.2.14.1.nupkg.sha512" }, + "MassTransit/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bSg8k5q+rP1s+dIGXLLbctqDGdIkfDjdxwNWtCUH7xNCN9ZuM7mqSPQPIFgaYIi34e81m4FqAqo4CAHuWPkhRA==", + "path": "masstransit/8.5.5", + "hashPath": "masstransit.8.5.5.nupkg.sha512" + }, + "MassTransit.Abstractions/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0mn2Ay17dD6z5tgSLjbVRlldSbL9iowzFEfVgVfBXVG5ttz9dSWeR4TrdD6pqH93GWXp4CvSmF8i1HqxLX7DZw==", + "path": "masstransit.abstractions/8.5.5", + "hashPath": "masstransit.abstractions.8.5.5.nupkg.sha512" + }, + "MassTransit.RabbitMQ/8.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UxWn4o90YVMF9PBkJeoskOFPneh6YtnI1fLJHtvZiSAG0eoiRrWPGa+6FQCvjkQ/ljCKfjzok2eGZc/vmNZ01A==", + "path": "masstransit.rabbitmq/8.5.5", + "hashPath": "masstransit.rabbitmq.8.5.5.nupkg.sha512" + }, "Microsoft.AspNetCore.Authentication.Abstractions/2.3.0": { "type": "package", "serviceable": true, @@ -1246,6 +1326,20 @@ "path": "microsoft.extensions.diagnostics.abstractions/8.0.1", "hashPath": "microsoft.extensions.diagnostics.abstractions.8.0.1.nupkg.sha512" }, + "Microsoft.Extensions.Diagnostics.HealthChecks/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-P9SoBuVZhJPpALZmSq72aQEb9ryP67EdquaCZGXGrrcASTNHYdrUhnpgSwIipgM5oVC+dKpRXg5zxobmF9xr5g==", + "path": "microsoft.extensions.diagnostics.healthchecks/8.0.0", + "hashPath": "microsoft.extensions.diagnostics.healthchecks.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AT2qqos3IgI09ok36Qag9T8bb6kHJ3uT9Q5ki6CySybFsK6/9JbvQAgAHf1pVEjST0/N4JaFaCbm40R5edffwg==", + "path": "microsoft.extensions.diagnostics.healthchecks.abstractions/8.0.0", + "hashPath": "microsoft.extensions.diagnostics.healthchecks.abstractions.8.0.0.nupkg.sha512" + }, "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { "type": "package", "serviceable": true, @@ -1393,6 +1487,13 @@ "path": "pomelo.entityframeworkcore.mysql/8.0.3", "hashPath": "pomelo.entityframeworkcore.mysql.8.0.3.nupkg.sha512" }, + "RabbitMQ.Client/7.1.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y3c6ulgULScWthHw5PLM1ShHRLhxg0vCtzX/hh61gRgNecL3ZC3WoBW2HYHoXOVRqTl99Br9E7CZEytGZEsCyQ==", + "path": "rabbitmq.client/7.1.2", + "hashPath": "rabbitmq.client.7.1.2.nupkg.sha512" + }, "StackExchange.Redis/2.9.32": { "type": "package", "serviceable": true, @@ -1553,6 +1654,13 @@ "sha512": "sha512-CMaFr7v+57RW7uZfZkPExsPB6ljwzhjACWW1gfU35Y56rk72B/Wu+sTqxVmGSk4SFUlPc3cjeKND0zktziyjBA==", "path": "system.threading.channels/8.0.0", "hashPath": "system.threading.channels.8.0.0.nupkg.sha512" + }, + "System.Threading.RateLimiting/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7mu9v0QDv66ar3DpGSZHg9NuNcxDaaAcnMULuZlaTpP9+hwXhrxNGsF5GmLkSHxFdb5bBc1TzeujsRgTrPWi+Q==", + "path": "system.threading.ratelimiting/8.0.0", + "hashPath": "system.threading.ratelimiting.8.0.0.nupkg.sha512" } } } \ No newline at end of file diff --git a/backend/IMTest/bin/Debug/net8.0/IM_API.dll b/backend/IMTest/bin/Debug/net8.0/IM_API.dll index 562d8b5..40f617b 100644 Binary files a/backend/IMTest/bin/Debug/net8.0/IM_API.dll and b/backend/IMTest/bin/Debug/net8.0/IM_API.dll differ diff --git a/backend/IMTest/bin/Debug/net8.0/IM_API.exe b/backend/IMTest/bin/Debug/net8.0/IM_API.exe index 1292e00..586f6e8 100644 Binary files a/backend/IMTest/bin/Debug/net8.0/IM_API.exe and b/backend/IMTest/bin/Debug/net8.0/IM_API.exe differ diff --git a/backend/IMTest/bin/Debug/net8.0/IM_API.pdb b/backend/IMTest/bin/Debug/net8.0/IM_API.pdb index 632c921..df4373c 100644 Binary files a/backend/IMTest/bin/Debug/net8.0/IM_API.pdb and b/backend/IMTest/bin/Debug/net8.0/IM_API.pdb differ diff --git a/backend/IMTest/bin/Debug/net8.0/appsettings.json b/backend/IMTest/bin/Debug/net8.0/appsettings.json index 9da907c..fc895fb 100644 --- a/backend/IMTest/bin/Debug/net8.0/appsettings.json +++ b/backend/IMTest/bin/Debug/net8.0/appsettings.json @@ -16,5 +16,11 @@ "ConnectionStrings": { "DefaultConnection": "Server=frp-era.com;Port=26582;Database=IM;User=product;Password=12345678;", "Redis": "192.168.5.100:6379" + }, + "RabbitMQOptions": { + "Host": "192.168.5.100", + "Port": 5672, + "Username": "test", + "Password": "123456" } } diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfo.cs b/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfo.cs index 9319c84..dfe6178 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfo.cs +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfo.cs @@ -14,7 +14,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("IMTest")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+7ebf23ddd8a0d5536167313c4cf37af1552a5057")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+83be063e7fbdba82984ef3beb231bd8a0a983c2f")] [assembly: System.Reflection.AssemblyProductAttribute("IMTest")] [assembly: System.Reflection.AssemblyTitleAttribute("IMTest")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfoInputs.cache b/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfoInputs.cache index 8fe6643..937da7a 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfoInputs.cache +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.AssemblyInfoInputs.cache @@ -1 +1 @@ -ca0390a4d5773daae2e747d7512c190701a7a942186c769e42327a4864733f0b +495895405696fa7fe9836aaaa2da1791d39c26be9cfe301758e0fe7d7c9164b6 diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.GeneratedMSBuildEditorConfig.editorconfig b/backend/IMTest/obj/Debug/net8.0/IMTest.GeneratedMSBuildEditorConfig.editorconfig index c718a10..aa41851 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.GeneratedMSBuildEditorConfig.editorconfig +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.GeneratedMSBuildEditorConfig.editorconfig @@ -1,7 +1,5 @@ is_global = true build_property.TargetFramework = net8.0 -build_property.TargetFrameworkIdentifier = .NETCoreApp -build_property.TargetFrameworkVersion = v8.0 build_property.TargetPlatformMinVersion = build_property.UsingMicrosoftNETSdkWeb = build_property.ProjectTypeGuids = diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.GlobalUsings.g.cs b/backend/IMTest/obj/Debug/net8.0/IMTest.GlobalUsings.g.cs index fe43752..2cd3d38 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.GlobalUsings.g.cs +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.GlobalUsings.g.cs @@ -1,9 +1,9 @@ // -global using System; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.Net.Http; -global using System.Threading; -global using System.Threading.Tasks; -global using Xunit; +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; +global using global::Xunit; diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.assets.cache b/backend/IMTest/obj/Debug/net8.0/IMTest.assets.cache index 94ea5c2..5432714 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/IMTest.assets.cache and b/backend/IMTest/obj/Debug/net8.0/IMTest.assets.cache differ diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.AssemblyReference.cache b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.AssemblyReference.cache index c202171..bfc429b 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.AssemblyReference.cache and b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.AssemblyReference.cache differ diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.CoreCompileInputs.cache b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.CoreCompileInputs.cache index a628f3f..290ddcd 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.CoreCompileInputs.cache +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -b97252705aa63c43e1310042fe4fd7115206f72ef0f55d39109c2b849fe2a37e +97ad978fabe5fb8f7f258c9878659ee9a5f2492332ad5efd70b1d456ebc42a59 diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.FileListAbsolute.txt b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.FileListAbsolute.txt index d11a777..6923254 100644 --- a/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.FileListAbsolute.txt +++ b/backend/IMTest/obj/Debug/net8.0/IMTest.csproj.FileListAbsolute.txt @@ -140,3 +140,7 @@ C:\Users\nanxun\Documents\IM\backend\IMTest\obj\Debug\net8.0\refint\IMTest.dll C:\Users\nanxun\Documents\IM\backend\IMTest\obj\Debug\net8.0\IMTest.pdb C:\Users\nanxun\Documents\IM\backend\IMTest\obj\Debug\net8.0\IMTest.genruntimeconfig.cache C:\Users\nanxun\Documents\IM\backend\IMTest\obj\Debug\net8.0\ref\IMTest.dll +C:\Users\nanxun\Documents\IM\backend\IMTest\bin\Debug\net8.0\MassTransit.dll +C:\Users\nanxun\Documents\IM\backend\IMTest\bin\Debug\net8.0\MassTransit.Abstractions.dll +C:\Users\nanxun\Documents\IM\backend\IMTest\bin\Debug\net8.0\MassTransit.RabbitMqTransport.dll +C:\Users\nanxun\Documents\IM\backend\IMTest\bin\Debug\net8.0\RabbitMQ.Client.dll diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.dll b/backend/IMTest/obj/Debug/net8.0/IMTest.dll index a4a7827..697ced0 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/IMTest.dll and b/backend/IMTest/obj/Debug/net8.0/IMTest.dll differ diff --git a/backend/IMTest/obj/Debug/net8.0/IMTest.pdb b/backend/IMTest/obj/Debug/net8.0/IMTest.pdb index d7f873d..fd1edfb 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/IMTest.pdb and b/backend/IMTest/obj/Debug/net8.0/IMTest.pdb differ diff --git a/backend/IMTest/obj/Debug/net8.0/ref/IMTest.dll b/backend/IMTest/obj/Debug/net8.0/ref/IMTest.dll index 79b0187..dc8e36e 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/ref/IMTest.dll and b/backend/IMTest/obj/Debug/net8.0/ref/IMTest.dll differ diff --git a/backend/IMTest/obj/Debug/net8.0/refint/IMTest.dll b/backend/IMTest/obj/Debug/net8.0/refint/IMTest.dll index 79b0187..dc8e36e 100644 Binary files a/backend/IMTest/obj/Debug/net8.0/refint/IMTest.dll and b/backend/IMTest/obj/Debug/net8.0/refint/IMTest.dll differ diff --git a/backend/IMTest/obj/IMTest.csproj.nuget.dgspec.json b/backend/IMTest/obj/IMTest.csproj.nuget.dgspec.json index ab66086..3a75a9e 100644 --- a/backend/IMTest/obj/IMTest.csproj.nuget.dgspec.json +++ b/backend/IMTest/obj/IMTest.csproj.nuget.dgspec.json @@ -49,7 +49,7 @@ "auditLevel": "low", "auditMode": "direct" }, - "SdkAnalysisLevel": "10.0.100" + "SdkAnalysisLevel": "9.0.300" }, "frameworks": { "net8.0": { @@ -96,7 +96,7 @@ "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json" } } }, @@ -141,7 +141,7 @@ "auditLevel": "low", "auditMode": "direct" }, - "SdkAnalysisLevel": "10.0.100" + "SdkAnalysisLevel": "9.0.300" }, "frameworks": { "net8.0": { @@ -223,7 +223,7 @@ "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json" } } } diff --git a/backend/IMTest/obj/IMTest.csproj.nuget.g.props b/backend/IMTest/obj/IMTest.csproj.nuget.g.props index 89b6bef..a72789c 100644 --- a/backend/IMTest/obj/IMTest.csproj.nuget.g.props +++ b/backend/IMTest/obj/IMTest.csproj.nuget.g.props @@ -7,7 +7,7 @@ $(UserProfile)\.nuget\packages\ C:\Users\nanxun\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages PackageReference - 7.0.0 + 6.14.1 diff --git a/backend/IMTest/obj/project.assets.json b/backend/IMTest/obj/project.assets.json index 411bfb3..04dbca1 100644 --- a/backend/IMTest/obj/project.assets.json +++ b/backend/IMTest/obj/project.assets.json @@ -8805,7 +8805,7 @@ "auditLevel": "low", "auditMode": "direct" }, - "SdkAnalysisLevel": "10.0.100" + "SdkAnalysisLevel": "9.0.300" }, "frameworks": { "net8.0": { @@ -8852,16 +8852,8 @@ "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.102/PortableRuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json" } } - }, - "logs": [ - { - "code": "Undefined", - "level": "Warning", - "warningLevel": 1, - "message": "读取缓存文件 C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\obj\\project.nuget.cache 时遇到问题: '<' is an invalid start of a property name. Expected a '\"'. Path: $ | LineNumber: 2 | BytePositionInLine: 0." - } - ] + } } \ No newline at end of file diff --git a/backend/IMTest/obj/project.nuget.cache b/backend/IMTest/obj/project.nuget.cache index 18f8666..8ba4b76 100644 --- a/backend/IMTest/obj/project.nuget.cache +++ b/backend/IMTest/obj/project.nuget.cache @@ -1,6 +1,6 @@ { "version": 2, - "dgSpecHash": "j7OjEXb1ZGE=", + "dgSpecHash": "tVGTA3KwBHQ=", "success": true, "projectFilePath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj", "expectedPackageFiles": [ @@ -169,15 +169,5 @@ "C:\\Users\\nanxun\\.nuget\\packages\\xunit.extensibility.execution\\2.5.3\\xunit.extensibility.execution.2.5.3.nupkg.sha512", "C:\\Users\\nanxun\\.nuget\\packages\\xunit.runner.visualstudio\\2.5.3\\xunit.runner.visualstudio.2.5.3.nupkg.sha512" ], - "logs": [ - { - "code": "Undefined", - "level": "Warning", - "message": "读取缓存文件 C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\obj\\project.nuget.cache 时遇到问题: '<' is an invalid start of a property name. Expected a '\"'. Path: $ | LineNumber: 2 | BytePositionInLine: 0.", - "projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj", - "warningLevel": 1, - "filePath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj", - "targetGraphs": [] - } - ] + "logs": [] } \ No newline at end of file diff --git a/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddConversationHandler.cs b/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddConversationHandler.cs index 99f62fe..929deae 100644 --- a/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddConversationHandler.cs +++ b/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddConversationHandler.cs @@ -1,13 +1,26 @@ using IM_API.Domain.Events; +using IM_API.Interface.Services; using MassTransit; namespace IM_API.Application.EventHandlers.FriendAddHandler { public class FriendAddConversationHandler : IConsumer { - public Task Consume(ConsumeContext context) + private readonly IFriendSerivce _friendService; + public FriendAddConversationHandler(IFriendSerivce friendService) { - throw new NotImplementedException(); + _friendService = friendService; + } + + public async Task Consume(ConsumeContext context) + { + var @event = context.Message; + //为请求发起人添加好友记录 + await _friendService.MakeFriendshipAsync( + @event.RequestUserId, @event.ResponseUserId, @event.RequestInfo.RemarkName); + //为接收人添加好友记录 + await _friendService.MakeFriendshipAsync( + @event.ResponseUserId, @event.RequestUserId, @event.requestUserRemarkname); } } } diff --git a/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddSignalRHandler.cs b/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddSignalRHandler.cs index 31cb723..77e046c 100644 --- a/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddSignalRHandler.cs +++ b/backend/IM_API/Application/EventHandlers/FriendAddHandler/FriendAddSignalRHandler.cs @@ -1,28 +1,37 @@ using IM_API.Domain.Events; +using IM_API.Dtos; +using IM_API.Hubs; using IM_API.Interface.Services; using IM_API.Models; using MassTransit; +using Microsoft.AspNetCore.SignalR; namespace IM_API.Application.EventHandlers.FriendAddHandler { public class FriendAddSignalRHandler : IConsumer { - private readonly IFriendSerivce _friendService; - public FriendAddSignalRHandler(IFriendSerivce friendSerivce) + private readonly IHubContext _chathub; + public FriendAddSignalRHandler(IHubContext chathub) { - _friendService = friendSerivce; + _chathub = chathub; } public async Task Consume(ConsumeContext context) { var @event = context.Message; - //为请求发起人添加好友记录 - await _friendService.MakeFriendshipAsync( - @event.RequestUser.Id, @event.ResponseUser.Id, @event.RequestInfo.RemarkName); - //为接收人添加好友记录 - await _friendService.MakeFriendshipAsync( - @event.ResponseUser.Id, @event.RequestUser.Id, @event.requestUserRemarkname); - + var usersList = new List { + @event.RequestUserId.ToString(), @event.ResponseUserId.ToString() + }; + var res = new HubResponse("Event", new MessageBaseDto() + { + ChatType = ChatType.PRIVATE, + Content = "您有新的好友关系已添加", + MsgId = @event.EventId.ToString(), + ReceiverId = @event.ResponseUserId, + SenderId = @event.RequestUserId, + TimeStamp = DateTime.UtcNow + }); + await _chathub.Clients.Users(usersList).SendAsync("ReceiveMessage", res); } } } diff --git a/backend/IM_API/Application/EventHandlers/MessageCreatedHandler/SignalREventHandler.cs b/backend/IM_API/Application/EventHandlers/MessageCreatedHandler/SignalREventHandler.cs index 643642c..a103658 100644 --- a/backend/IM_API/Application/EventHandlers/MessageCreatedHandler/SignalREventHandler.cs +++ b/backend/IM_API/Application/EventHandlers/MessageCreatedHandler/SignalREventHandler.cs @@ -28,13 +28,13 @@ namespace IM_API.Application.EventHandlers.MessageCreatedHandler MessageBaseDto messageBaseDto = new MessageBaseDto { MsgId = @event.MessageId.ToString(), - ChatType = @event.ChatType.ToString(), + ChatType = @event.ChatType, Content = @event.MessageContent, GroupMemberId = null, ReceiverId = @event.MsgRecipientId, SenderId = @event.MsgSenderId, TimeStamp = @event.MessageCreated, - Type = @event.MessageMsgType.ToString() + Type = @event.MessageMsgType }; await _hub.Clients.Users(@event.MsgRecipientId.ToString()).SendAsync("ReceiveMessage", messageBaseDto); } diff --git a/backend/IM_API/Application/EventHandlers/RequestFriendHandler/RequestFriendSignalRHandler.cs b/backend/IM_API/Application/EventHandlers/RequestFriendHandler/RequestFriendSignalRHandler.cs new file mode 100644 index 0000000..35053d1 --- /dev/null +++ b/backend/IM_API/Application/EventHandlers/RequestFriendHandler/RequestFriendSignalRHandler.cs @@ -0,0 +1,36 @@ +using IM_API.Domain.Events; +using IM_API.Dtos; +using IM_API.Hubs; +using IM_API.Interface.Services; +using MassTransit; +using Microsoft.AspNetCore.SignalR; + +namespace IM_API.Application.EventHandlers.RequestFriendHandler +{ + public class RequestFriendSignalRHandler:IConsumer + { + private readonly IHubContext _hub; + private readonly IUserService _userService; + public RequestFriendSignalRHandler(IHubContext hubContext, IUserService userService) + { + _hub = hubContext; + _userService = userService; + } + + public async Task Consume(ConsumeContext context) + { + var @event = context.Message; + var userInfo = await _userService.GetUserInfoAsync(@event.FromUserId); + var res = new HubResponse("Event", new FriendRequestResDto() + { + RequestUser = @event.FromUserId, + ResponseUser = @event.ToUserId, + Created = DateTime.UtcNow, + Description = @event.Description, + Avatar = userInfo.Avatar, + NickName = userInfo.NickName + }); + await _hub.Clients.User(@event.ToUserId.ToString()).SendAsync("ReceiveMessage", res); + } + } +} diff --git a/backend/IM_API/Configs/MapperConfig.cs b/backend/IM_API/Configs/MapperConfig.cs index e196430..09eb2c1 100644 --- a/backend/IM_API/Configs/MapperConfig.cs +++ b/backend/IM_API/Configs/MapperConfig.cs @@ -46,6 +46,13 @@ namespace IM_API.Configs .ForMember(dest => dest.StateEnum , opt => opt.MapFrom(src => FriendRequestState.Pending)) .ForMember(dest => dest.Description , opt => opt.MapFrom(src => src.Description)) ; + + CreateMap() + .ForMember(dest => dest.ToUserId, opt => opt.MapFrom(src => src.ResponseUser)) + .ForMember(dest => dest.FromUserId, opt => opt.MapFrom(src => src.RequestUser)) + .ForMember(dest => dest.RemarkName, opt => opt.MapFrom(src => src.RemarkName)) + .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description)) + ; //消息模型转换 CreateMap() .ForMember(dest => dest.Type , opt => opt.MapFrom(src => src.MsgTypeEnum.ToString())) @@ -59,8 +66,8 @@ namespace IM_API.Configs ; CreateMap() .ForMember(dest => dest.Sender, opt => opt.MapFrom(src => src.SenderId)) - .ForMember(dest => dest.ChatTypeEnum,opt => opt.MapFrom(src => Enum.Parse(src.ChatType,true))) - .ForMember(dest => dest.MsgTypeEnum, opt => opt.MapFrom(src => Enum.Parse(src.Type,true))) + .ForMember(dest => dest.ChatTypeEnum,opt => opt.MapFrom(src => src.ChatType)) + .ForMember(dest => dest.MsgTypeEnum, opt => opt.MapFrom(src => src.Type)) .ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.TimeStamp)) .ForMember(dest => dest.Content, opt => opt.MapFrom(src => src.Content)) .ForMember(dest => dest.Recipient, opt => opt.MapFrom(src => src.ReceiverId)) diff --git a/backend/IM_API/Domain/Events/FriendAddEvent.cs b/backend/IM_API/Domain/Events/FriendAddEvent.cs index fefce14..2ed471a 100644 --- a/backend/IM_API/Domain/Events/FriendAddEvent.cs +++ b/backend/IM_API/Domain/Events/FriendAddEvent.cs @@ -8,12 +8,12 @@ namespace IM_API.Domain.Events /// /// 发起请求用户 /// - public UserInfoDto RequestUser { get; init; } + public int RequestUserId { get; init; } public string? requestUserRemarkname { get; init; } /// /// 接受请求用户 /// - public UserInfoDto ResponseUser { get; init; } + public int ResponseUserId { get; init; } public FriendRequestDto RequestInfo { get; init; } /// diff --git a/backend/IM_API/Domain/Events/RequestFriendEvent.cs b/backend/IM_API/Domain/Events/RequestFriendEvent.cs new file mode 100644 index 0000000..62a80ce --- /dev/null +++ b/backend/IM_API/Domain/Events/RequestFriendEvent.cs @@ -0,0 +1,10 @@ +namespace IM_API.Domain.Events +{ + public record RequestFriendEvent : DomainEvent + { + public override string EventType => "IM.FRIENDS_FRIEND_REQUEST"; + public int FromUserId { get; init; } + public int ToUserId { get; init; } + public string Description { get; init; } + } +} diff --git a/backend/IM_API/Dtos/HubResponse.cs b/backend/IM_API/Dtos/HubResponse.cs new file mode 100644 index 0000000..eb167bf --- /dev/null +++ b/backend/IM_API/Dtos/HubResponse.cs @@ -0,0 +1,47 @@ +using IM_API.Tools; + +namespace IM_API.Dtos +{ + public class HubResponse + { + public int Code { get; init; } + public string Method { get; init; } + public HubResponseType Type { get; init; } + public string Message { get; init; } + public T? Data { get; init; } + public HubResponse(string method) + { + Code = CodeDefine.SUCCESS.Code; + Message = CodeDefine.SUCCESS.Message; + Type = HubResponseType.ActionStatus; + } + public HubResponse(string method,T data) + { + Code = CodeDefine.SUCCESS.Code; + Message = CodeDefine.SUCCESS.Message; + Type = HubResponseType.ActionStatus; + Data = data; + } + public HubResponse(CodeDefine codedefine,string method) + { + Code = codedefine.Code; + Method = method; + Message = codedefine.Message; + Type = HubResponseType.ActionStatus; + } + public HubResponse(CodeDefine codeDefine, string method, HubResponseType type, T? data) + { + Code = codeDefine.Code; + Method = method; + Type = type; + Message = codeDefine.Message; + Data = data; + } + } + public enum HubResponseType + { + ChatMsg = 1, // 聊天内容 + SystemNotice = 2, // 系统通知(如:申请好友成功) + ActionStatus = 3 // 状态变更(如:对方正在输入、已读回执) + } +} diff --git a/backend/IM_API/Dtos/MessageDto.cs b/backend/IM_API/Dtos/MessageDto.cs index c7bcac6..a546b89 100644 --- a/backend/IM_API/Dtos/MessageDto.cs +++ b/backend/IM_API/Dtos/MessageDto.cs @@ -1,10 +1,12 @@ -namespace IM_API.Dtos +using IM_API.Models; + +namespace IM_API.Dtos { public record MessageBaseDto { // 使用 { get; init; } 确保对象创建后不可修改,且支持无参构造 - public string Type { get; init; } = default!; - public string ChatType { get; init; } = default!; + public MessageMsgType Type { get; init; } = default!; + public ChatType ChatType { get; init; } = default!; public string? MsgId { get; init; } public int SenderId { get; init; } public int ReceiverId { get; init; } diff --git a/backend/IM_API/Hubs/ChatHub.cs b/backend/IM_API/Hubs/ChatHub.cs index 37a26eb..da23832 100644 --- a/backend/IM_API/Hubs/ChatHub.cs +++ b/backend/IM_API/Hubs/ChatHub.cs @@ -40,17 +40,17 @@ namespace IM_API.Hubs } await base.OnConnectedAsync(); } - public async Task SendMessage(MessageBaseDto dto) + public async Task> SendMessage(MessageBaseDto dto) { if (!Context.User.Identity.IsAuthenticated) { await Clients.Caller.SendAsync("ReceiveMessage", new BaseResponse(CodeDefine.AUTH_FAILED)); Context.Abort(); - return; + return new HubResponse(CodeDefine.AUTH_FAILED, "SendMessage"); } var userIdStr = Context.User.FindFirstValue(ClaimTypes.NameIdentifier); MessageBaseDto msgInfo = null; - if(dto.ChatType.ToLower() == ChatType.PRIVATE.ToString().ToLower()) + if(dto.ChatType == ChatType.PRIVATE) { msgInfo = await _messageService.SendPrivateMessageAsync(int.Parse(userIdStr), dto.ReceiverId, dto); } @@ -58,19 +58,19 @@ namespace IM_API.Hubs { msgInfo = await _messageService.SendGroupMessageAsync(int.Parse(userIdStr), dto.ReceiverId, dto); } - return; + return new HubResponse("SendMessage", msgInfo); } - public async Task ClearUnreadCount(int conversationId) + public async Task> ClearUnreadCount(int conversationId) { if (!Context.User.Identity.IsAuthenticated) { await Clients.Caller.SendAsync("ReceiveMessage", new BaseResponse(CodeDefine.AUTH_FAILED)); Context.Abort(); - return; + return new HubResponse(CodeDefine.AUTH_FAILED, "ClearUnreadCount"); ; } var userIdStr = Context.User.FindFirstValue(ClaimTypes.NameIdentifier); await _conversationService.ClearUnreadCountAsync(int.Parse(userIdStr), conversationId); - return; + return new HubResponse("ClearUnreadCount"); } } } diff --git a/backend/IM_API/Models/Friendrequest.cs b/backend/IM_API/Models/Friendrequest.cs index 3897a5e..2c969b9 100644 --- a/backend/IM_API/Models/Friendrequest.cs +++ b/backend/IM_API/Models/Friendrequest.cs @@ -32,6 +32,11 @@ public partial class FriendRequest /// public sbyte State { get; set; } + /// + /// 备注 + /// + public string RemarkName { get; set; } = null!; + public virtual User RequestUserNavigation { get; set; } = null!; public virtual User ResponseUserNavigation { get; set; } = null!; diff --git a/backend/IM_API/Models/ImContext.cs b/backend/IM_API/Models/ImContext.cs index eac2179..a112714 100644 --- a/backend/IM_API/Models/ImContext.cs +++ b/backend/IM_API/Models/ImContext.cs @@ -281,6 +281,9 @@ public partial class ImContext : DbContext entity.Property(e => e.Description) .HasComment("申请附言 ") .HasColumnType("text"); + entity.Property(e => e.RemarkName) + .HasMaxLength(20) + .HasComment("备注"); entity.Property(e => e.RequestUser) .HasComment("申请人 ") .HasColumnType("int(11)"); diff --git a/backend/IM_API/Program.cs b/backend/IM_API/Program.cs index 2ad90d3..8454049 100644 --- a/backend/IM_API/Program.cs +++ b/backend/IM_API/Program.cs @@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using StackExchange.Redis; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; namespace IM_API { @@ -38,7 +40,12 @@ namespace IM_API builder.Services.AddAllService(configuration); - builder.Services.AddSignalR(); + builder.Services.AddSignalR().AddJsonProtocol(options => + { + // öַ + options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.PayloadSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); //Դ builder.Services.AddCors(options => { @@ -110,6 +117,10 @@ namespace IM_API { // ISO 8601 ʽ options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter()); + // öתΪַ + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + // 飺շ + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; }); builder.Services.AddModelValidation(configuration); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle diff --git a/backend/IM_API/Services/FriendService.cs b/backend/IM_API/Services/FriendService.cs index a372be8..9511525 100644 --- a/backend/IM_API/Services/FriendService.cs +++ b/backend/IM_API/Services/FriendService.cs @@ -1,9 +1,11 @@ using AutoMapper; +using IM_API.Domain.Events; using IM_API.Dtos; using IM_API.Exceptions; using IM_API.Interface.Services; using IM_API.Models; using IM_API.Tools; +using MassTransit; using Microsoft.EntityFrameworkCore; namespace IM_API.Services @@ -13,11 +15,13 @@ namespace IM_API.Services private readonly ImContext _context; private readonly ILogger _logger; private readonly IMapper _mapper; - public FriendService(ImContext context, ILogger logger, IMapper mapper) + private readonly IPublishEndpoint _endpoint; + public FriendService(ImContext context, ILogger logger, IMapper mapper, IPublishEndpoint endpoint) { _context = context; _logger = logger; _mapper = mapper; + _endpoint = endpoint; } #region 拉黑好友 public async Task BlockeFriendAsync(int friendId) @@ -127,13 +131,18 @@ namespace IM_API.Services //同意后标记 case HandleFriendRequestAction.Accept: - friend.StatusEnum = FriendStatus.Added; friendRequest.StateEnum = FriendRequestState.Passed; + await _endpoint.Publish(new FriendAddEvent() + { + AggregateId = friendRequest.Id.ToString(), + OccurredAt = DateTime.UtcNow, + Created = DateTime.UtcNow, + EventId = Guid.NewGuid(), + OperatorId = friendRequest.ResponseUser, + RequestInfo = _mapper.Map(friendRequest), + requestUserRemarkname = requestDto.RemarkName, - //根据当前好友请求为被申请方添加一条好友记录(注意:好友记录为双向) - var ResponseFriend = _mapper.Map(friendRequest); - if (!string.IsNullOrEmpty(requestDto.RemarkName)) ResponseFriend.RemarkName = requestDto.RemarkName; - _context.Friends.Add(ResponseFriend); + }); break; //无效操作 @@ -172,6 +181,16 @@ namespace IM_API.Services var friendRequst = _mapper.Map(dto); _context.FriendRequests.Add(friendRequst); await _context.SaveChangesAsync(); + await _endpoint.Publish(new RequestFriendEvent() + { + AggregateId = friendRequst.Id.ToString(), + OccurredAt = friendRequst.Created, + Description = friendRequst.Description, + EventId = Guid.NewGuid(), + FromUserId = friendRequst.RequestUser, + ToUserId = friendRequst.ResponseUser, + OperatorId = friendRequst.RequestUser + }); return true; } #endregion diff --git a/frontend/web/.env b/frontend/web/.env index c7dcb08..4651767 100644 --- a/frontend/web/.env +++ b/frontend/web/.env @@ -1,4 +1,4 @@ -#VITE_API_BASE_URL = http://localhost:5202/api -#VITE_SIGNALR_BASE_URL = http://localhost:5202/chat -VITE_API_BASE_URL = https://im.test.nxsir.cn/api -VITE_SIGNALR_BASE_URL = https://im.test.nxsir.cn/chat/ \ No newline at end of file +VITE_API_BASE_URL = http://localhost:5202/api +VITE_SIGNALR_BASE_URL = http://localhost:5202/chat/ +#VITE_API_BASE_URL = https://im.test.nxsir.cn/api +#VITE_SIGNALR_BASE_URL = https://im.test.nxsir.cn/chat/ \ No newline at end of file