后端:
新增好友请求事件和好友已添加事件
This commit is contained in:
commit
136199290b
@ -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<IPublishEndpoint> _mockEndpoint = new();
|
||||
private readonly Mock<ILogger<FriendService>> _mockLogger = new();
|
||||
|
||||
#region 辅助构造方法
|
||||
private ImContext CreateDbContext()
|
||||
{
|
||||
var options = new DbContextOptionsBuilder<ImContext>()
|
||||
.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<Friend, FriendInfoDto>();
|
||||
cfg.CreateMap<FriendRequestDto, FriendRequest>();
|
||||
cfg.CreateMap<HandleFriendRequestDto, FriendRequest>();
|
||||
cfg.CreateMap<FriendRequest, Friend>()
|
||||
.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<ILogger<FriendService>>();
|
||||
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<BaseException>(() => 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<Friend>
|
||||
{
|
||||
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<RequestFriendEvent>(e => e.FromUserId == 1 && e.ToUserId == 2),
|
||||
It.IsAny<CancellationToken>()),
|
||||
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<BaseException>(() => 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<BaseException>(() => service.SendFriendRequestAsync(new FriendRequestDto
|
||||
{
|
||||
FromUserId = 10,
|
||||
ToUserId = 99
|
||||
}));
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<BaseException>(() => 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 状态的
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@ -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")]
|
||||
|
||||
@ -1 +1 @@
|
||||
ca0390a4d5773daae2e747d7512c190701a7a942186c769e42327a4864733f0b
|
||||
495895405696fa7fe9836aaaa2da1791d39c26be9cfe301758e0fe7d7c9164b6
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// <auto-generated/>
|
||||
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;
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
b97252705aa63c43e1310042fe4fd7115206f72ef0f55d39109c2b849fe2a37e
|
||||
97ad978fabe5fb8f7f258c9878659ee9a5f2492332ad5efd70b1d456ebc42a59
|
||||
|
||||
@ -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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\nanxun\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
|
||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.1</NuGetToolVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||
<SourceRoot Include="C:\Users\nanxun\.nuget\packages\" />
|
||||
|
||||
@ -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."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -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": []
|
||||
}
|
||||
@ -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<FriendAddEvent>
|
||||
{
|
||||
public Task Consume(ConsumeContext<FriendAddEvent> context)
|
||||
private readonly IFriendSerivce _friendService;
|
||||
public FriendAddConversationHandler(IFriendSerivce friendService)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_friendService = friendService;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<FriendAddEvent> context)
|
||||
{
|
||||
var @event = context.Message;
|
||||
//为请求发起人添加好友记录
|
||||
await _friendService.MakeFriendshipAsync(
|
||||
@event.RequestUserId, @event.ResponseUserId, @event.RequestInfo.RemarkName);
|
||||
//为接收人添加好友记录
|
||||
await _friendService.MakeFriendshipAsync(
|
||||
@event.ResponseUserId, @event.RequestUserId, @event.requestUserRemarkname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<FriendAddEvent>
|
||||
{
|
||||
private readonly IFriendSerivce _friendService;
|
||||
public FriendAddSignalRHandler(IFriendSerivce friendSerivce)
|
||||
private readonly IHubContext<ChatHub> _chathub;
|
||||
public FriendAddSignalRHandler(IHubContext<ChatHub> chathub)
|
||||
{
|
||||
_friendService = friendSerivce;
|
||||
_chathub = chathub;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<FriendAddEvent> 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<string> {
|
||||
@event.RequestUserId.ToString(), @event.ResponseUserId.ToString()
|
||||
};
|
||||
var res = new HubResponse<MessageBaseDto>("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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<RequestFriendEvent>
|
||||
{
|
||||
private readonly IHubContext<ChatHub> _hub;
|
||||
private readonly IUserService _userService;
|
||||
public RequestFriendSignalRHandler(IHubContext<ChatHub> hubContext, IUserService userService)
|
||||
{
|
||||
_hub = hubContext;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<RequestFriendEvent> context)
|
||||
{
|
||||
var @event = context.Message;
|
||||
var userInfo = await _userService.GetUserInfoAsync(@event.FromUserId);
|
||||
var res = new HubResponse<FriendRequestResDto>("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<FriendRequest, FriendRequestDto>()
|
||||
.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<Message, MessageBaseDto>()
|
||||
.ForMember(dest => dest.Type , opt => opt.MapFrom(src => src.MsgTypeEnum.ToString()))
|
||||
@ -59,8 +66,8 @@ namespace IM_API.Configs
|
||||
;
|
||||
CreateMap<MessageBaseDto, Message>()
|
||||
.ForMember(dest => dest.Sender, opt => opt.MapFrom(src => src.SenderId))
|
||||
.ForMember(dest => dest.ChatTypeEnum,opt => opt.MapFrom(src => Enum.Parse<ChatType>(src.ChatType,true)))
|
||||
.ForMember(dest => dest.MsgTypeEnum, opt => opt.MapFrom(src => Enum.Parse<MessageMsgType>(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))
|
||||
|
||||
@ -8,12 +8,12 @@ namespace IM_API.Domain.Events
|
||||
/// <summary>
|
||||
/// 发起请求用户
|
||||
/// </summary>
|
||||
public UserInfoDto RequestUser { get; init; }
|
||||
public int RequestUserId { get; init; }
|
||||
public string? requestUserRemarkname { get; init; }
|
||||
/// <summary>
|
||||
/// 接受请求用户
|
||||
/// </summary>
|
||||
public UserInfoDto ResponseUser { get; init; }
|
||||
public int ResponseUserId { get; init; }
|
||||
|
||||
public FriendRequestDto RequestInfo { get; init; }
|
||||
/// <summary>
|
||||
|
||||
10
backend/IM_API/Domain/Events/RequestFriendEvent.cs
Normal file
10
backend/IM_API/Domain/Events/RequestFriendEvent.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
47
backend/IM_API/Dtos/HubResponse.cs
Normal file
47
backend/IM_API/Dtos/HubResponse.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using IM_API.Tools;
|
||||
|
||||
namespace IM_API.Dtos
|
||||
{
|
||||
public class HubResponse<T>
|
||||
{
|
||||
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 // 状态变更(如:对方正在输入、已读回执)
|
||||
}
|
||||
}
|
||||
@ -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; }
|
||||
|
||||
@ -40,17 +40,17 @@ namespace IM_API.Hubs
|
||||
}
|
||||
await base.OnConnectedAsync();
|
||||
}
|
||||
public async Task SendMessage(MessageBaseDto dto)
|
||||
public async Task<HubResponse<MessageBaseDto?>> SendMessage(MessageBaseDto dto)
|
||||
{
|
||||
if (!Context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
await Clients.Caller.SendAsync("ReceiveMessage", new BaseResponse<object?>(CodeDefine.AUTH_FAILED));
|
||||
Context.Abort();
|
||||
return;
|
||||
return new HubResponse<MessageBaseDto?>(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<MessageBaseDto?>("SendMessage", msgInfo);
|
||||
}
|
||||
public async Task ClearUnreadCount(int conversationId)
|
||||
public async Task<HubResponse<object?>> ClearUnreadCount(int conversationId)
|
||||
{
|
||||
if (!Context.User.Identity.IsAuthenticated)
|
||||
{
|
||||
await Clients.Caller.SendAsync("ReceiveMessage", new BaseResponse<object?>(CodeDefine.AUTH_FAILED));
|
||||
Context.Abort();
|
||||
return;
|
||||
return new HubResponse<object?>(CodeDefine.AUTH_FAILED, "ClearUnreadCount"); ;
|
||||
}
|
||||
var userIdStr = Context.User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
await _conversationService.ClearUnreadCountAsync(int.Parse(userIdStr), conversationId);
|
||||
return;
|
||||
return new HubResponse<object?>("ClearUnreadCount");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,11 @@ public partial class FriendRequest
|
||||
/// </summary>
|
||||
public sbyte State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string RemarkName { get; set; } = null!;
|
||||
|
||||
public virtual User RequestUserNavigation { get; set; } = null!;
|
||||
|
||||
public virtual User ResponseUserNavigation { get; set; } = null!;
|
||||
|
||||
@ -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)");
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<FriendService> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
public FriendService(ImContext context, ILogger<FriendService> logger, IMapper mapper)
|
||||
private readonly IPublishEndpoint _endpoint;
|
||||
public FriendService(ImContext context, ILogger<FriendService> logger, IMapper mapper, IPublishEndpoint endpoint)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
_endpoint = endpoint;
|
||||
}
|
||||
#region 拉黑好友
|
||||
public async Task<bool> 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<FriendRequestDto>(friendRequest),
|
||||
requestUserRemarkname = requestDto.RemarkName,
|
||||
|
||||
//根据当前好友请求为被申请方添加一条好友记录(注意:好友记录为双向)
|
||||
var ResponseFriend = _mapper.Map<Friend>(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<FriendRequest>(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
|
||||
|
||||
@ -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/
|
||||
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/
|
||||
Loading…
Reference in New Issue
Block a user