65 changed files with 1210 additions and 844 deletions
@ -0,0 +1,12 @@ |
|||||
|
namespace LINGYUN.Abp.IM.Contract |
||||
|
{ |
||||
|
public class UserAddFriendResult |
||||
|
{ |
||||
|
public bool Successed => Status == UserFriendStatus.Added; |
||||
|
public UserFriendStatus Status { get; } |
||||
|
public UserAddFriendResult(UserFriendStatus status) |
||||
|
{ |
||||
|
Status = status; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.IM.Contract |
||||
|
{ |
||||
|
public enum UserFriendStatus : byte |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 需要验证
|
||||
|
/// </summary>
|
||||
|
NeedValidation, |
||||
|
/// <summary>
|
||||
|
/// 已添加
|
||||
|
/// </summary>
|
||||
|
Added |
||||
|
} |
||||
|
} |
||||
@ -1,29 +1,79 @@ |
|||||
using System; |
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
using Volo.Abp.Auditing; |
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.ObjectExtending; |
||||
|
|
||||
namespace LINGYUN.Abp.IM.Messages |
namespace LINGYUN.Abp.IM.Messages |
||||
{ |
{ |
||||
public class ChatMessage |
public class ChatMessage : ExtensibleObject |
||||
{ |
{ |
||||
|
/// <summary>
|
||||
|
/// 租户
|
||||
|
/// </summary>
|
||||
public Guid? TenantId { get; set; } |
public Guid? TenantId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 群组标识
|
||||
|
/// </summary>
|
||||
public string GroupId { get; set; } |
public string GroupId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 消息标识
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 调用者无需关注此字段,将由服务自动生成
|
||||
|
/// </remarks>
|
||||
public string MessageId { get; set; } |
public string MessageId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 发送者标识
|
||||
|
/// </summary>
|
||||
public Guid FormUserId { get; set; } |
public Guid FormUserId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 发送者名称
|
||||
|
/// </summary>
|
||||
public string FormUserName { get; set; } |
public string FormUserName { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 接收用户标识
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// 设计为可空是为了兼容群聊消息
|
||||
|
/// /remarks>
|
||||
public Guid? ToUserId { get; set; } |
public Guid? ToUserId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 消息内容
|
||||
|
/// </summary>
|
||||
[DisableAuditing] |
[DisableAuditing] |
||||
public string Content { get; set; } |
public string Content { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 发送时间
|
||||
|
/// </summary>
|
||||
public DateTime SendTime { get; set; } |
public DateTime SendTime { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 是否匿名发送
|
||||
|
/// </summary>
|
||||
|
public bool IsAnonymous { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 消息类型
|
||||
|
/// </summary>
|
||||
|
public MessageType MessageType { get; set; } = MessageType.Text; |
||||
|
|
||||
public bool IsAnonymous { get; set; } = false; |
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext) |
||||
|
{ |
||||
|
var results = ExtensibleObjectValidator.GetValidationErrors(this, validationContext); |
||||
|
|
||||
public MessageType MessageType { get; set; } = MessageType.Text; |
foreach (var result in ValidateReceiver(validationContext)) |
||||
|
{ |
||||
|
results.Add(result); |
||||
|
} |
||||
|
|
||||
|
return results; |
||||
|
} |
||||
|
|
||||
|
protected virtual IEnumerable<ValidationResult> ValidateReceiver(ValidationContext validationContext) |
||||
|
{ |
||||
|
if (GroupId.IsNullOrWhiteSpace() && !ToUserId.HasValue) |
||||
|
{ |
||||
|
yield return new ValidationResult(""); |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,47 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public abstract class MessageSenderBase : IMessageSender |
||||
|
{ |
||||
|
protected IMessageStore Store { get; } |
||||
|
protected ILogger Logger { get; } |
||||
|
protected MessageSenderBase( |
||||
|
IMessageStore store, |
||||
|
ILogger logger) |
||||
|
{ |
||||
|
Store = store; |
||||
|
Logger = logger; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task SendMessageAsync(ChatMessage chatMessage) |
||||
|
{ |
||||
|
// 持久化
|
||||
|
await Store.StoreMessageAsync(chatMessage); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
if (!chatMessage.GroupId.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
await SendMessageToGroupAsync(chatMessage); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
await SendMessageToUserAsync(chatMessage); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogWarning("Could not send message, group: {0}, formUser: {1}, toUser: {2}", |
||||
|
chatMessage.GroupId, chatMessage.FormUserName, |
||||
|
chatMessage.ToUserId.HasValue ? chatMessage.ToUserId.ToString() : "None"); |
||||
|
Logger.LogWarning("Send group message error: {0}", ex.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected abstract Task SendMessageToGroupAsync(ChatMessage chatMessage); |
||||
|
protected abstract Task SendMessageToUserAsync(ChatMessage chatMessage); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public class NullMessageSender : MessageSenderBase, ITransientDependency |
||||
|
{ |
||||
|
public NullMessageSender(IMessageStore store, ILogger<NullMessageSender> logger) |
||||
|
: base(store, logger) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override Task SendMessageToGroupAsync(ChatMessage chatMessage) |
||||
|
{ |
||||
|
Logger.LogWarning("No IMessageSender Interface implementation!"); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
protected override Task SendMessageToUserAsync(ChatMessage chatMessage) |
||||
|
{ |
||||
|
Logger.LogWarning("No IMessageSender Interface implementation!"); |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,82 +0,0 @@ |
|||||
using LINGYUN.Abp.RealTime.Client; |
|
||||
using Microsoft.AspNetCore.Http; |
|
||||
using Microsoft.Extensions.Logging; |
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.AspNetCore.SignalR; |
|
||||
using Volo.Abp.Security.Claims; |
|
||||
|
|
||||
namespace LINGYUN.Abp.Notifications.SignalR |
|
||||
{ |
|
||||
public abstract class OnlineClientHubBase : AbpHub |
|
||||
{ |
|
||||
private ICurrentPrincipalAccessor _currentPrincipalAccessor; |
|
||||
protected ICurrentPrincipalAccessor CurrentPrincipalAccessor => LazyGetRequiredService(ref _currentPrincipalAccessor); |
|
||||
|
|
||||
private IOnlineClientManager _onlineClientManager; |
|
||||
protected IOnlineClientManager OnlineClientManager => LazyGetRequiredService(ref _onlineClientManager); |
|
||||
|
|
||||
private IHttpContextAccessor _httpContextAccessor; |
|
||||
protected IHttpContextAccessor HttpContextAccessor => LazyGetRequiredService(ref _httpContextAccessor); |
|
||||
|
|
||||
public override async Task OnConnectedAsync() |
|
||||
{ |
|
||||
await base.OnConnectedAsync(); |
|
||||
IOnlineClient onlineClient = CreateClientForCurrentConnection(); |
|
||||
Logger.LogDebug("A client is connected: " + onlineClient.ToString()); |
|
||||
OnlineClientManager.Add(onlineClient); |
|
||||
if (onlineClient.TenantId.HasValue) |
|
||||
{ |
|
||||
// 以租户为分组,将用户加入租户通讯组
|
|
||||
await Groups.AddToGroupAsync(onlineClient.ConnectionId, onlineClient.TenantId.Value.ToString()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override async Task OnDisconnectedAsync(Exception exception) |
|
||||
{ |
|
||||
await base.OnDisconnectedAsync(exception); |
|
||||
Logger.LogDebug("A client is disconnected: " + Context.ConnectionId); |
|
||||
try |
|
||||
{ |
|
||||
// 从通讯组移除
|
|
||||
var onlineClient = OnlineClientManager.GetByConnectionIdOrNull(Context.ConnectionId); |
|
||||
if(onlineClient != null) |
|
||||
{ |
|
||||
// 移除在线客户端
|
|
||||
OnlineClientManager.Remove(Context.ConnectionId); |
|
||||
} |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
Logger.LogWarning(ex.ToString(), ex); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual IOnlineClient CreateClientForCurrentConnection() |
|
||||
{ |
|
||||
// abp框架没有处理,需要切换一下用户身份令牌.否则无法获取用户信息
|
|
||||
using (CurrentPrincipalAccessor.Change(Context.User)) |
|
||||
{ |
|
||||
return new OnlineClient(Context.ConnectionId, GetClientIpAddress(), |
|
||||
CurrentTenant.Id, CurrentUser.Id) |
|
||||
{ |
|
||||
ConnectTime = Clock.Now, |
|
||||
UserName = CurrentUser.UserName |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual string GetClientIpAddress() |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); |
|
||||
} |
|
||||
catch (Exception ex) |
|
||||
{ |
|
||||
Logger.LogException(ex, LogLevel.Warning); |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.RealTime.SignalR |
||||
|
{ |
||||
|
public class Class1 |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="3.2.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.RealTime\LINGYUN.Abp.RealTime.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp.AspNetCore.SignalR; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.RealTime.SignalR |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAspNetCoreSignalRModule))] |
||||
|
public class AbpRealTimeSignalRModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using LINGYUN.Abp.IM.Contract; |
||||
|
using System; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Chat |
||||
|
{ |
||||
|
public class UserChatFriendEto : IMultiTenant |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 用户标识
|
||||
|
/// </summary>
|
||||
|
public Guid UserId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 好友标识
|
||||
|
/// </summary>
|
||||
|
public Guid FrientId { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 状态
|
||||
|
/// </summary>
|
||||
|
public UserFriendStatus Status { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,4 +1,4 @@ |
|||||
namespace LINGYUN.Abp.MessageService.Chat |
namespace LINGYUN.Abp.MessageService.Group |
||||
{ |
{ |
||||
public class ChatGroupConsts |
public class ChatGroupConsts |
||||
{ |
{ |
||||
@ -1,34 +1,99 @@ |
|||||
namespace LINGYUN.Abp.MessageService |
namespace LINGYUN.Abp.MessageService |
||||
{ |
{ |
||||
|
/// <summary>
|
||||
|
/// 消息系统错误码设计
|
||||
|
/// 状态码分为两部分 前2位领域 后3位状态
|
||||
|
///
|
||||
|
/// <list type="table">
|
||||
|
/// 领域部分:
|
||||
|
/// 01 输入
|
||||
|
/// 02 群组
|
||||
|
/// 03 用户
|
||||
|
/// 04 应用
|
||||
|
/// 05 内部
|
||||
|
/// 10 输出
|
||||
|
/// </list>
|
||||
|
///
|
||||
|
/// <list type="table">
|
||||
|
/// 状态部分:
|
||||
|
/// 200-299 成功
|
||||
|
/// 300-399 成功但有后续操作
|
||||
|
/// 400-499 业务异常
|
||||
|
/// 500-599 内部异常
|
||||
|
/// 900-999 输入输出异常
|
||||
|
/// </list>
|
||||
|
///
|
||||
|
/// </summary>
|
||||
public class MessageServiceErrorCodes |
public class MessageServiceErrorCodes |
||||
{ |
{ |
||||
|
public const string Namespace = "LINGYUN.Abp.Message"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 管理员已开启全员禁言
|
/// 消息不完整
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string GroupNotAllowedToSpeak = "Messages.Group:1001"; |
public const string MessageIncomplete = Namespace + ":01400"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 管理员不允许匿名发言
|
/// 您还未加入群组,不能进行操作
|
||||
|
/// </summary>
|
||||
|
public const string YouHaveNotJoinedGroup = Namespace + ":01401"; |
||||
|
/// <summary>
|
||||
|
/// 已发送群组申请,等待管理员同意
|
||||
|
/// </summary>
|
||||
|
public const string YouHaveAddingToGroup = Namespace + ":02301"; |
||||
|
/// <summary>
|
||||
|
/// 你需要验证问题才能加入群聊
|
||||
|
/// </summary>
|
||||
|
public const string YouNeedValidationQuestingByAddGroup = Namespace + ":02302"; |
||||
|
/// <summary>
|
||||
|
/// 管理员已开启全员禁言
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string GroupNotAllowedToSpeakAnonymously = "Messages.Group:1002"; |
public const string GroupNotAllowedToSpeak = Namespace + ":02400"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 管理员已禁止用户发言
|
/// 管理员已禁止用户发言
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string GroupUserHasBlack = "Messages.Group:1003"; |
public const string GroupUserHasBlack = Namespace + ":02403"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 用户已将发信人拉黑
|
/// 管理员不允许匿名发言
|
||||
|
/// </summary>
|
||||
|
public const string GroupNotAllowedToSpeakAnonymously = Namespace + ":02401"; |
||||
|
/// <summary>
|
||||
|
/// 群组不存在或已解散
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string UserHasBlack = "Messages.User:1003"; |
public const string GroupNotFount = Namespace + ":02404"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 用户已拒接所有消息
|
/// 用户已拒接所有消息
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string UserHasRejectAllMessage = "Messages.User:1001"; |
public const string UserHasRejectAllMessage = Namespace + ":03400"; |
||||
|
/// <summary>
|
||||
|
/// 用户已将发信人拉黑
|
||||
|
/// </summary>
|
||||
|
public const string UserHasBlack = Namespace + ":03401"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 用户不允许匿名发言
|
/// 用户不允许匿名发言
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string UserNotAllowedToSpeakAnonymously = "Messages.User:1002"; |
public const string UserNotAllowedToSpeakAnonymously = Namespace + ":03402"; |
||||
|
/// <summary>
|
||||
|
/// 用户不接收非好友发言
|
||||
|
/// </summary>
|
||||
|
public const string UserHasRejectNotFriendMessage = Namespace + ":03403"; |
||||
|
/// <summary>
|
||||
|
/// 接收消息用户不存在或已注销
|
||||
|
/// </summary>
|
||||
|
public const string UseNotFount = Namespace + ":03404"; |
||||
|
/// <summary>
|
||||
|
/// 用户拒绝添加好友
|
||||
|
/// </summary>
|
||||
|
public const string UseRefuseToAddFriend = Namespace + ":03410"; |
||||
|
/// <summary>
|
||||
|
/// 对方已是您的好友或已发送验证请求,不能重复操作
|
||||
|
/// </summary>
|
||||
|
public const string UseHasBeenAddedTheFriendOrSendAuthorization = Namespace + ":03411"; |
||||
|
/// <summary>
|
||||
|
/// 已发送好友申请,等待对方同意
|
||||
|
/// </summary>
|
||||
|
public const string YouHaveAddingTheUserToFriend = Namespace + ":03301"; |
||||
/// <summary>
|
/// <summary>
|
||||
/// 已经添加对方为好友
|
/// 你需要验证问题才能添加好友
|
||||
/// </summary>
|
/// </summary>
|
||||
public const string YouHaveAddedTheUserToFriend = "Messages.UserFriend:1001"; |
public const string YouNeedValidationQuestingByAddFriend = Namespace + ":03302"; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,14 @@ |
|||||
|
namespace LINGYUN.Abp.MessageService.Chat |
||||
|
{ |
||||
|
public static class ChatNotificationNames |
||||
|
{ |
||||
|
public const string GroupName = "LINGYUN.Abp.IM.Chat"; |
||||
|
|
||||
|
public static class UserFriend |
||||
|
{ |
||||
|
public const string Default = GroupName + ".UserFriend"; |
||||
|
|
||||
|
public const string NeedValidation = Default + ".NeedValidation"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,32 +0,0 @@ |
|||||
using System; |
|
||||
using Volo.Abp.Domain.Entities.Auditing; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Chat |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 用户黑名单
|
|
||||
/// </summary>
|
|
||||
public class UserChatBlack : CreationAuditedEntity<long>, IMultiTenant |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 租户
|
|
||||
/// </summary>
|
|
||||
public virtual Guid? TenantId { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 用户标识
|
|
||||
/// </summary>
|
|
||||
public virtual Guid UserId { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 拉黑的用户
|
|
||||
/// </summary>
|
|
||||
public virtual Guid ShieldUserId { get; protected set; } |
|
||||
protected UserChatBlack() { } |
|
||||
public UserChatBlack(Guid userId, Guid shieldUserId, Guid? tenantId) |
|
||||
{ |
|
||||
UserId = userId; |
|
||||
ShieldUserId = shieldUserId; |
|
||||
TenantId = tenantId; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,27 @@ |
|||||
|
using LINGYUN.Abp.IM.Contract; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Chat |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class UserFriendCacheItem |
||||
|
{ |
||||
|
public List<UserFriend> Friends { get; set; } |
||||
|
|
||||
|
public UserFriendCacheItem() |
||||
|
{ |
||||
|
Friends = new List<UserFriend>(); |
||||
|
} |
||||
|
|
||||
|
public UserFriendCacheItem(List<UserFriend> friends) |
||||
|
{ |
||||
|
Friends = friends; |
||||
|
} |
||||
|
|
||||
|
public static string CalculateCacheKey(string userId) |
||||
|
{ |
||||
|
return "uid:" + userId; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,32 +0,0 @@ |
|||||
using System; |
|
||||
using Volo.Abp.Domain.Entities.Auditing; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Chat |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 用户特别关注
|
|
||||
/// </summary>
|
|
||||
public class UserSpecialFocus : CreationAuditedEntity<long>, IMultiTenant |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 租户
|
|
||||
/// </summary>
|
|
||||
public virtual Guid? TenantId { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 用户标识
|
|
||||
/// </summary>
|
|
||||
public virtual Guid UserId { get; protected set; } |
|
||||
/// <summary>
|
|
||||
/// 关注的用户
|
|
||||
/// </summary>
|
|
||||
public virtual Guid FocusUserId { get; protected set; } |
|
||||
protected UserSpecialFocus() { } |
|
||||
public UserSpecialFocus(Guid userId, Guid focusUserId, Guid? tenantId) |
|
||||
{ |
|
||||
UserId = userId; |
|
||||
FocusUserId = focusUserId; |
|
||||
TenantId = tenantId; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,84 @@ |
|||||
|
using LINGYUN.Abp.IM.Messages; |
||||
|
using LINGYUN.Abp.MessageService.Chat; |
||||
|
using LINGYUN.Abp.Notifications; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Entities.Events; |
||||
|
using Volo.Abp.EventBus; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.EventBus.Local |
||||
|
{ |
||||
|
public class UserChatFriendEventHandler : |
||||
|
ILocalEventHandler<EntityCreatedEventData<UserChatFriend>>, |
||||
|
ILocalEventHandler<EntityDeletedEventData<UserChatFriend>>, |
||||
|
ILocalEventHandler<EntityUpdatedEventData<UserChatFriend>>, |
||||
|
ILocalEventHandler<UserChatFriendEto>, |
||||
|
ITransientDependency |
||||
|
{ |
||||
|
private ILogger _logger; |
||||
|
private IMessageSender _messageSender; |
||||
|
private INotificationDispatcher _dispatcher; |
||||
|
private IDistributedCache<UserFriendCacheItem> _cache; |
||||
|
|
||||
|
public UserChatFriendEventHandler( |
||||
|
IMessageSender messageSender, |
||||
|
INotificationDispatcher dispatcher, |
||||
|
ILogger<UserChatFriendEventHandler> logger) |
||||
|
{ |
||||
|
_logger = logger; |
||||
|
_dispatcher = dispatcher; |
||||
|
_messageSender = messageSender; |
||||
|
} |
||||
|
|
||||
|
public virtual async Task HandleEventAsync(EntityCreatedEventData<UserChatFriend> eventData) |
||||
|
{ |
||||
|
switch (eventData.Entity.Status) |
||||
|
{ |
||||
|
case IM.Contract.UserFriendStatus.Added: |
||||
|
await SendFriendAddedMessageAsync(eventData.Entity.UserId, eventData.Entity.FrientId, eventData.Entity.TenantId); |
||||
|
break; |
||||
|
case IM.Contract.UserFriendStatus.NeedValidation: |
||||
|
await SendFriendValidationNotiferAsync(eventData.Entity.UserId, eventData.Entity.FrientId, eventData.Entity.TenantId); |
||||
|
break; |
||||
|
} |
||||
|
await RemoveUserFriendCacheItemAsync(eventData.Entity.UserId); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task HandleEventAsync(EntityDeletedEventData<UserChatFriend> eventData) |
||||
|
{ |
||||
|
await RemoveUserFriendCacheItemAsync(eventData.Entity.UserId); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task HandleEventAsync(EntityUpdatedEventData<UserChatFriend> eventData) |
||||
|
{ |
||||
|
await RemoveUserFriendCacheItemAsync(eventData.Entity.UserId); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task HandleEventAsync(UserChatFriendEto eventData) |
||||
|
{ |
||||
|
if (eventData.Status == IM.Contract.UserFriendStatus.Added) |
||||
|
{ |
||||
|
await SendFriendAddedMessageAsync(eventData.UserId, eventData.FrientId, eventData.TenantId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task SendFriendAddedMessageAsync(Guid userId, Guid friendId, Guid? tenantId = null) |
||||
|
{ |
||||
|
// 发送添加好友的第一条消息
|
||||
|
} |
||||
|
|
||||
|
protected virtual async Task SendFriendValidationNotiferAsync(Guid userId, Guid friendId, Guid? tenantId = null) |
||||
|
{ |
||||
|
// 发送好友验证通知
|
||||
|
} |
||||
|
|
||||
|
protected virtual async Task RemoveUserFriendCacheItemAsync(Guid userId) |
||||
|
{ |
||||
|
// 移除好友缓存
|
||||
|
await _cache.RemoveAsync(UserFriendCacheItem.CalculateCacheKey(userId.ToString())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,7 +1,8 @@ |
|||||
using LINGYUN.Abp.IM.Messages; |
using LINGYUN.Abp.IM.Messages; |
||||
|
using LINGYUN.Abp.MessageService.Chat; |
||||
using System; |
using System; |
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Chat |
namespace LINGYUN.Abp.MessageService.Group |
||||
{ |
{ |
||||
public class GroupMessage : Message |
public class GroupMessage : Message |
||||
{ |
{ |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Group |
||||
|
{ |
||||
|
public static class IGroupRepositoryExtensions |
||||
|
{ |
||||
|
public static async Task<ChatGroup> GetByIdAsync( |
||||
|
this IGroupRepository repository, |
||||
|
long id, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var group = await repository.FindByIdAsync(id, cancellationToken); |
||||
|
|
||||
|
return group ?? throw new BusinessException(MessageServiceErrorCodes.GroupNotFount); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,305 +0,0 @@ |
|||||
using LINGYUN.Abp.IM.Group; |
|
||||
using LINGYUN.Abp.MessageService.EntityFrameworkCore; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
using Microsoft.EntityFrameworkCore.Internal; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Linq.Dynamic.Core; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|
||||
using Volo.Abp.EntityFrameworkCore; |
|
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Chat |
|
||||
{ |
|
||||
public class EfCoreUserChatGroupRepository : EfCoreRepository<IMessageServiceDbContext, UserChatGroup, long>, |
|
||||
IUserChatGroupRepository, ITransientDependency |
|
||||
{ |
|
||||
public EfCoreUserChatGroupRepository( |
|
||||
IDbContextProvider<IMessageServiceDbContext> dbContextProvider) : base(dbContextProvider) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<GroupUserCard> GetMemberAsync( |
|
||||
long groupId, |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
|
||||
join ucg in DbContext.Set<UserChatGroup>() |
|
||||
on gp.GroupId equals ucg.GroupId |
|
||||
join ugc in DbContext.Set<UserGroupCard>() |
|
||||
on ucg.UserId equals ugc.UserId |
|
||||
join uc in DbContext.Set<UserChatCard>() |
|
||||
on ugc.UserId equals uc.UserId |
|
||||
where gp.GroupId == groupId && ugc.UserId == userId |
|
||||
select new GroupUserCard |
|
||||
{ |
|
||||
TenantId = uc.TenantId, |
|
||||
UserId = uc.UserId, |
|
||||
UserName = uc.UserName, |
|
||||
Age = uc.Age, |
|
||||
AvatarUrl = uc.AvatarUrl, |
|
||||
IsAdmin = ugc.IsAdmin, |
|
||||
IsSuperAdmin = gp.AdminUserId == uc.UserId, |
|
||||
GroupId = gp.GroupId, |
|
||||
Birthday = uc.Birthday, |
|
||||
Description = uc.Description, |
|
||||
NickName = ugc.NickName ?? uc.NickName, |
|
||||
Sex = uc.Sex, |
|
||||
Sign = uc.Sign |
|
||||
}; |
|
||||
|
|
||||
return await cardQuery |
|
||||
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<List<GroupUserCard>> GetMembersAsync( |
|
||||
long groupId, |
|
||||
string sorting = nameof(UserChatCard.UserId), |
|
||||
bool reverse = false, |
|
||||
int skipCount = 0, |
|
||||
int maxResultCount = 10, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
sorting ??= nameof(UserChatCard.UserId); |
|
||||
sorting = reverse ? sorting + " desc" : sorting; |
|
||||
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
|
||||
join ucg in DbContext.Set<UserChatGroup>() |
|
||||
on gp.GroupId equals ucg.GroupId |
|
||||
join ugc in DbContext.Set<UserGroupCard>() |
|
||||
on ucg.UserId equals ugc.UserId |
|
||||
join uc in DbContext.Set<UserChatCard>() |
|
||||
on ugc.UserId equals uc.UserId |
|
||||
where gp.GroupId == groupId |
|
||||
select new GroupUserCard |
|
||||
{ |
|
||||
TenantId = uc.TenantId, |
|
||||
UserId = uc.UserId, |
|
||||
UserName = uc.UserName, |
|
||||
Age = uc.Age, |
|
||||
AvatarUrl = uc.AvatarUrl, |
|
||||
IsAdmin = ugc.IsAdmin, |
|
||||
IsSuperAdmin = gp.AdminUserId == uc.UserId, |
|
||||
GroupId = gp.GroupId, |
|
||||
Birthday = uc.Birthday, |
|
||||
Description = uc.Description, |
|
||||
NickName = ugc.NickName ?? uc.NickName, |
|
||||
Sex = uc.Sex, |
|
||||
Sign = uc.Sign |
|
||||
}; |
|
||||
|
|
||||
return await cardQuery |
|
||||
.OrderBy(sorting ?? nameof(UserChatCard.UserId)) |
|
||||
.PageBy(skipCount, maxResultCount) |
|
||||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<int> GetMembersCountAsync( |
|
||||
long groupId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
|
||||
join ucg in DbContext.Set<UserChatGroup>() |
|
||||
on gp.GroupId equals ucg.GroupId |
|
||||
join ugc in DbContext.Set<UserGroupCard>() |
|
||||
on ucg.UserId equals ugc.UserId |
|
||||
join uc in DbContext.Set<UserChatCard>() |
|
||||
on ugc.UserId equals uc.UserId |
|
||||
where gp.GroupId == groupId |
|
||||
select ucg; |
|
||||
|
|
||||
return await cardQuery |
|
||||
.CountAsync(GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<bool> MemberHasInGroupAsync( |
|
||||
long groupId, |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
return await DbContext.Set<UserChatGroup>() |
|
||||
.AnyAsync(ucg => ucg.GroupId == groupId && ucg.UserId == userId, |
|
||||
GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task<List<Group>> GetMemberGroupsAsync( |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
var groupQuery = from gp in DbContext.Set<ChatGroup>() |
|
||||
join ucg in DbContext.Set<UserChatGroup>() |
|
||||
on gp.GroupId equals ucg.GroupId |
|
||||
where ucg.UserId.Equals(userId) |
|
||||
group ucg by new |
|
||||
{ |
|
||||
gp.AllowAnonymous, |
|
||||
gp.AllowSendMessage, |
|
||||
gp.MaxUserCount, |
|
||||
gp.Name |
|
||||
} |
|
||||
into cg |
|
||||
select new Group |
|
||||
{ |
|
||||
AllowAnonymous = cg.Key.AllowAnonymous, |
|
||||
AllowSendMessage = cg.Key.AllowSendMessage, |
|
||||
MaxUserLength = cg.Key.MaxUserCount, |
|
||||
Name = cg.Key.Name, |
|
||||
GroupUserCount = cg.Count() |
|
||||
}; |
|
||||
|
|
||||
return await groupQuery |
|
||||
.ToListAsync(GetCancellationToken(cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
public virtual async Task RemoveMemberFormGroupAsync( |
|
||||
long groupId, |
|
||||
Guid userId, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
await DeleteAsync(ucg => ucg.GroupId == groupId && ucg.UserId == userId); |
|
||||
} |
|
||||
|
|
||||
//public virtual async Task<List<GroupUserCard>> GetGroupUsersAsync(
|
|
||||
// long groupId,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// // TODO: 急需单元测试,对这段代码不是太自信...
|
|
||||
// var groupUsers = await (from cg in DbContext.Set<ChatGroup>()
|
|
||||
// join ucg in DbContext.Set<UserChatGroup>()
|
|
||||
// on cg.GroupId equals ucg.GroupId
|
|
||||
// join ugc in DbContext.Set<UserGroupCard>()
|
|
||||
// on ucg.UserId equals ugc.UserId
|
|
||||
// where cg.GroupId.Equals(groupId)
|
|
||||
// select new GroupUserCard
|
|
||||
// {
|
|
||||
// GroupId = ucg.GroupId,
|
|
||||
// IsSuperAdmin = ugc.UserId == cg.AdminUserId,
|
|
||||
// IsAdmin = ugc.IsAdmin,
|
|
||||
// TenantId = ucg.TenantId,
|
|
||||
// UserId = ucg.UserId
|
|
||||
// })
|
|
||||
// .Distinct()
|
|
||||
// .AsNoTracking()
|
|
||||
// .ToListAsync(GetCancellationToken(cancellationToken));
|
|
||||
// return groupUsers;
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual async Task<GroupUserCard> GetMemberAsync(
|
|
||||
// long groupId,
|
|
||||
// Guid userId,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// var groupUserCard = await (from cg in DbContext.Set<ChatGroup>()
|
|
||||
// join ucg in DbContext.Set<UserChatGroup>().DefaultIfEmpty()
|
|
||||
// on cg.GroupId equals ucg.GroupId
|
|
||||
// join ucc in DbContext.Set<UserChatCard>().DefaultIfEmpty()
|
|
||||
// on ucg.UserId equals ucc.UserId
|
|
||||
// join cga in DbContext.Set<ChatGroupAdmin>().DefaultIfEmpty()
|
|
||||
// on cg.GroupId equals cga.GroupId
|
|
||||
// where ucg.GroupId.Equals(groupId) && cga.UserId.Equals(userId)
|
|
||||
// select new GroupUserCard
|
|
||||
// {
|
|
||||
// IsSuperAdmin = cga != null && cga.IsSuperAdmin,
|
|
||||
// IsAdmin = cga != null,//能查到数据就是管理员
|
|
||||
// GroupId = ucg.GroupId,
|
|
||||
// UserId = ucg.UserId,
|
|
||||
// TenantId = ucg.TenantId,
|
|
||||
// Permissions = new Dictionary<string, bool>
|
|
||||
// {
|
|
||||
// { nameof(ChatGroupAdmin.AllowAddPeople), cga != null && cga.AllowAddPeople },
|
|
||||
// { nameof(ChatGroupAdmin.AllowDissolveGroup), cga != null && cga.AllowDissolveGroup },
|
|
||||
// { nameof(ChatGroupAdmin.AllowKickPeople), cga != null && cga.AllowKickPeople },
|
|
||||
// { nameof(ChatGroupAdmin.AllowSendNotice), cga != null && cga.AllowSendNotice },
|
|
||||
// { nameof(ChatGroupAdmin.AllowSilence), cga != null && cga.AllowSilence },
|
|
||||
// { nameof(ChatGroupAdmin.IsSuperAdmin), cga != null && cga.IsSuperAdmin }
|
|
||||
// }
|
|
||||
// })
|
|
||||
// .AsNoTracking()
|
|
||||
// .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
|
|
||||
|
|
||||
// return groupUserCard;
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual Task<List<UserGroup>> GetUsersAsync(
|
|
||||
// long groupId,
|
|
||||
// string filter = "",
|
|
||||
// string sorting = nameof(UserGroup.UserId),
|
|
||||
// bool reverse = false,
|
|
||||
// int skipCount = 0,
|
|
||||
// int maxResultCount = 10,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// sorting = reverse ? sorting + " desc" : sorting;
|
|
||||
// // TODO: 复杂的实现,暂时无关紧要,后期再说 :)
|
|
||||
// throw new NotImplementedException();
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual Task<int> GetMembersCountAsync(
|
|
||||
// long groupId,
|
|
||||
// string filter = "",
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// var ss = (from ucg in DbContext.Set<UserChatGroup>()
|
|
||||
// join cg in DbContext.Set<ChatGroup>() on ucg.GroupId equals cg.GroupId
|
|
||||
// select cg)
|
|
||||
// .WhereIf(!filter.IsNullOrWhiteSpace(),)
|
|
||||
|
|
||||
// // TODO: 复杂的实现,暂时无关紧要,后期再说 :)
|
|
||||
// //throw new NotImplementedException();
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual async Task<UserChatGroup> GetUserGroupAsync(
|
|
||||
// long groupId,
|
|
||||
// Guid userId,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// return await DbSet.Where(x => x.GroupId.Equals(groupId) && x.UserId.Equals(userId))
|
|
||||
// .AsNoTracking()
|
|
||||
// .FirstOrDefaultAsync(GetCancellationToken(cancellationToken));
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual async Task<List<Group>> GetUserGroupsAsync(
|
|
||||
// Guid userId,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// // TODO: 急需单元测试,对这段代码不是太自信...
|
|
||||
// var userGroups = await (from ucg in DbSet
|
|
||||
// join cg in DbContext.Set<ChatGroup>()
|
|
||||
// on ucg.GroupId equals cg.GroupId
|
|
||||
// group cg by new
|
|
||||
// {
|
|
||||
// cg.GroupId,
|
|
||||
// cg.Name,
|
|
||||
// cg.AllowAnonymous,
|
|
||||
// cg.AllowSendMessage,
|
|
||||
// cg.MaxUserCount
|
|
||||
// }
|
|
||||
// into ug
|
|
||||
// orderby ug.Key.GroupId descending
|
|
||||
// select new Group
|
|
||||
// {
|
|
||||
// AllowAnonymous = ug.Key.AllowAnonymous,
|
|
||||
// AllowSendMessage = ug.Key.AllowSendMessage,
|
|
||||
// GroupUserCount = ug.Count(),
|
|
||||
// MaxUserLength = ug.Key.MaxUserCount,
|
|
||||
// Name = ug.Key.Name
|
|
||||
// })
|
|
||||
// .Distinct()
|
|
||||
// .ToListAsync(GetCancellationToken(cancellationToken));
|
|
||||
|
|
||||
// return userGroups;
|
|
||||
//}
|
|
||||
|
|
||||
//public virtual async Task<bool> MemberHasInGroupAsync(
|
|
||||
// long groupId,
|
|
||||
// Guid userId,
|
|
||||
// CancellationToken cancellationToken = default)
|
|
||||
//{
|
|
||||
// return await DbSet
|
|
||||
// .AnyAsync(x => x.GroupId.Equals(groupId) && x.UserId.Equals(userId), GetCancellationToken(cancellationToken));
|
|
||||
//}
|
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,166 @@ |
|||||
|
using LINGYUN.Abp.IM.Group; |
||||
|
using LINGYUN.Abp.MessageService.Chat; |
||||
|
using LINGYUN.Abp.MessageService.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore.Internal; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Dynamic.Core; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Group |
||||
|
{ |
||||
|
public class EfCoreUserChatGroupRepository : EfCoreRepository<IMessageServiceDbContext, UserChatGroup, long>, |
||||
|
IUserChatGroupRepository, ITransientDependency |
||||
|
{ |
||||
|
public EfCoreUserChatGroupRepository( |
||||
|
IDbContextProvider<IMessageServiceDbContext> dbContextProvider) : base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<GroupUserCard> GetMemberAsync( |
||||
|
long groupId, |
||||
|
Guid userId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
||||
|
join ucg in DbContext.Set<UserChatGroup>() |
||||
|
on gp.GroupId equals ucg.GroupId |
||||
|
join ugc in DbContext.Set<UserGroupCard>() |
||||
|
on ucg.UserId equals ugc.UserId |
||||
|
join uc in DbContext.Set<UserChatCard>() |
||||
|
on ugc.UserId equals uc.UserId |
||||
|
where gp.GroupId == groupId && ugc.UserId == userId |
||||
|
select new GroupUserCard |
||||
|
{ |
||||
|
TenantId = uc.TenantId, |
||||
|
UserId = uc.UserId, |
||||
|
UserName = uc.UserName, |
||||
|
Age = uc.Age, |
||||
|
AvatarUrl = uc.AvatarUrl, |
||||
|
IsAdmin = ugc.IsAdmin, |
||||
|
IsSuperAdmin = gp.AdminUserId == uc.UserId, |
||||
|
GroupId = gp.GroupId, |
||||
|
Birthday = uc.Birthday, |
||||
|
Description = uc.Description, |
||||
|
NickName = ugc.NickName ?? uc.NickName, |
||||
|
Sex = uc.Sex, |
||||
|
Sign = uc.Sign |
||||
|
}; |
||||
|
|
||||
|
return await cardQuery |
||||
|
.FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<GroupUserCard>> GetMembersAsync( |
||||
|
long groupId, |
||||
|
string sorting = nameof(UserChatCard.UserId), |
||||
|
bool reverse = false, |
||||
|
int skipCount = 0, |
||||
|
int maxResultCount = 10, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
sorting ??= nameof(UserChatCard.UserId); |
||||
|
sorting = reverse ? sorting + " desc" : sorting; |
||||
|
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
||||
|
join ucg in DbContext.Set<UserChatGroup>() |
||||
|
on gp.GroupId equals ucg.GroupId |
||||
|
join ugc in DbContext.Set<UserGroupCard>() |
||||
|
on ucg.UserId equals ugc.UserId |
||||
|
join uc in DbContext.Set<UserChatCard>() |
||||
|
on ugc.UserId equals uc.UserId |
||||
|
where gp.GroupId == groupId |
||||
|
select new GroupUserCard |
||||
|
{ |
||||
|
TenantId = uc.TenantId, |
||||
|
UserId = uc.UserId, |
||||
|
UserName = uc.UserName, |
||||
|
Age = uc.Age, |
||||
|
AvatarUrl = uc.AvatarUrl, |
||||
|
IsAdmin = ugc.IsAdmin, |
||||
|
IsSuperAdmin = gp.AdminUserId == uc.UserId, |
||||
|
GroupId = gp.GroupId, |
||||
|
Birthday = uc.Birthday, |
||||
|
Description = uc.Description, |
||||
|
NickName = ugc.NickName ?? uc.NickName, |
||||
|
Sex = uc.Sex, |
||||
|
Sign = uc.Sign |
||||
|
}; |
||||
|
|
||||
|
return await cardQuery |
||||
|
.OrderBy(sorting ?? nameof(UserChatCard.UserId)) |
||||
|
.PageBy(skipCount, maxResultCount) |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<int> GetMembersCountAsync( |
||||
|
long groupId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var cardQuery = from gp in DbContext.Set<ChatGroup>() |
||||
|
join ucg in DbContext.Set<UserChatGroup>() |
||||
|
on gp.GroupId equals ucg.GroupId |
||||
|
join ugc in DbContext.Set<UserGroupCard>() |
||||
|
on ucg.UserId equals ugc.UserId |
||||
|
join uc in DbContext.Set<UserChatCard>() |
||||
|
on ugc.UserId equals uc.UserId |
||||
|
where gp.GroupId == groupId |
||||
|
select ucg; |
||||
|
|
||||
|
return await cardQuery |
||||
|
.CountAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<bool> MemberHasInGroupAsync( |
||||
|
long groupId, |
||||
|
Guid userId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return await DbContext.Set<UserChatGroup>() |
||||
|
.AnyAsync(ucg => ucg.GroupId == groupId && ucg.UserId == userId, |
||||
|
GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task<List<IM.Group.Group>> GetMemberGroupsAsync( |
||||
|
Guid userId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
var groupQuery = from gp in DbContext.Set<ChatGroup>() |
||||
|
join ucg in DbContext.Set<UserChatGroup>() |
||||
|
on gp.GroupId equals ucg.GroupId |
||||
|
where ucg.UserId.Equals(userId) |
||||
|
group ucg by new |
||||
|
{ |
||||
|
gp.AllowAnonymous, |
||||
|
gp.AllowSendMessage, |
||||
|
gp.MaxUserCount, |
||||
|
gp.Name |
||||
|
} |
||||
|
into cg |
||||
|
select new IM.Group.Group |
||||
|
{ |
||||
|
AllowAnonymous = cg.Key.AllowAnonymous, |
||||
|
AllowSendMessage = cg.Key.AllowSendMessage, |
||||
|
MaxUserLength = cg.Key.MaxUserCount, |
||||
|
Name = cg.Key.Name, |
||||
|
GroupUserCount = cg.Count() |
||||
|
}; |
||||
|
|
||||
|
return await groupQuery |
||||
|
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
} |
||||
|
|
||||
|
public virtual async Task RemoveMemberFormGroupAsync( |
||||
|
long groupId, |
||||
|
Guid userId, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
await DeleteAsync(ucg => ucg.GroupId == groupId && ucg.UserId == userId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Binary file not shown.
Loading…
Reference in new issue