diff --git a/README.en.md b/README.en.md index 85dd66395..f4edfe568 100644 --- a/README.en.md +++ b/README.en.md @@ -41,7 +41,19 @@ If you want to get started with a minimal template code instead of integration s ## Screenshots -![dashboard](./demo/dashboard.png) +![Login](./vueJs/images/userLogin.png) + +![Tenants](./vueJs/images/tenant.png) + +![Roles](./vueJs/images/userRoles.png) + +![Permissions](./vueJs/images/userPermissions.png) + +![IM](./vueJs/images/im-notifications.png) + +![Clients](./vueJs/images/client.png) + +![Aggregate route](./vueJs/images/aggregate.png) ## Related Projects diff --git a/README.md b/README.md index f5b5cd661..7c4f53eac 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,19 @@ ## 截图 -![登录页](./images/userLogin.png) +![登录页](./vueJs/images/userLogin.png) -![角色页](./images/userRoles.png) +![租户管理](./vueJs/images/tenant.png) -![权限页](./images/userPermissions.png) +![角色页](./vueJs/images/userRoles.png) + +![权限页](./vueJs/images/userPermissions.png) + +![即时通讯](./vueJs/images/im-notifications.png) + +![客户端管理](./vueJs/images/client.png) + +![聚合路由](./vueJs/images/aggregate.png) ## 相关项目 diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs new file mode 100644 index 000000000..6b90f18d7 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.Designer.cs @@ -0,0 +1,494 @@ +// +using System; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + [DbContext(typeof(MessageServiceHostMigrationsDbContext))] + [Migration("20200602134027_Add-Chat-Message-Entites")] + partial class AddChatMessageEntites + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Address") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") + .HasMaxLength(20); + + b.Property("Notice") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Tag") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroupAdmin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowDissolveGroup") + .HasColumnType("tinyint(1)"); + + b.Property("AllowKickPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendNotice") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSilence") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("IsSuperAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppChatGroupAdmins"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserSpecialFocus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("FocusUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserSpecialFocuss"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.Notification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationData") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("NotificationTypeName") + .IsRequired() + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("Severity") + .HasColumnType("tinyint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("NotificationName"); + + b.ToTable("AppNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("NotificationId") + .HasColumnType("bigint"); + + b.Property("ReadStatus") + .HasColumnType("int"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationId") + .HasName("IX_Tenant_User_Notification_Id"); + + b.ToTable("AppUserNotifications"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Subscriptions.UserSubscribe", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("NotificationName") + .IsRequired() + .HasColumnType("varchar(100) CHARACTER SET utf8mb4") + .HasMaxLength(100); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId", "NotificationName") + .IsUnique() + .HasName("IX_Tenant_User_Notification_Name"); + + b.ToTable("AppUserSubscribes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs new file mode 100644 index 000000000..c11cb75b4 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200602134027_Add-Chat-Message-Entites.cs @@ -0,0 +1,281 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + public partial class AddChatMessageEntites : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "ReadStatus", + table: "AppUserNotifications", + nullable: false, + oldClrType: typeof(sbyte), + oldType: "tinyint"); + + migrationBuilder.CreateTable( + name: "AppChatGroupAdmins", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + GroupId = table.Column(nullable: false), + UserId = table.Column(nullable: false), + IsSuperAdmin = table.Column(nullable: false), + AllowSilence = table.Column(nullable: false), + AllowKickPeople = table.Column(nullable: false), + AllowAddPeople = table.Column(nullable: false), + AllowSendNotice = table.Column(nullable: false), + AllowDissolveGroup = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppChatGroupAdmins", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppChatGroups", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + LastModificationTime = table.Column(nullable: true), + LastModifierId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + GroupId = table.Column(nullable: false), + Name = table.Column(maxLength: 20, nullable: false), + Tag = table.Column(maxLength: 512, nullable: true), + Address = table.Column(maxLength: 256, nullable: true), + Notice = table.Column(maxLength: 64, nullable: true), + MaxUserCount = table.Column(nullable: false), + AllowAnonymous = table.Column(nullable: false), + AllowSendMessage = table.Column(nullable: false), + Description = table.Column(maxLength: 128, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AppChatGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppGroupChatBlacks", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + GroupId = table.Column(nullable: false), + ShieldUserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppGroupChatBlacks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppGroupMessages", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + MessageId = table.Column(nullable: false), + SendUserName = table.Column(maxLength: 64, nullable: false), + Content = table.Column(maxLength: 1048576, nullable: false), + Type = table.Column(nullable: false), + SendState = table.Column(nullable: false), + GroupId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppGroupMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserChatBlacks", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + UserId = table.Column(nullable: false), + ShieldUserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserChatBlacks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserChatGroups", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + UserId = table.Column(nullable: false), + GroupId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserChatGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserChatSettings", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + TenantId = table.Column(nullable: true), + UserId = table.Column(nullable: false), + AllowAnonymous = table.Column(nullable: false), + AllowAddFriend = table.Column(nullable: false), + RequireAddFriendValition = table.Column(nullable: false), + AllowReceiveMessage = table.Column(nullable: false), + AllowSendMessage = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserChatSettings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserMessages", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + MessageId = table.Column(nullable: false), + SendUserName = table.Column(maxLength: 64, nullable: false), + Content = table.Column(maxLength: 1048576, nullable: false), + Type = table.Column(nullable: false), + SendState = table.Column(nullable: false), + ReceiveUserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserSpecialFocuss", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + CreationTime = table.Column(nullable: false), + CreatorId = table.Column(nullable: true), + TenantId = table.Column(nullable: true), + UserId = table.Column(nullable: false), + FocusUserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserSpecialFocuss", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AppChatGroupAdmins_TenantId_GroupId", + table: "AppChatGroupAdmins", + columns: new[] { "TenantId", "GroupId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppChatGroups_TenantId_Name", + table: "AppChatGroups", + columns: new[] { "TenantId", "Name" }); + + migrationBuilder.CreateIndex( + name: "IX_AppGroupChatBlacks_TenantId_GroupId", + table: "AppGroupChatBlacks", + columns: new[] { "TenantId", "GroupId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppGroupMessages_TenantId_GroupId", + table: "AppGroupMessages", + columns: new[] { "TenantId", "GroupId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserChatBlacks_TenantId_UserId", + table: "AppUserChatBlacks", + columns: new[] { "TenantId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserChatGroups_TenantId_GroupId_UserId", + table: "AppUserChatGroups", + columns: new[] { "TenantId", "GroupId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserChatSettings_TenantId_UserId", + table: "AppUserChatSettings", + columns: new[] { "TenantId", "UserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserMessages_TenantId_ReceiveUserId", + table: "AppUserMessages", + columns: new[] { "TenantId", "ReceiveUserId" }); + + migrationBuilder.CreateIndex( + name: "IX_AppUserSpecialFocuss_TenantId_UserId", + table: "AppUserSpecialFocuss", + columns: new[] { "TenantId", "UserId" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AppChatGroupAdmins"); + + migrationBuilder.DropTable( + name: "AppChatGroups"); + + migrationBuilder.DropTable( + name: "AppGroupChatBlacks"); + + migrationBuilder.DropTable( + name: "AppGroupMessages"); + + migrationBuilder.DropTable( + name: "AppUserChatBlacks"); + + migrationBuilder.DropTable( + name: "AppUserChatGroups"); + + migrationBuilder.DropTable( + name: "AppUserChatSettings"); + + migrationBuilder.DropTable( + name: "AppUserMessages"); + + migrationBuilder.DropTable( + name: "AppUserSpecialFocuss"); + + migrationBuilder.AlterColumn( + name: "ReadStatus", + table: "AppUserNotifications", + type: "tinyint", + nullable: false, + oldClrType: typeof(int)); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs index 8e253493d..8704b41fc 100644 --- a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs @@ -17,6 +17,370 @@ namespace LINGYUN.Abp.MessageService.Migrations .HasAnnotation("ProductVersion", "3.1.3") .HasAnnotation("Relational:MaxIdentifierLength", 64); + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Address") + .HasColumnType("varchar(256) CHARACTER SET utf8mb4") + .HasMaxLength(256); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("Description") + .HasColumnType("varchar(128) CHARACTER SET utf8mb4") + .HasMaxLength(128); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("MaxUserCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("varchar(20) CHARACTER SET utf8mb4") + .HasMaxLength(20); + + b.Property("Notice") + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("Tag") + .HasColumnType("varchar(512) CHARACTER SET utf8mb4") + .HasMaxLength(512); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Name"); + + b.ToTable("AppChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.ChatGroupAdmin", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowDissolveGroup") + .HasColumnType("tinyint(1)"); + + b.Property("AllowKickPeople") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendNotice") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSilence") + .HasColumnType("tinyint(1)"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("IsSuperAdmin") + .HasColumnType("tinyint(1)"); + + b.Property("LastModificationTime") + .HasColumnType("datetime(6)"); + + b.Property("LastModifierId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppChatGroupAdmins"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.GroupMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId"); + + b.ToTable("AppGroupMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatBlack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("ShieldUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatBlacks"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("bigint"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "GroupId", "UserId"); + + b.ToTable("AppUserChatGroups"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserChatSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("AllowAddFriend") + .HasColumnType("tinyint(1)"); + + b.Property("AllowAnonymous") + .HasColumnType("tinyint(1)"); + + b.Property("AllowReceiveMessage") + .HasColumnType("tinyint(1)"); + + b.Property("AllowSendMessage") + .HasColumnType("tinyint(1)"); + + b.Property("RequireAddFriendValition") + .HasColumnType("tinyint(1)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserChatSettings"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext CHARACTER SET utf8mb4") + .HasMaxLength(1048576); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("MessageId") + .HasColumnType("bigint"); + + b.Property("ReceiveUserId") + .HasColumnType("char(36)"); + + b.Property("SendState") + .HasColumnType("tinyint"); + + b.Property("SendUserName") + .IsRequired() + .HasColumnType("varchar(64) CHARACTER SET utf8mb4") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "ReceiveUserId"); + + b.ToTable("AppUserMessages"); + }); + + modelBuilder.Entity("LINGYUN.Abp.MessageService.Messages.UserSpecialFocus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationTime") + .HasColumnType("datetime(6)"); + + b.Property("CreatorId") + .HasColumnType("char(36)"); + + b.Property("FocusUserId") + .HasColumnType("char(36)"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AppUserSpecialFocuss"); + }); + modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.Notification", b => { b.Property("Id") @@ -74,8 +438,8 @@ namespace LINGYUN.Abp.MessageService.Migrations b.Property("NotificationId") .HasColumnType("bigint"); - b.Property("ReadStatus") - .HasColumnType("tinyint"); + b.Property("ReadStatus") + .HasColumnType("int"); b.Property("TenantId") .HasColumnName("TenantId") diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs index df413d9aa..9e4856d84 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs @@ -30,14 +30,14 @@ namespace LINGYUN.Abp.IM.SignalR.Hubs // 持久化 await _messageStore.StoreMessageAsync(chatMessage); - if (!chatMessage.GroupName.IsNullOrWhiteSpace()) + if (!chatMessage.GroupId.IsNullOrWhiteSpace()) { try { - var signalRClient = Clients.Group(chatMessage.GroupName); + var signalRClient = Clients.Group(chatMessage.GroupId); if (signalRClient == null) { - Logger.LogDebug("Can not get group " + chatMessage.GroupName + " from SignalR hub!"); + Logger.LogDebug("Can not get group " + chatMessage.GroupId + " from SignalR hub!"); return; } @@ -45,13 +45,13 @@ namespace LINGYUN.Abp.IM.SignalR.Hubs } catch (Exception ex) { - Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupName); + Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupId); Logger.LogWarning("Send group message error: {0}", ex.Message); } } else { - var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId); + var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId.GetValueOrDefault()); var onlineClients = OnlineClientManager.GetAllByContext(onlineClientContext); foreach (var onlineClient in onlineClients) { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Messages/SignalRMessageSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Messages/SignalRMessageSender.cs index 069d5f199..380c90669 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Messages/SignalRMessageSender.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Messages/SignalRMessageSender.cs @@ -41,47 +41,59 @@ namespace LINGYUN.Abp.IM.SignalR.Messages // 持久化 await _messageStore.StoreMessageAsync(chatMessage); - if (!chatMessage.GroupName.IsNullOrWhiteSpace()) + 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 virtual async Task SendMessageToGroupAsync(ChatMessage chatMessage) + { + var signalRClient = _hubContext.Clients.Group(chatMessage.GroupId); + if (signalRClient == null) + { + Logger.LogDebug("Can not get group " + chatMessage.GroupId + " from SignalR hub!"); + return; + } + + await signalRClient.SendAsync("getChatMessage", chatMessage); + } + + protected virtual async Task SendMessageToUserAsync(ChatMessage chatMessage) + { + var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId.Value); + var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); + foreach (var onlineClient in onlineClients) { try { - var signalRClient = _hubContext.Clients.Group(chatMessage.GroupName); + var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); if (signalRClient == null) { - Logger.LogDebug("Can not get group " + chatMessage.GroupName + " from SignalR hub!"); - return; + Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); + continue; } await signalRClient.SendAsync("getChatMessage", chatMessage); } catch (Exception ex) { - Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupName); - Logger.LogWarning("Send group message error: {0}", ex.Message); - } - } - else - { - var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId); - var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); - foreach (var onlineClient in onlineClients) - { - try - { - var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); - if (signalRClient == null) - { - Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); - continue; - } - - await signalRClient.SendAsync("getChatMessage", chatMessage); - } - catch (Exception ex) - { - Logger.LogWarning("Could not send message to user: {0}", chatMessage.ToUserId); - Logger.LogWarning("Send to user message error: {0}", ex.Message); - } + Logger.LogWarning("Could not send message to user: {0}", chatMessage.ToUserId); + Logger.LogWarning("Send to user message error: {0}", ex.Message); } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN.Abp.IM.csproj b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN.Abp.IM.csproj index 76ce15181..db4635ca9 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN.Abp.IM.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN.Abp.IM.csproj @@ -6,7 +6,7 @@ - + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/Group.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/Group.cs new file mode 100644 index 000000000..4618778ab --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/Group.cs @@ -0,0 +1,26 @@ +namespace LINGYUN.Abp.IM.Group +{ + public class Group + { + /// + /// 群组名称 + /// + public string Name { get; set; } + /// + /// 允许匿名聊天 + /// + public bool AllowAnonymous { get; set; } + /// + /// 允许发送消息 + /// + public bool AllowSendMessage { get; set; } + /// + /// 最大用户数 + /// + public int MaxUserLength { get; set; } + /// + /// 群组用户数 + /// + public int GroupUserCount { get; set; } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/GroupChat.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/GroupChat.cs deleted file mode 100644 index 4927ae723..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/GroupChat.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace LINGYUN.Abp.IM.Group -{ - public class GroupChat - { - public string Name { get; set; } - public int MaxUserLength { get; set; } - } -} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs index 800ca41b6..85f5f620e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs @@ -12,7 +12,7 @@ namespace LINGYUN.Abp.IM.Group /// /// /// - Task> GetUserGroupsAsync(Guid? tenantId, Guid userId); + Task> GetUserGroupsAsync(Guid? tenantId, Guid userId); /// /// 获取通讯组所有用户 /// @@ -27,7 +27,7 @@ namespace LINGYUN.Abp.IM.Group /// /// /// - Task AddUserToGroupAsync(Guid? tenantId, Guid userId, long groupId); + Task AddUserToGroupAsync(Guid? tenantId, Guid userId, long groupId, Guid acceptUserId); /// /// 用户退出通讯组 /// diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/UserGroup.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/UserGroup.cs index d008896d5..120b13aa0 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/UserGroup.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/UserGroup.cs @@ -7,5 +7,7 @@ namespace LINGYUN.Abp.IM.Group public Guid? TenantId { get; set; } public Guid UserId { get; set; } public long GroupId { get; set; } + public bool IsAdmin { get; set; } + public bool IsSuperAdmin { get; set; } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/ChatMessage.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/ChatMessage.cs index 33f9c7624..e5b51f37e 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/ChatMessage.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/ChatMessage.cs @@ -1,15 +1,29 @@ using System; +using Volo.Abp.Auditing; namespace LINGYUN.Abp.IM.Messages { public class ChatMessage { public Guid? TenantId { get; set; } - public string GroupName { get; set; } + + public string GroupId { get; set; } + + public string MessageId { get; set; } + public Guid FormUserId { get; set; } - public Guid ToUserId { get; set; } + + public string FormUserName { get; set; } + + public Guid? ToUserId { get; set; } + + [DisableAuditing] public string Content { get; set; } + public DateTime SendTime { get; set; } + + public bool IsAnonymous { get; set; } = false; + public MessageType MessageType { get; set; } = MessageType.Text; } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageStore.cs index 7ca433a90..b8be51000 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageStore.cs @@ -21,7 +21,7 @@ namespace LINGYUN.Abp.IM.Messages /// /// /// - Task> GetGroupMessageAsync(Guid tenantId, string groupName, int maxResultCount = 10); + Task> GetGroupMessageAsync(Guid? tenantId, long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10); /// /// 获取与某个用户的聊天记录 /// @@ -29,6 +29,7 @@ namespace LINGYUN.Abp.IM.Messages /// /// /// - Task> GetChatMessageAsync(Guid tenantId, Guid userId, int maxResultCount = 10); + Task> GetChatMessageAsync(Guid? tenantId, Guid sendUserId, Guid receiveUserId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10); + } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/MessageSendState.cs similarity index 84% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs rename to aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/MessageSendState.cs index 7795118ab..3fbbfafe1 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/SendStatus.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/MessageSendState.cs @@ -1,9 +1,9 @@ -namespace LINGYUN.Abp.MessageService +namespace LINGYUN.Abp.IM.Messages { /// /// 消息状态 /// - public enum SendStatus : sbyte + public enum MessageSendState : sbyte { /// /// 已发送 diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs index 62c39d11b..6b0b5bc98 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/NotificationInfo.cs @@ -18,6 +18,8 @@ namespace LINGYUN.Abp.Notifications Data = new NotificationData(); NotificationType = NotificationType.Application; NotificationSeverity = NotificationSeverity.Info; + + CreationTime = DateTime.Now; } } } diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json index 81c9ce62b..2b174ebd2 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/en.json @@ -25,6 +25,7 @@ "ClientClaimNotFound": "Client claim: {0} not found!", "ClientSecretNotFound": "Client secret: {0} not found!", "ClientPropertyNotFound": "Client property: {0} not found!", - "IdentityResourcePropertyNotFound": "Identity resource property: {0} not found!" + "IdentityResourcePropertyNotFound": "Identity resource property: {0} not found!", + "EncryptionNotImplemented": "Encryption type: {0} not implemented!" } } \ No newline at end of file diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json index db3ae18ee..9b2fe7010 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/Localization/Resources/zh-Hans.json @@ -25,6 +25,7 @@ "ClientClaimNotFound": "客户端声明: {0} 不存在!", "ClientSecretNotFound": "客户端密钥: {0} 不存在!", "ClientPropertyNotFound": "客户端属性: {0} 不存在!", - "IdentityResourcePropertyNotFound": "身份资源属性: {0} 不存在!" + "IdentityResourcePropertyNotFound": "身份资源属性: {0} 不存在!", + "EncryptionNotImplemented": "加密类型: {0} 未实现!" } } \ No newline at end of file diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/Clients/ClientAppService.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/Clients/ClientAppService.cs index 8dd96466d..455c83798 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/Clients/ClientAppService.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application/LINGYUN/Abp/IdentityServer/Clients/ClientAppService.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.IdentityServer.Clients; -using Volo.Abp.Security.Encryption; using Client = Volo.Abp.IdentityServer.Clients.Client; namespace LINGYUN.Abp.IdentityServer.Clients @@ -15,9 +14,6 @@ namespace LINGYUN.Abp.IdentityServer.Clients [Authorize(AbpIdentityServerPermissions.Clients.Default)] public class ClientAppService : AbpIdentityServerAppServiceBase, IClientAppService { - private IStringEncryptionService _encryptionService; - protected IStringEncryptionService EncryptionService => LazyGetRequiredService(ref _encryptionService); - protected IClientRepository ClientRepository { get; } public ClientAppService(IClientRepository clientRepository) @@ -69,7 +65,8 @@ namespace LINGYUN.Abp.IdentityServer.Clients } else { - clientSecretValue = EncryptionService.Encrypt(clientSecretCreate.Value); + // 其他类型的服务器加密方式暂时不提供 + throw new UserFriendlyException(L["EncryptionNotImplemented", clientSecretCreate.Type]); } client.AddSecret(clientSecretValue, clientSecretCreate.Expiration, clientSecretCreate.Type, clientSecretCreate.Description); @@ -461,7 +458,7 @@ namespace LINGYUN.Abp.IdentityServer.Clients } else { - clientSecretValue = EncryptionService.Encrypt(clientSecretUpdate.Value); + throw new UserFriendlyException(L["EncryptionNotImplemented", clientSecretUpdate.Type]); } clientSecret.Value = clientSecretValue; diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/MessageServiceErrorCodes.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/MessageServiceErrorCodes.cs new file mode 100644 index 000000000..0ddb5ae88 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/MessageServiceErrorCodes.cs @@ -0,0 +1,30 @@ +namespace LINGYUN.Abp.MessageService +{ + public class MessageServiceErrorCodes + { + /// + /// 管理员已开启全员禁言 + /// + public const string GroupNotAllowedToSpeak = "Messages:Group:1001"; + /// + /// 管理员不允许匿名发言 + /// + public const string GroupNotAllowedToSpeakAnonymously = "Messages:Group:1002"; + /// + /// 管理员已禁止用户发言 + /// + public const string GroupUserHasBlack = "Messages:Group:1003"; + /// + /// 用户已将发信人拉黑 + /// + public const string UserHasBlack = "Messages:User:1003"; + /// + /// 用户已拒接所有消息 + /// + public const string UserHasRejectAllMessage = "Messages:User:1001"; + /// + /// 用户不允许匿名发言 + /// + public const string UserNotAllowedToSpeakAnonymously = "Messages:User:1002"; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ChatGroupConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ChatGroupConsts.cs new file mode 100644 index 000000000..7c015a16c --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/ChatGroupConsts.cs @@ -0,0 +1,15 @@ +namespace LINGYUN.Abp.MessageService.Messages +{ + public class ChatGroupConsts + { + public const int MaxNameLength = 20; + + public const int MaxTagLength = 512; + + public const int MaxAddressLength = 256; + + public const int MaxNoticeLength = 64; + + public const int MaxDescriptionLength = 128; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/MessageConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/MessageConsts.cs new file mode 100644 index 000000000..6708d9bfa --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Messages/MessageConsts.cs @@ -0,0 +1,10 @@ +namespace LINGYUN.Abp.MessageService.Messages +{ + public class MessageConsts + { + public const int MaxSendUserNameLength = 64; + + // 1 MB + public const int MaxContentLength = 1024 * 1024; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs similarity index 100% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/NotificationConsts.cs diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs similarity index 100% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Subscriptions/SubscribeConsts.cs diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj index 4ca8aa840..30ef08749 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN.Abp.MessageService.Domain.csproj @@ -5,10 +5,21 @@ + + + + + + + + + + + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/UserCreateEventHandler.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/UserCreateEventHandler.cs new file mode 100644 index 000000000..30e0cead3 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/EventBus/UserCreateEventHandler.cs @@ -0,0 +1,48 @@ +using LINGYUN.Abp.MessageService.Messages; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.MessageService.EventBus +{ + public class UserCreateEventHandler : IDistributedEventHandler> + { + private readonly ICurrentTenant _currentTenant; + private readonly IUnitOfWorkManager _unitOfWorkManager; + private readonly IUserChatSettingRepository _userChatSettingRepository; + public UserCreateEventHandler( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + IUserChatSettingRepository userChatSettingRepository) + { + _currentTenant = currentTenant; + _unitOfWorkManager = unitOfWorkManager; + _userChatSettingRepository = userChatSettingRepository; + } + /// + /// 接收添加用户事件,启用IM模块时增加用户配置 + /// + /// + /// + public async Task HandleEventAsync(EntityCreatedEto eventData) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (_currentTenant.Change(eventData.Entity.TenantId)) + { + var userHasOpendIm = await _userChatSettingRepository.UserHasOpendImAsync(eventData.Entity.Id); + if (!userHasOpendIm) + { + var userChatSetting = new UserChatSetting(eventData.Entity.Id, eventData.Entity.TenantId); + await _userChatSettingRepository.InsertAsync(userChatSetting); + + await unitOfWork.SaveChangesAsync(); + } + } + } + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json new file mode 100644 index 000000000..948b35c47 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/en.json @@ -0,0 +1,11 @@ +{ + "culture": "en", + "texts": { + "Messages:Group:1001": "The current group is not allowed to speak", + "Messages:Group:1002": "The current group is not allowed to speak anonymously", + "Messages:Group:1003": "The administrator has banned you from speaking!", + "Messages:User:1001": "Users do not receive anonymous comments!", + "Messages:User:1002": "The user has rejected all messages!", + "Messages:User:1003": "The user rejects the message you sent!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..0041a0ce4 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Localization/Resources/zh-Hans.json @@ -0,0 +1,11 @@ +{ + "culture": "zh-Hans", + "texts": { + "Messages:Group:1001": "管理员已开启全员禁言!", + "Messages:Group:1002": "管理员不允许匿名发言!", + "Messages:Group:1003": "管理员已禁止您发言!", + "Messages:User:1001": "用户不接收匿名发言!", + "Messages:User:1002": "用户已拒接所有消息!", + "Messages:User:1003": "用户拒绝您发送的消息!" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs index f49e6d8a3..631b50e39 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs @@ -1,11 +1,11 @@ using AutoMapper; +using LINGYUN.Abp.IM.Messages; +using LINGYUN.Abp.MessageService.Messages; using LINGYUN.Abp.MessageService.Notifications; using LINGYUN.Abp.MessageService.Subscriptions; using LINGYUN.Abp.Notifications; using Newtonsoft.Json; using System; -using System.Collections.Generic; -using System.Text; namespace LINGYUN.Abp.MessageService.Mapper { @@ -30,6 +30,28 @@ namespace LINGYUN.Abp.MessageService.Mapper })); CreateMap(); + + CreateMap() + .ForMember(dto => dto.Content, map => map.MapFrom(src => src.Content)) + .ForMember(dto => dto.GroupId, map => map.MapFrom(src => src.GroupId.ToString())) + .ForMember(dto => dto.MessageId, map => map.MapFrom(src => src.MessageId.ToString())) + .ForMember(dto => dto.FormUserId, map => map.MapFrom(src => src.CreatorId)) + .ForMember(dto => dto.FormUserName, map => map.MapFrom(src => src.SendUserName)) + .ForMember(dto => dto.SendTime, map => map.MapFrom(src => src.CreationTime)) + .ForMember(dto => dto.MessageType, map => map.MapFrom(src => src.Type)) + .ForMember(dto => dto.IsAnonymous, map => map.Ignore()) + .ForMember(dto => dto.ToUserId, map => map.Ignore()); + + CreateMap() + .ForMember(dto => dto.Content, map => map.MapFrom(src => src.Content)) + .ForMember(dto => dto.ToUserId, map => map.MapFrom(src => src.ReceiveUserId)) + .ForMember(dto => dto.MessageId, map => map.MapFrom(src => src.MessageId.ToString())) + .ForMember(dto => dto.FormUserId, map => map.MapFrom(src => src.CreatorId)) + .ForMember(dto => dto.FormUserName, map => map.MapFrom(src => src.SendUserName)) + .ForMember(dto => dto.SendTime, map => map.MapFrom(src => src.CreationTime)) + .ForMember(dto => dto.MessageType, map => map.MapFrom(src => src.Type)) + .ForMember(dto => dto.IsAnonymous, map => map.Ignore()) + .ForMember(dto => dto.GroupId, map => map.Ignore()); } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroup.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroup.cs new file mode 100644 index 000000000..defe140e0 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroup.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 聊天群组 + /// + public class ChatGroup : AuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 群组标识 + /// + public virtual long GroupId { get; protected set; } + /// + /// 群组名称 + /// + public virtual string Name { get; protected set; } + /// + /// 群组标记 + /// + public virtual string Tag { get; protected set; } + /// + /// 群组地址 + /// + public virtual string Address { get; protected set; } + /// + /// 群组公告 + /// + public virtual string Notice { get; protected set; } + /// + /// 最大用户数量 + /// + public virtual int MaxUserCount { get; protected set; } + /// + /// 允许匿名聊天 + /// + public virtual bool AllowAnonymous { get; set; } + /// + /// 允许发送消息 + /// + public virtual bool AllowSendMessage { get; set; } + /// + /// 群组说明 + /// + public virtual string Description { get; set; } + protected ChatGroup() + { + } + public ChatGroup(long id, string name, string tag = "", string address = "", int maxUserCount = 200) + { + GroupId = id; + Name = name; + Tag = tag; + Address = address; + MaxUserCount = maxUserCount; + } + + public void ChangeAddress(string address) + { + Address = address; + } + + public void SetNotice(string notice) + { + Notice = notice; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroupAdmin.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroupAdmin.cs new file mode 100644 index 000000000..6c31cff0f --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatGroupAdmin.cs @@ -0,0 +1,69 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 群管理员 + /// + public class ChatGroupAdmin : AuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 群组标识 + /// + public virtual long GroupId { get; protected set; } + /// + /// 管理员用户 + /// + public virtual Guid UserId { get; protected set; } + /// + /// 是否群主 + /// + public virtual bool IsSuperAdmin { get; protected set; } + /// + /// 允许禁言 + /// + public virtual bool AllowSilence { get; set; } + /// + /// 允许踢人 + /// + public virtual bool AllowKickPeople { get; set; } + /// + /// 允许加人 + /// + public virtual bool AllowAddPeople { get; set; } + /// + /// 允许发送群公告 + /// + public virtual bool AllowSendNotice { get; set; } + /// + /// 允许解散群组 + /// + public virtual bool AllowDissolveGroup { get; set; } + protected ChatGroupAdmin() { } + public ChatGroupAdmin(long groupId, Guid userId, bool isSuperAdmin = false) + { + GroupId = groupId; + UserId = userId; + AllowSilence = true; + AllowKickPeople = true; + AllowAddPeople = true; + AllowSendNotice = true; + SetSuperAdmin(isSuperAdmin); + } + + public void SetSuperAdmin(bool isSuperAdmin = false) + { + IsSuperAdmin = isSuperAdmin; + if (isSuperAdmin) + { + AllowDissolveGroup = true; + } + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatMessage.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatMessage.cs deleted file mode 100644 index fb4ac32b3..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatMessage.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using Volo.Abp.Domain.Entities; -using Volo.Abp.MultiTenancy; - -namespace LINGYUN.Abp.MessageService.Messages -{ - public abstract class ChatMessage : Entity, IMultiTenant - { - /// - /// 租户 - /// - public virtual Guid? TenantId { get; protected set; } - /// - /// 发送用户标识 - /// - public virtual Guid SendUserId { get; protected set; } - /// - /// 接收用户标识 - /// - public virtual Guid ReceiveUserId { get; set; } - /// - /// 内容 - /// - public virtual string Content { get; protected set; } - /// - /// 发送状态 - /// - public virtual SendStatus SendStatus { get; protected set; } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupChatBlack.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupChatBlack.cs new file mode 100644 index 000000000..8c95ec396 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupChatBlack.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 用户黑名单 + /// + public class GroupChatBlack : CreationAuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 群组标识 + /// + public virtual long GroupId { get; protected set; } + /// + /// 拉黑的用户 + /// + public virtual Guid ShieldUserId { get; protected set; } + protected GroupChatBlack() { } + public GroupChatBlack(long groupId, Guid shieldUserId, Guid? tenantId) + { + GroupId = groupId; + ShieldUserId = shieldUserId; + TenantId = tenantId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupMessage.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupMessage.cs new file mode 100644 index 000000000..8897e4fcf --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/GroupMessage.cs @@ -0,0 +1,24 @@ +using LINGYUN.Abp.IM.Messages; +using System; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class GroupMessage : Message + { + /// + /// 群组标识 + /// + public virtual long GroupId { get; protected set; } + + protected GroupMessage() { } + public GroupMessage(long id, Guid sendUserId, string sendUserName, string content, MessageType type = MessageType.Text) + : base(id, sendUserId, sendUserName, content, type) + { + + } + public void SendToGroup(long groupId) + { + GroupId = groupId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IGroupRepository.cs new file mode 100644 index 000000000..864e5170e --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IGroupRepository.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public interface IGroupRepository : IBasicRepository + { + /// + /// 用户是否已被拉黑 + /// + /// + /// + /// + Task UserHasBlackedAsync(long id, Guid formUserId); + + Task GetByIdAsync(long id); + + Task> GetGroupAdminAsync(long id); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IMessageRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IMessageRepository.cs new file mode 100644 index 000000000..825e96b9e --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IMessageRepository.cs @@ -0,0 +1,24 @@ +using LINGYUN.Abp.IM.Messages; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public interface IMessageRepository + { + Task InsertUserMessageAsync(UserMessage userMessage, bool saveChangs = false); + + Task InsertGroupMessageAsync(GroupMessage groupMessage, bool saveChangs = false); + + Task GetUserMessageAsync(long id); + + Task GetGroupMessageAsync(long id); + + Task> GetUserMessagesAsync(Guid sendUserId, Guid receiveUserId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10); + + Task> GetGroupMessagesAsync(long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10); + + Task> GetUserGroupMessagesAsync(Guid sendUserId, long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatGroupRepository.cs new file mode 100644 index 000000000..2772adaff --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatGroupRepository.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.IM.Group; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public interface IUserChatGroupRepository : IBasicRepository + { + /// + /// 用户是否在组里 + /// + /// + /// + /// + Task UserHasInGroupAsync(long groupId, Guid userId); + + Task GetUserGroupAsync(long groupId, Guid userId); + + Task> GetGroupUsersAsync(long groupId); + + Task> GetUserGroupsAsync(Guid userId); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatSettingRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatSettingRepository.cs new file mode 100644 index 000000000..a091c38c4 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/IUserChatSettingRepository.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public interface IUserChatSettingRepository : IBasicRepository + { + Task UserHasOpendImAsync(Guid userId); + /// + /// 用户是否已被拉黑 + /// + /// + /// + /// + Task UserHasBlackedAsync(Guid formUserId, Guid toUserId); + + Task GetByUserIdAsync(Guid userId); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/Message.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/Message.cs new file mode 100644 index 000000000..3bb474be0 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/Message.cs @@ -0,0 +1,50 @@ +using LINGYUN.Abp.IM.Messages; +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public abstract class Message : CreationAuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 消息标识 + /// + public virtual long MessageId { get; protected set; } + /// + /// 发送用户名称 + /// + public virtual string SendUserName { get; protected set; } + /// + /// 内容 + /// + public virtual string Content { get; protected set; } + /// + /// 消息类型 + /// + public virtual MessageType Type { get; protected set; } + /// + /// 发送状态 + /// + public virtual MessageSendState SendState { get; protected set; } + protected Message() { } + public Message(long id, Guid sendUserId, string sendUserName, string content, MessageType type = MessageType.Text) + { + MessageId = id; + CreatorId = sendUserId; + SendUserName = sendUserName; + Content = content; + Type = type; + CreationTime = DateTime.Now; + } + + public void ChangeSendState(MessageSendState state = MessageSendState.Send) + { + SendState = state; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/MessageStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/MessageStore.cs new file mode 100644 index 000000000..46d4cf74e --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/MessageStore.cs @@ -0,0 +1,132 @@ +using LINGYUN.Abp.IM.Messages; +using LINGYUN.Abp.MessageService.Utils; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Domain.Services; +using Volo.Abp.ObjectMapping; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class MessageStore : DomainService, IMessageStore + { + private IObjectMapper _objectMapper; + protected IObjectMapper ObjectMapper => LazyGetRequiredService(ref _objectMapper); + + private IUnitOfWorkManager _unitOfWorkManager; + protected IUnitOfWorkManager UnitOfWorkManager => LazyGetRequiredService(ref _unitOfWorkManager); + protected IUserChatSettingRepository UserChatSettingRepository { get; } + protected IMessageRepository MessageRepository { get; } + protected IGroupRepository GroupRepository { get; } + protected ISnowflakeIdGenerator SnowflakeIdGenerator { get; } + public MessageStore( + IGroupRepository groupRepository, + IMessageRepository messageRepository, + ISnowflakeIdGenerator snowflakeIdGenerator, + IUserChatSettingRepository userChatSettingRepository) + { + GroupRepository = groupRepository; + MessageRepository = messageRepository; + SnowflakeIdGenerator = snowflakeIdGenerator; + UserChatSettingRepository = userChatSettingRepository; + } + + [UnitOfWork] + public async Task StoreMessageAsync(ChatMessage chatMessage) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(chatMessage.TenantId)) + { + if (!chatMessage.GroupId.IsNullOrWhiteSpace()) + { + long groupId = long.Parse(chatMessage.GroupId); + await StoreGroupMessageAsync(chatMessage, groupId); + } + else + { + await StoreUserMessageAsync(chatMessage); + } + await unitOfWork.SaveChangesAsync(); + } + } + } + + public async Task> GetGroupMessageAsync(Guid? tenantId, long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10) + { + using (CurrentTenant.Change(tenantId)) + { + var groupMessages = await MessageRepository.GetGroupMessagesAsync(groupId, filter, type, skipCount, maxResultCount); + var chatMessages = ObjectMapper.Map, List>(groupMessages); + + return chatMessages; + } + } + + public async Task> GetChatMessageAsync(Guid? tenantId, Guid sendUserId, Guid receiveUserId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10) + { + using (CurrentTenant.Change(tenantId)) + { + var userMessages = await MessageRepository.GetUserMessagesAsync(sendUserId, receiveUserId, filter, type, skipCount, maxResultCount); + var chatMessages = ObjectMapper.Map, List>(userMessages); + + return chatMessages; + } + } + + protected virtual async Task StoreUserMessageAsync(ChatMessage chatMessage) + { + var userHasBlacked = await UserChatSettingRepository + .UserHasBlackedAsync(chatMessage.ToUserId.Value, chatMessage.FormUserId); + if (userHasBlacked) + { + // 当前发送的用户已被拉黑 + throw new BusinessException(MessageServiceErrorCodes.UserHasBlack); + } + var userChatSetting = await UserChatSettingRepository.GetByUserIdAsync(chatMessage.ToUserId.Value); + if (!userChatSetting.AllowReceiveMessage) + { + // 当前发送的用户不接收消息 + throw new BusinessException(MessageServiceErrorCodes.UserHasRejectAllMessage); + } + if (chatMessage.IsAnonymous && !userChatSetting.AllowAnonymous) + { + // 当前用户不允许匿名发言 + throw new BusinessException(MessageServiceErrorCodes.UserNotAllowedToSpeakAnonymously); + } + var messageId = SnowflakeIdGenerator.Create(); + var message = new UserMessage(messageId, chatMessage.FormUserId, chatMessage.FormUserName, chatMessage.Content, chatMessage.MessageType); + message.SendToUser(chatMessage.ToUserId.Value); + await MessageRepository.InsertUserMessageAsync(message); + } + + protected virtual async Task StoreGroupMessageAsync(ChatMessage chatMessage, long groupId) + { + var userHasBlacked = await GroupRepository + .UserHasBlackedAsync(groupId, chatMessage.FormUserId); + if (userHasBlacked) + { + // 当前发送的用户已被拉黑 + throw new BusinessException(MessageServiceErrorCodes.GroupUserHasBlack); + } + var group = await GroupRepository.GetByIdAsync(groupId); + if (!group.AllowSendMessage) + { + // 当前群组不允许发言 + throw new BusinessException(MessageServiceErrorCodes.GroupNotAllowedToSpeak); + } + if (chatMessage.IsAnonymous && !group.AllowAnonymous) + { + // 当前群组不允许匿名发言 + throw new BusinessException(MessageServiceErrorCodes.GroupNotAllowedToSpeakAnonymously); + } + var messageId = SnowflakeIdGenerator.Create(); + var message = new GroupMessage(messageId, chatMessage.FormUserId, chatMessage.FormUserName, chatMessage.Content, chatMessage.MessageType); + // TODO: 需要压测 高并发场景下的装箱性能影响 + message.SendToGroup(groupId); + await MessageRepository.InsertGroupMessageAsync(message); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatBlack.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatBlack.cs new file mode 100644 index 000000000..4dc1267b6 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatBlack.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 用户黑名单 + /// + public class UserChatBlack : CreationAuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 用户标识 + /// + public virtual Guid UserId { get; protected set; } + /// + /// 拉黑的用户 + /// + public virtual Guid ShieldUserId { get; protected set; } + protected UserChatBlack() { } + public UserChatBlack(Guid userId, Guid shieldUserId, Guid? tenantId) + { + UserId = userId; + ShieldUserId = shieldUserId; + TenantId = tenantId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatGroup.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatGroup.cs new file mode 100644 index 000000000..b4b49bc59 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatGroup.cs @@ -0,0 +1,27 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 用户群组 + /// + public class UserChatGroup : CreationAuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + public virtual Guid UserId { get; protected set; } + public virtual long GroupId { get; protected set; } + protected UserChatGroup() { } + public UserChatGroup(long groupId, Guid userId, Guid acceptUserId, Guid? tenantId = null) + { + UserId = userId; + GroupId = groupId; + CreatorId = acceptUserId; + TenantId = tenantId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatSetting.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatSetting.cs new file mode 100644 index 000000000..926884807 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserChatSetting.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class UserChatSetting : Entity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 用户标识 + /// + public virtual Guid UserId { get; protected set; } + /// + /// 允许匿名聊天 + /// + public virtual bool AllowAnonymous { get; set; } + /// + /// 允许添加好友 + /// + public virtual bool AllowAddFriend { get; set; } + /// + /// 添加好友需要验证 + /// + public virtual bool RequireAddFriendValition { get; set; } + /// + /// 允许接收消息 + /// + public virtual bool AllowReceiveMessage { get; set; } + /// + /// 允许发送消息 + /// + public virtual bool AllowSendMessage { get; set; } + protected UserChatSetting() + { + } + public UserChatSetting(Guid userId, Guid? tenantId) + : this() + { + UserId = userId; + TenantId = tenantId; + AllowAnonymous = false; + AllowAddFriend = true; + AllowReceiveMessage = true; + AllowSendMessage = true; + RequireAddFriendValition = true; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserGroupStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserGroupStore.cs new file mode 100644 index 000000000..a94ad250f --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserGroupStore.cs @@ -0,0 +1,86 @@ +using LINGYUN.Abp.IM.Group; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; +using Volo.Abp.ObjectMapping; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class UserGroupStore : DomainService, IUserGroupStore + { + private IObjectMapper _objectMapper; + protected IObjectMapper ObjectMapper => LazyGetRequiredService(ref _objectMapper); + + private IUnitOfWorkManager _unitOfWorkManager; + protected IUnitOfWorkManager UnitOfWorkManager => LazyGetRequiredService(ref _unitOfWorkManager); + + protected IUserChatGroupRepository UserChatGroupRepository { get; } + + public UserGroupStore( + IUserChatGroupRepository userChatGroupRepository) + { + UserChatGroupRepository = userChatGroupRepository; + } + + [UnitOfWork] + public async Task AddUserToGroupAsync(Guid? tenantId, Guid userId, long groupId, Guid acceptUserId) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + var userHasInGroup = await UserChatGroupRepository.UserHasInGroupAsync(groupId, userId); + if (!userHasInGroup) + { + var userGroup = new UserChatGroup(groupId, userId, acceptUserId, tenantId); + + await UserChatGroupRepository.InsertAsync(userGroup); + + await unitOfWork.SaveChangesAsync(); + } + } + } + } + + public async Task> GetGroupUsersAsync(Guid? tenantId, long groupId) + { + using (CurrentTenant.Change(tenantId)) + { + var userGroups = await UserChatGroupRepository.GetGroupUsersAsync(groupId); + + return userGroups; + } + } + + public async Task> GetUserGroupsAsync(Guid? tenantId, Guid userId) + { + using (CurrentTenant.Change(tenantId)) + { + var groups = await UserChatGroupRepository.GetUserGroupsAsync(userId); + + return groups; + } + } + + [UnitOfWork] + public async Task RemoveUserFormGroupAsync(Guid? tenantId, Guid userId, long groupId) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + var userGroup = await UserChatGroupRepository.GetUserGroupAsync(groupId, userId); + + if(userGroup != null) + { + await UserChatGroupRepository.DeleteAsync(userGroup); + + await unitOfWork.SaveChangesAsync(); + } + } + } + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserMessage.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserMessage.cs new file mode 100644 index 000000000..540f4a06b --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserMessage.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.IM.Messages; +using System; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class UserMessage : Message + { + /// + /// 接收用户标识 + /// + public virtual Guid ReceiveUserId { get; set; } + + protected UserMessage() { } + public UserMessage(long id, Guid sendUserId, string sendUserName, string content, MessageType type = MessageType.Text) + : base(id, sendUserId, sendUserName, content, type) + { + + } + + public void SendToUser(Guid receiveUserId) + { + ReceiveUserId = receiveUserId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserSpecialFocus.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserSpecialFocus.cs new file mode 100644 index 000000000..b7835f920 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/UserSpecialFocus.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MessageService.Messages +{ + /// + /// 用户特别关注 + /// + public class UserSpecialFocus : CreationAuditedEntity, IMultiTenant + { + /// + /// 租户 + /// + public virtual Guid? TenantId { get; protected set; } + /// + /// 用户标识 + /// + public virtual Guid UserId { get; protected set; } + /// + /// 关注的用户 + /// + public virtual Guid FocusUserId { get; protected set; } + protected UserSpecialFocus() { } + public UserSpecialFocus(Guid userId, Guid focusUserId, Guid? tenantId) + { + UserId = userId; + FocusUserId = focusUserId; + TenantId = tenantId; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/AbpMessageServiceEntityFrameworkCoreModule.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/AbpMessageServiceEntityFrameworkCoreModule.cs index 8fdc82b7d..aee1cc373 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/AbpMessageServiceEntityFrameworkCoreModule.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/AbpMessageServiceEntityFrameworkCoreModule.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.MessageService.Notifications; +using LINGYUN.Abp.MessageService.Messages; +using LINGYUN.Abp.MessageService.Notifications; using LINGYUN.Abp.MessageService.Subscriptions; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EntityFrameworkCore; @@ -19,6 +20,10 @@ namespace LINGYUN.Abp.MessageService.EntityFrameworkCore options.AddRepository(); options.AddRepository(); + options.AddRepository(); + options.AddRepository(); + options.AddRepository(); + options.AddDefaultRepositories(includeAllEntities: true); }); } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs index a30c550a8..71e42ab07 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs @@ -1,4 +1,5 @@ -using LINGYUN.Abp.MessageService.Notifications; +using LINGYUN.Abp.MessageService.Messages; +using LINGYUN.Abp.MessageService.Notifications; using LINGYUN.Abp.MessageService.Subscriptions; using Microsoft.EntityFrameworkCore; using System; @@ -52,11 +53,108 @@ namespace LINGYUN.Abp.MessageService.EntityFrameworkCore b.ConfigureCreationTime(); b.ConfigureMultiTenant(); - b.ConfigureMultiTenant(); b.HasIndex(p => new { p.TenantId, p.UserId, p.NotificationName }) .HasName("IX_Tenant_User_Notification_Name") .IsUnique(); }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserMessages", options.Schema); + + b.Property(p => p.SendUserName).HasMaxLength(MessageConsts.MaxSendUserNameLength).IsRequired(); + b.Property(p => p.Content).HasMaxLength(MessageConsts.MaxContentLength).IsRequired(); + + b.ConfigureCreationTime(); + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.ReceiveUserId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "GroupMessages", options.Schema); + + b.Property(p => p.SendUserName).HasMaxLength(MessageConsts.MaxSendUserNameLength).IsRequired(); + b.Property(p => p.Content).HasMaxLength(MessageConsts.MaxContentLength).IsRequired(); + + b.ConfigureCreationTime(); + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.GroupId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserChatSettings", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.UserId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserSpecialFocuss", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.UserId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserChatBlacks", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.UserId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "GroupChatBlacks", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.GroupId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "ChatGroupAdmins", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.GroupId }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "ChatGroups", options.Schema); + + b.Property(p => p.Name).HasMaxLength(ChatGroupConsts.MaxNameLength).IsRequired(); + + b.Property(p => p.Tag).HasMaxLength(ChatGroupConsts.MaxTagLength); + b.Property(p => p.Notice).HasMaxLength(ChatGroupConsts.MaxNoticeLength); + b.Property(p => p.Address).HasMaxLength(ChatGroupConsts.MaxAddressLength); + b.Property(p => p.Description).HasMaxLength(ChatGroupConsts.MaxDescriptionLength); + + b.ConfigureAudited(); + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.Name }); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserChatGroups", options.Schema); + + b.ConfigureCreationAudited(); + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.GroupId, p.UserId }); + }); } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs new file mode 100644 index 000000000..1b1b1e653 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreGroupRepository.cs @@ -0,0 +1,43 @@ +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class EfCoreGroupRepository : EfCoreRepository, + IGroupRepository, ITransientDependency + { + public EfCoreGroupRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task GetByIdAsync(long id) + { + return await DbSet.Where(x => x.GroupId.Equals(id)).FirstOrDefaultAsync(); + } + + public async Task> GetGroupAdminAsync(long id) + { + var groupAdmins = await (from gp in DbContext.Set() + join gpa in DbContext.Set() + on gp.GroupId equals gpa.GroupId + select gpa).ToListAsync(); + return groupAdmins; + } + + public async Task UserHasBlackedAsync(long id, Guid formUserId) + { + var userHasBlack = await DbContext.Set() + .AnyAsync(x => x.GroupId.Equals(id) && x.ShieldUserId.Equals(formUserId)); + return userHasBlack; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs new file mode 100644 index 000000000..6508e1a83 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreMessageRepository.cs @@ -0,0 +1,114 @@ +using LINGYUN.Abp.IM.Messages; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class EfCoreMessageRepository : EfCoreRepository, + IMessageRepository, ITransientDependency + { + public EfCoreMessageRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task GetGroupMessageAsync(long id) + { + return await DbContext.Set() + .Where(x => x.MessageId.Equals(id)) + .AsNoTracking() + .FirstOrDefaultAsync(); + } + + public async Task> GetGroupMessagesAsync(long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10) + { + if(skipCount > 0) + { + skipCount -= 1; + } + var groupMessages = await DbContext.Set() + .Where(x => x.GroupId.Equals(groupId) && x.Type.Equals(type)) + .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) + .OrderByDescending(x => x.MessageId) + .Skip(skipCount * maxResultCount) + .Take(maxResultCount) + .ToListAsync(); + + return groupMessages; + } + + public async Task> GetUserGroupMessagesAsync(Guid sendUserId, long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10) + { + if (skipCount > 0) + { + skipCount -= 1; + } + var groupMessages = await DbContext.Set() + .Where(x => x.GroupId.Equals(groupId) && x.CreatorId.Equals(sendUserId) && x.Type.Equals(type)) + .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) + .OrderByDescending(x => x.MessageId) + .Skip(skipCount * maxResultCount) + .Take(maxResultCount) + .ToListAsync(); + + return groupMessages; + } + + public async Task GetUserMessageAsync(long id) + { + return await DbContext.Set() + .Where(x => x.MessageId.Equals(id)) + .AsNoTracking() + .FirstOrDefaultAsync(); + } + + public async Task> GetUserMessagesAsync(Guid sendUserId, Guid receiveUserId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, int maxResultCount = 10) + { + if (skipCount > 0) + { + skipCount -= 1; + } + var userMessages = await DbContext.Set() + .Where(x => x.CreatorId.Equals(sendUserId) && x.ReceiveUserId.Equals(receiveUserId) && x.Type.Equals(type)) + .WhereIf(!filter.IsNullOrWhiteSpace(), x => x.Content.Contains(filter) || x.SendUserName.Contains(filter)) + .OrderByDescending(x => x.MessageId) + .Skip(skipCount * maxResultCount) + .Take(maxResultCount) + .ToListAsync(); + + return userMessages; + } + + public async Task InsertGroupMessageAsync(GroupMessage groupMessage, bool saveChangs = false) + { + groupMessage = (await DbContext.Set().AddAsync(groupMessage, GetCancellationToken())).Entity; + + if(saveChangs) + { + await DbContext.SaveChangesAsync(); + } + + return groupMessage; + } + + public async Task InsertUserMessageAsync(UserMessage userMessage, bool saveChangs = false) + { + userMessage = (await DbContext.Set().AddAsync(userMessage, GetCancellationToken())).Entity; + + if (saveChangs) + { + await DbContext.SaveChangesAsync(); + } + + return userMessage; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs new file mode 100644 index 000000000..95cfec605 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatGroupRepository.cs @@ -0,0 +1,86 @@ +using LINGYUN.Abp.IM.Group; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class EfCoreUserChatGroupRepository : EfCoreRepository, + IUserChatGroupRepository, ITransientDependency + { + public EfCoreUserChatGroupRepository( + IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + public async Task> GetGroupUsersAsync(long groupId) + { + // TODO: 急需单元测试,对这段代码不是太自信... + var groupUsers = await (from ug in DbSet + join x in ( + from gaj in DbContext.Set() + where gaj.GroupId.Equals(groupId) + select gaj + ) on ug.UserId equals x.UserId + into y from ga in y.DefaultIfEmpty() + where ug.GroupId.Equals(groupId) + select new UserGroup + { + GroupId = ug.GroupId, + IsSuperAdmin = ga != null && ga.IsSuperAdmin, + IsAdmin = ga != null, + TenantId = ug.TenantId, + UserId = ug.UserId + }) + .AsNoTracking() + .ToListAsync(); + return groupUsers; + } + + public async Task GetUserGroupAsync(long groupId, Guid userId) + { + return await DbSet.Where(x => x.GroupId.Equals(groupId) && x.UserId.Equals(userId)) + .AsNoTracking() + .FirstOrDefaultAsync(); + } + + public async Task> GetUserGroupsAsync(Guid userId) + { + // TODO: 急需单元测试,对这段代码不是太自信... + var userGroups = await (from ucg in DbSet + join cg in DbContext.Set() + 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 + }).ToListAsync(); + + return userGroups; + } + + public async Task UserHasInGroupAsync(long groupId, Guid userId) + { + return await DbSet.AnyAsync(x => x.GroupId.Equals(groupId) && x.UserId.Equals(userId)); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatSettingRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatSettingRepository.cs new file mode 100644 index 000000000..e68008eaf --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Messages/EfCoreUserChatSettingRepository.cs @@ -0,0 +1,39 @@ +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.Messages +{ + public class EfCoreUserChatSettingRepository : EfCoreRepository, + IUserChatSettingRepository, ITransientDependency + { + public EfCoreUserChatSettingRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task GetByUserIdAsync(Guid userId) + { + return await DbSet.Where(x => x.UserId.Equals(userId)) + .AsNoTracking() + .FirstOrDefaultAsync(); + } + + public async Task UserHasBlackedAsync(Guid formUserId, Guid toUserId) + { + return await DbContext.Set() + .AnyAsync(x => x.UserId.Equals(toUserId) && x.ShieldUserId.Equals(formUserId)); + } + + public async Task UserHasOpendImAsync(Guid userId) + { + return await DbSet.AnyAsync(x => x.UserId.Equals(userId)); + } + } +} diff --git a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs index 53ac44165..e63868347 100644 --- a/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs +++ b/aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs @@ -41,6 +41,12 @@ namespace LINGYUN.Abp.SettingManagement continue; } + // TODO: 是否遵循框架的限制? + //if (!setting.IsVisibleToClients) + //{ + // continue; + //} + var settingValue = await SettingManager.GetOrNullAsync(setting.Name, providerName, providerKey); var settingInfo = new SettingDto { diff --git a/vueJs/images/aggregate.png b/vueJs/images/aggregate.png new file mode 100644 index 000000000..537a913da Binary files /dev/null and b/vueJs/images/aggregate.png differ diff --git a/vueJs/images/client.png b/vueJs/images/client.png new file mode 100644 index 000000000..8c9f4679b Binary files /dev/null and b/vueJs/images/client.png differ diff --git a/vueJs/images/im-notifications.png b/vueJs/images/im-notifications.png new file mode 100644 index 000000000..aac0ca99c Binary files /dev/null and b/vueJs/images/im-notifications.png differ diff --git a/vueJs/images/tenant.png b/vueJs/images/tenant.png new file mode 100644 index 000000000..c2042fd6d Binary files /dev/null and b/vueJs/images/tenant.png differ diff --git a/vueJs/src/components/TenantBox/index.vue b/vueJs/src/components/TenantBox/index.vue index d96409f90..1ed363f54 100644 --- a/vueJs/src/components/TenantBox/index.vue +++ b/vueJs/src/components/TenantBox/index.vue @@ -9,10 +9,9 @@ - {{ $t('AbpUiMultiTenancy.SwitchTenant') }} + ({{ $t('AbpUiMultiTenancy.SwitchTenant') }})