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/Controllers/NotificationController.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs new file mode 100644 index 000000000..fc87e40a4 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Controllers/NotificationController.cs @@ -0,0 +1,62 @@ +using LINGYUN.Abp.Notifications; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.Abp.MessageService.Controllers +{ + [Route("api/app/notifications")] + public class NotificationController : AbpController + { + private readonly INotificationDispatcher _notificationDispatcher; + public NotificationController( + INotificationDispatcher notificationDispatcher) + { + _notificationDispatcher = notificationDispatcher; + } + + [HttpPost] + [Route("Send")] + public async Task SendNofitication([FromForm] SendNotification notification) + { + var notificationInfo = new NotificationInfo + { + TenantId = null, + NotificationSeverity = notification.Severity, + NotificationType = NotificationType.Application, + Id = new Random().Next(int.MinValue, int.MaxValue), + Name = "TestApplicationNotofication", + CreationTime = Clock.Now + }; + notificationInfo.Data.Properties["id"] = notificationInfo.Id.ToString(); + notificationInfo.Data.Properties["title"] = notification.Title; + notificationInfo.Data.Properties["message"] = notification.Message; + notificationInfo.Data.Properties["datetime"] = Clock.Now; + notificationInfo.Data.Properties["severity"] = notification.Severity; + + await _notificationDispatcher.DispatcheAsync(notificationInfo); + } + } + + public class SendNotification + { + public Guid UserId { get; set; } + public string Title { get; set; } + public string Message { get; set; } + public NotificationSeverity Severity { get; set; } = NotificationSeverity.Success; + } + + public class TestApplicationNotificationData : NotificationData + { + public object Message + { + get { return this[nameof(Message)]; } + set + { + Properties[nameof(Message)] = value; + } + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs new file mode 100644 index 000000000..20be364d6 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContext.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + public class MessageServiceHostMigrationsDbContext : AbpDbContext + { + public MessageServiceHostMigrationsDbContext(DbContextOptions options) + : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureMessageService(); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs new file mode 100644 index 000000000..dc0072ba9 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/EntityFrameworkCore/MessageServiceHostMigrationsDbContextFactory.cs @@ -0,0 +1,29 @@ +using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + public class MessageServiceHostMigrationsDbContextFactory : IDesignTimeDbContextFactory + { + public MessageServiceHostMigrationsDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + + var builder = new DbContextOptionsBuilder() + .UseMySql(configuration.GetConnectionString("Default")); + + return new MessageServiceHostMigrationsDbContext(builder.Options); + } + + private static IConfigurationRoot BuildConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.Development.json", optional: false); + + return builder.Build(); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj new file mode 100644 index 000000000..bba35b34b --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj @@ -0,0 +1,40 @@ + + + + netcoreapp3.1 + LINGYUN.Abp.MessageService + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs new file mode 100644 index 000000000..917a61050 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiHostModule.cs @@ -0,0 +1,152 @@ +using IdentityModel; +using LINGYUN.Abp.IM.SignalR; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using LINGYUN.Abp.MessageService.MultiTenancy; +using LINGYUN.Abp.Notifications.SignalR; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using StackExchange.Redis; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Authentication.JwtBearer; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.Autofac; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.Security.Claims; +using Volo.Abp.SettingManagement.EntityFrameworkCore; +using Volo.Abp.TenantManagement.EntityFrameworkCore; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.MessageService +{ + [DependsOn( + typeof(AbpMessageServiceHttpApiModule), + typeof(AbpAspNetCoreMultiTenancyModule), + typeof(AbpMessageServiceEntityFrameworkCoreModule), + typeof(AbpTenantManagementEntityFrameworkCoreModule), + typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpAspNetCoreAuthenticationJwtBearerModule), + typeof(AbpIMSignalRModule), + typeof(AbpNotificationsSignalRModule), + typeof(AbpAutofacModule) + )] + public class AbpMessageServiceHttpApiHostModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = hostingEnvironment.BuildConfiguration(); + // 配置Ef + Configure(options => + { + options.UseMySQL(); + }); + + Configure(options => + { + options.FileSets.AddEmbedded("LINGYUN.Abp.MessageService"); + }); + + // 多租户 + Configure(options => + { + options.IsEnabled = true; + }); + + Configure(options => + { + options.TenantResolvers.Insert(0, new AuthorizationTenantResolveContributor()); + }); + + // Swagger + context.Services.AddSwaggerGen( + options => + { + options.SwaggerDoc("v1", new OpenApiInfo { Title = "MessageService API", Version = "v1" }); + options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); + }); + + // 支持本地化语言类型 + Configure(options => + { + options.Languages.Add(new LanguageInfo("en", "en", "English")); + options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + }); + + context.Services.AddAuthentication("Bearer") + .AddIdentityServerAuthentication(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.RequireHttpsMetadata = false; + options.ApiName = configuration["AuthServer:ApiName"]; + AbpClaimTypes.UserId = JwtClaimTypes.Subject; + AbpClaimTypes.UserName = JwtClaimTypes.Name; + AbpClaimTypes.Role = JwtClaimTypes.Role; + AbpClaimTypes.Email = JwtClaimTypes.Email; + }); + + context.Services.AddStackExchangeRedisCache(options => + { + options.Configuration = configuration["RedisCache:ConnectString"]; + var instanceName = configuration["RedisCache:RedisPrefix"]; + options.InstanceName = instanceName.IsNullOrEmpty() ? "MessageService_Cache" : instanceName; + }); + + if (!hostingEnvironment.IsDevelopment()) + { + var redis = ConnectionMultiplexer.Connect(configuration["RedisCache:ConnectString"]); + context.Services + .AddDataProtection() + .PersistKeysToStackExchangeRedis(redis, "MessageService-Protection-Keys"); + } + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + // http调用链 + app.UseCorrelationId(); + // 虚拟文件系统 + app.UseVirtualFiles(); + // 本地化 + app.UseAbpRequestLocalization(); + //路由 + app.UseRouting(); + // 加入自定义中间件 + app.UseMiddleware(); + // 认证 + app.UseAuthentication(); + // jwt + app.UseJwtTokenMiddleware(); + // 授权 + app.UseAuthorization(); + // 多租户 + app.UseMultiTenancy(); + // Swagger + app.UseSwagger(); + // Swagger可视化界面 + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support MessageService API"); + }); + // 审计日志 + app.UseAuditing(); + // 路由 + app.UseConfiguredEndpoints(); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs new file mode 100644 index 000000000..0b5d5b0c8 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN/Abp/MessageService/Utils/SnowflakeIdGenerator.cs @@ -0,0 +1,16 @@ +using DotNetCore.CAP.Internal; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.MessageService.Utils +{ + [Dependency(ServiceLifetime.Singleton, TryRegister = true)] + [ExposeServices(typeof(ISnowflakeIdGenerator))] + public class SnowflakeIdGenerator : ISnowflakeIdGenerator + { + public long Create() + { + return SnowflakeId.Default().NextId(); + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs new file mode 100644 index 000000000..54ac519b1 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.Designer.cs @@ -0,0 +1,130 @@ +// +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("20200601060701_Add-Abp-Message-Service-Module")] + partial class AddAbpMessageServiceModule + { + 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.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("tinyint"); + + 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/20200601060701_Add-Abp-Message-Service-Module.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs new file mode 100644 index 000000000..4da6c6aef --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/20200601060701_Add-Abp-Message-Service-Module.cs @@ -0,0 +1,93 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + public partial class AddAbpMessageServiceModule : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AppNotifications", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + TenantId = table.Column(nullable: true), + Severity = table.Column(nullable: false), + Type = table.Column(nullable: false), + NotificationId = table.Column(nullable: false), + NotificationName = table.Column(maxLength: 100, nullable: false), + NotificationData = table.Column(maxLength: 1048576, nullable: false), + NotificationTypeName = table.Column(maxLength: 512, nullable: false), + ExpirationTime = table.Column(nullable: true), + CreationTime = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppNotifications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserNotifications", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + TenantId = table.Column(nullable: true), + UserId = table.Column(nullable: false), + NotificationId = table.Column(nullable: false), + ReadStatus = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserNotifications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AppUserSubscribes", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + TenantId = table.Column(nullable: true), + CreationTime = table.Column(nullable: false), + NotificationName = table.Column(maxLength: 100, nullable: false), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AppUserSubscribes", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_AppNotifications_NotificationName", + table: "AppNotifications", + column: "NotificationName"); + + migrationBuilder.CreateIndex( + name: "IX_Tenant_User_Notification_Id", + table: "AppUserNotifications", + columns: new[] { "TenantId", "UserId", "NotificationId" }); + + migrationBuilder.CreateIndex( + name: "IX_Tenant_User_Notification_Name", + table: "AppUserSubscribes", + columns: new[] { "TenantId", "UserId", "NotificationName" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AppNotifications"); + + migrationBuilder.DropTable( + name: "AppUserNotifications"); + + migrationBuilder.DropTable( + name: "AppUserSubscribes"); + } + } +} 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 new file mode 100644 index 000000000..8704b41fc --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Migrations/MessageServiceHostMigrationsDbContextModelSnapshot.cs @@ -0,0 +1,492 @@ +// +using System; +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace LINGYUN.Abp.MessageService.Migrations +{ + [DbContext(typeof(MessageServiceHostMigrationsDbContext))] + partial class MessageServiceHostMigrationsDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(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/MultiTenancy/AuthorizationTenantResolveContributor.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs new file mode 100644 index 000000000..f0c09657f --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/MultiTenancy/AuthorizationTenantResolveContributor.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Http; +using System.Linq; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Security.Claims; + +namespace LINGYUN.Abp.MessageService.MultiTenancy +{ + public class AuthorizationTenantResolveContributor : HttpTenantResolveContributorBase + { + public override string Name => "Authorization"; + + protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context, HttpContext httpContext) + { + if (httpContext.User?.Identity == null) + { + return null; + } + if (!httpContext.User.Identity.IsAuthenticated) + { + return null; + } + var tenantIdKey = context.GetAbpAspNetCoreMultiTenancyOptions().TenantKey; + + var tenantClaim = httpContext.User.Claims.FirstOrDefault(x => x.Type.Equals(AbpClaimTypes.TenantId)); + + if (tenantClaim == null) + { + return null; + } + + return tenantClaim.Value; + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs new file mode 100644 index 000000000..210cb65f8 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Program.cs @@ -0,0 +1,49 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Serilog; +using System; +using System.IO; + +namespace LINGYUN.Abp.MessageService +{ + public class Program + { + public static int Main(string[] args) + { + var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"; + var configuration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile($"appsettings.{env}.json", optional: false, reloadOnChange: true) + .AddEnvironmentVariables() + .Build(); + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(configuration) + .CreateLogger(); + try + { + Log.Information("Starting web host."); + CreateHostBuilder(args).Build().Run(); + return 0; + } + catch (Exception ex) + { + Log.Fatal(ex, "Host terminated unexpectedly!"); + return 1; + } + finally + { + Log.CloseAndFlush(); + } + } + + internal static IHostBuilder CreateHostBuilder(string[] args) => + Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }) + .UseSerilog() + .UseAutofac(); + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json new file mode 100644 index 000000000..0e44e51b1 --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Properties/launchSettings.json @@ -0,0 +1,20 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63963", + "sslPort": 0 + } + }, + "profiles": { + "LINGYUN.Abp.MessageService.HttpApi.Host": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "http://localhost:30020", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs new file mode 100644 index 000000000..ad091b0da --- /dev/null +++ b/aspnet-core/LINGYUN.Abp.MessageService.HttpApi.Host/Startup.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace LINGYUN.Abp.MessageService +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddApplication(); + } + + public void Configure(IApplicationBuilder app) + { + app.InitializeApplication(); + } + } +} diff --git a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs index c2e5e7982..0ec05b642 100644 --- a/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs +++ b/aspnet-core/modules/account/LINGYUN.Abp.Account.Application/LINGYUN/Abp/Account/AccountAppService.cs @@ -59,13 +59,15 @@ namespace LINGYUN.Abp.Account var userEmail = input.EmailAddress ?? input.PhoneNumber + "@abp.io"; var userName = input.UserName ?? input.PhoneNumber; - var user = new IdentityUser(GuidGenerator.Create(), userName, userEmail, CurrentTenant.Id); - user.Name = input.Name ?? input.PhoneNumber; + var user = new IdentityUser(GuidGenerator.Create(), userName, userEmail, CurrentTenant.Id) + { + Name = input.Name ?? input.PhoneNumber + }; (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); - await UserManager.ChangePhoneNumberAsync(user, input.PhoneNumber, input.VerifyCode); - await UserManager.SetEmailAsync(user, userEmail); - await UserManager.AddDefaultRolesAsync(user); + (await UserManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors(); + (await UserManager.SetEmailAsync(user, userEmail)).CheckErrors(); + (await UserManager.AddDefaultRolesAsync(user)).CheckErrors(); await Cache.RemoveAsync(phoneVerifyCacheKey); diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN.Abp.IM.SignalR.csproj b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN.Abp.IM.SignalR.csproj index 36bb389f9..7718a5418 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN.Abp.IM.SignalR.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN.Abp.IM.SignalR.csproj @@ -11,6 +11,7 @@ + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/AbpIMSignalRModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/AbpIMSignalRModule.cs index 541627145..6d2bcdc75 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/AbpIMSignalRModule.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/AbpIMSignalRModule.cs @@ -1,9 +1,12 @@ -using Volo.Abp.AspNetCore.SignalR; +using LINGYUN.Abp.RealTime; +using Volo.Abp.AspNetCore.SignalR; using Volo.Abp.Modularity; namespace LINGYUN.Abp.IM.SignalR { - [DependsOn(typeof(AbpAspNetCoreSignalRModule))] + [DependsOn( + typeof(AbpRealTimeModule), + typeof(AbpAspNetCoreSignalRModule))] public class AbpIMSignalRModule : AbpModule { 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 new file mode 100644 index 000000000..9e4856d84 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Hubs/MessageHub.cs @@ -0,0 +1,77 @@ +using LINGYUN.Abp.IM.Messages; +using LINGYUN.Abp.RealTime.Client; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.SignalR; + +namespace LINGYUN.Abp.IM.SignalR.Hubs +{ + [Authorize] + public class MessageHub : OnlineClientHubBase + { + private readonly IMessageStore _messageStore; + + public MessageHub( + IMessageStore messageStore) + { + _messageStore = messageStore; + } + /// + /// 客户端调用发送消息方法 + /// + /// + /// + [HubMethodName("SendMessage")] + public virtual async Task SendMessageAsync(ChatMessage chatMessage) + { + // 持久化 + await _messageStore.StoreMessageAsync(chatMessage); + + if (!chatMessage.GroupId.IsNullOrWhiteSpace()) + { + try + { + var signalRClient = Clients.Group(chatMessage.GroupId); + if (signalRClient == null) + { + Logger.LogDebug("Can not get group " + chatMessage.GroupId + " from SignalR hub!"); + return; + } + + await signalRClient.SendAsync("getChatMessage", chatMessage); + } + catch (Exception ex) + { + 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.GetValueOrDefault()); + var onlineClients = OnlineClientManager.GetAllByContext(onlineClientContext); + foreach (var onlineClient in onlineClients) + { + try + { + var signalRClient = 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); + } + } + } + } + } +} 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 new file mode 100644 index 000000000..380c90669 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/Messages/SignalRMessageSender.cs @@ -0,0 +1,101 @@ +using LINGYUN.Abp.IM.Messages; +using LINGYUN.Abp.IM.SignalR.Hubs; +using LINGYUN.Abp.RealTime.Client; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.IM.SignalR.Messages +{ + public class SignalRMessageSender : IMessageSender, ITransientDependency + { + public ILogger Logger { protected get; set; } + + private readonly IOnlineClientManager _onlineClientManager; + + private readonly IHubContext _hubContext; + + private readonly IMessageStore _messageStore; + + public SignalRMessageSender( + IOnlineClientManager onlineClientManager, + IHubContext hubContext, + IMessageStore messageStore) + { + _hubContext = hubContext; + _messageStore = messageStore; + _onlineClientManager = onlineClientManager; + + Logger = NullLogger.Instance; + } + /// + /// 服务端调用发送消息方法 + /// + /// + /// + public async Task SendMessageAsync(ChatMessage chatMessage) + { + // 持久化 + await _messageStore.StoreMessageAsync(chatMessage); + + try + { + if (!chatMessage.GroupId.IsNullOrWhiteSpace()) + { + await SendMessageToGroupAsync(chatMessage); + } + else + { + await SendMessageToUserAsync(chatMessage); + } + } + catch (Exception ex) + { + Logger.LogWarning("Could not send message, group: {0}, formUser: {1}, toUser: {2}", + chatMessage.GroupId, chatMessage.FormUserName, + chatMessage.ToUserId.HasValue ? chatMessage.ToUserId.ToString() : "None"); + Logger.LogWarning("Send group message error: {0}", ex.Message); + } + } + + protected 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.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); + } + } + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs index ad432a11e..0d9d2aac9 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM.SignalR/LINGYUN/Abp/IM/SignalR/OnlineClientHubBase.cs @@ -1,4 +1,6 @@ -using Microsoft.AspNetCore.Http; +using LINGYUN.Abp.IM.Group; +using LINGYUN.Abp.RealTime.Client; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; @@ -8,6 +10,9 @@ namespace LINGYUN.Abp.IM.SignalR { public abstract class OnlineClientHubBase : AbpHub { + private IUserGroupStore _userGroupStore; + protected IUserGroupStore UserGroupStore => LazyGetRequiredService(ref _userGroupStore); + private IOnlineClientManager _onlineClientManager; protected IOnlineClientManager OnlineClientManager => LazyGetRequiredService(ref _onlineClientManager); @@ -18,28 +23,45 @@ namespace LINGYUN.Abp.IM.SignalR { await base.OnConnectedAsync(); IOnlineClient onlineClient = CreateClientForCurrentConnection(); - Logger.LogDebug("A client is connected: " + onlineClient?.ToString()); + Logger.LogDebug("A client is connected: " + onlineClient.ToString()); OnlineClientManager.Add(onlineClient); + // 加入通讯组 + var userGroups = await UserGroupStore.GetUserGroupsAsync(onlineClient.TenantId, onlineClient.UserId.Value); + foreach(var group in userGroups) + { + await Groups.AddToGroupAsync(onlineClient.ConnectionId, group.Name); + } } public override async Task OnDisconnectedAsync(Exception exception) { await base.OnDisconnectedAsync(exception); - Logger.LogDebug("A client is disconnected: " + base.Context.ConnectionId); + Logger.LogDebug("A client is disconnected: " + Context.ConnectionId); try { - OnlineClientManager.Remove(Context.ConnectionId); + // 从通讯组移除 + var onlineClient = OnlineClientManager.GetByConnectionIdOrNull(Context.ConnectionId); + if(onlineClient != null) + { + var userGroups = await UserGroupStore.GetUserGroupsAsync(onlineClient.TenantId, onlineClient.UserId.Value); + foreach (var group in userGroups) + { + await Groups.RemoveFromGroupAsync(onlineClient.ConnectionId, group.Name); + } + // 移除在线客户端 + OnlineClientManager.Remove(Context.ConnectionId); + } } catch (Exception ex) { - base.Logger.LogWarning(ex.ToString(), ex); + Logger.LogWarning(ex.ToString(), ex); } } protected virtual IOnlineClient CreateClientForCurrentConnection() { return new OnlineClient(Context.ConnectionId, GetClientIpAddress(), - CurrentTenant.Id, CurrentUser.Id, CurrentUser.Roles) + CurrentTenant.Id, CurrentUser.Id) { ConnectTime = Clock.Now }; 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/IUserGroupStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs new file mode 100644 index 000000000..85f5f620e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/IUserGroupStore.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.IM.Group +{ + public interface IUserGroupStore + { + /// + /// 获取用户所在通讯组列表 + /// + /// + /// + /// + Task> GetUserGroupsAsync(Guid? tenantId, Guid userId); + /// + /// 获取通讯组所有用户 + /// + /// + /// + /// + Task> GetGroupUsersAsync(Guid? tenantId, long groupId); + /// + /// 用户加入通讯组 + /// + /// + /// + /// + /// + Task AddUserToGroupAsync(Guid? tenantId, Guid userId, long groupId, Guid acceptUserId); + /// + /// 用户退出通讯组 + /// + /// + /// + /// + /// + Task RemoveUserFormGroupAsync(Guid? tenantId, Guid userId, long groupId); + } +} 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 new file mode 100644 index 000000000..120b13aa0 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Group/UserGroup.cs @@ -0,0 +1,13 @@ +using System; + +namespace LINGYUN.Abp.IM.Group +{ + public class UserGroup + { + 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 new file mode 100644 index 000000000..e5b51f37e --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/ChatMessage.cs @@ -0,0 +1,29 @@ +using System; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.IM.Messages +{ + public class ChatMessage + { + public Guid? TenantId { get; set; } + + public string GroupId { get; set; } + + public string MessageId { get; set; } + + public Guid FormUserId { 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/IMessageSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageSender.cs new file mode 100644 index 000000000..caea95cb9 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageSender.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.IM.Messages +{ + public interface IMessageSender + { + Task SendMessageAsync(ChatMessage chatMessage); + } +} 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 new file mode 100644 index 000000000..b8be51000 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/IMessageStore.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.IM.Messages +{ + public interface IMessageStore + { + /// + /// 存储聊天记录 + /// + /// + /// + /// + /// + Task StoreMessageAsync(ChatMessage chatMessage); + /// + /// 获取群组聊天记录 + /// + /// + /// + /// + /// + Task> GetGroupMessageAsync(Guid? tenantId, long groupId, string filter = "", MessageType type = MessageType.Text, int skipCount = 1, 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.IM/LINGYUN/Abp/IM/Messages/MessageType.cs b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/MessageType.cs new file mode 100644 index 000000000..eb9e6fb9f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/Messages/MessageType.cs @@ -0,0 +1,10 @@ +namespace LINGYUN.Abp.IM.Messages +{ + public enum MessageType + { + Text = 0, + Image = 10, + Link = 20, + Video = 30 + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN.Abp.Notifications.SignalR.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN.Abp.Notifications.SignalR.csproj new file mode 100644 index 000000000..1d4d15feb --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN.Abp.Notifications.SignalR.csproj @@ -0,0 +1,18 @@ + + + + netcoreapp3.1 + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs new file mode 100644 index 000000000..549f249f8 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/AbpNotificationsSignalRModule.cs @@ -0,0 +1,15 @@ +using LINGYUN.Abp.RealTime; +using Volo.Abp.AspNetCore.SignalR; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications.SignalR +{ + [DependsOn( + typeof(AbpRealTimeModule), + typeof(AbpNotificationModule), + typeof(AbpAspNetCoreSignalRModule))] + public class AbpNotificationsSignalRModule : AbpModule + { + + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs new file mode 100644 index 000000000..5cd3ab3f1 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/Hubs/NotificationsHub.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Users; + +namespace LINGYUN.Abp.Notifications.SignalR.Hubs +{ + [Authorize] + public class NotificationsHub : OnlineClientHubBase + { + private INotificationStore _notificationStore; + protected INotificationStore NotificationStore => LazyGetRequiredService(ref _notificationStore); + + [HubMethodName("GetNotification")] + public virtual async Task> GetNotificationAsync( + NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10) + { + var userNotifications = await NotificationStore.GetUserNotificationsAsync(CurrentTenant.Id, CurrentUser.GetId(), readState, maxResultCount); + + return new ListResultDto(userNotifications); + } + + [HubMethodName("ChangeState")] + public virtual async Task ChangeStateAsync(long id, NotificationReadState readState = NotificationReadState.Read) + { + await NotificationStore.ChangeUserNotificationReadStateAsync(CurrentTenant.Id, CurrentUser.GetId(), id, readState); + } + + + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs new file mode 100644 index 000000000..04c341cb6 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/OnlineClientHubBase.cs @@ -0,0 +1,78 @@ +using LINGYUN.Abp.RealTime.Client; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.SignalR; +using Volo.Abp.Security.Claims; + +namespace LINGYUN.Abp.Notifications.SignalR +{ + public abstract class OnlineClientHubBase : AbpHub + { + private ICurrentPrincipalAccessor _currentPrincipalAccessor; + protected ICurrentPrincipalAccessor CurrentPrincipalAccessor => LazyGetRequiredService(ref _currentPrincipalAccessor); + + private IOnlineClientManager _onlineClientManager; + protected IOnlineClientManager OnlineClientManager => LazyGetRequiredService(ref _onlineClientManager); + + private IHttpContextAccessor _httpContextAccessor; + protected IHttpContextAccessor HttpContextAccessor => LazyGetRequiredService(ref _httpContextAccessor); + + public override async Task OnConnectedAsync() + { + await base.OnConnectedAsync(); + IOnlineClient onlineClient = CreateClientForCurrentConnection(); + Logger.LogDebug("A client is connected: " + onlineClient.ToString()); + OnlineClientManager.Add(onlineClient); + } + + public override async Task OnDisconnectedAsync(Exception exception) + { + await base.OnDisconnectedAsync(exception); + Logger.LogDebug("A client is disconnected: " + Context.ConnectionId); + try + { + // 从通讯组移除 + var onlineClient = OnlineClientManager.GetByConnectionIdOrNull(Context.ConnectionId); + if(onlineClient != null) + { + // 移除在线客户端 + OnlineClientManager.Remove(Context.ConnectionId); + } + } + catch (Exception ex) + { + Logger.LogWarning(ex.ToString(), ex); + } + } + + protected virtual IOnlineClient CreateClientForCurrentConnection() + { + // abp框架没有处理,需要切换一下用户身份令牌.否则无法获取用户信息 + using (CurrentPrincipalAccessor.Change(Context.User)) + { + return new OnlineClient(Context.ConnectionId, GetClientIpAddress(), + CurrentTenant.Id, CurrentUser.Id) + { + ConnectTime = Clock.Now, + UserName = CurrentUser.UserName + }; + } + } + + protected virtual string GetClientIpAddress() + { + try + { + return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); + } + catch (Exception ex) + { + Logger.LogException(ex, LogLevel.Warning); + return null; + } + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs similarity index 55% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs rename to aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs index 98da317ef..8130a659e 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN/Abp/MessageService/SignalR/Notifications/SignalRNotificationPublisher.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/LINGYUN/Abp/Notifications/SignalR/SignalRNotificationPublisher.cs @@ -1,7 +1,5 @@ -using LINGYUN.Abp.IM; -using LINGYUN.Abp.MessageService.Notifications; -using LINGYUN.Abp.MessageService.SignalR.Hubs; -using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications.SignalR.Hubs; +using LINGYUN.Abp.RealTime.Client; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -10,19 +8,19 @@ using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -namespace LINGYUN.Abp.MessageService.SignalR.Notifications +namespace LINGYUN.Abp.Notifications.SignalR { - public class SignalRNotificationPublisher : INotificationPublisher, ITransientDependency + public class SignalRNotificationPublisher : INotificationPublisher, ISingletonDependency { public ILogger Logger { protected get; set; } private readonly IOnlineClientManager _onlineClientManager; - private readonly IHubContext _hubContext; + private readonly IHubContext _hubContext; public SignalRNotificationPublisher( - IOnlineClientManager onlineClientManager, - IHubContext hubContext) + IOnlineClientManager onlineClientManager, + IHubContext hubContext) { _hubContext = hubContext; _onlineClientManager = onlineClientManager; @@ -30,15 +28,15 @@ namespace LINGYUN.Abp.MessageService.SignalR.Notifications Logger = NullLogger.Instance; } - public async Task PublishAsync(NotificationData data, IEnumerable userIds, Guid? tenantId) + public async Task PublishAsync(NotificationInfo notification, IEnumerable userIds) { - try + foreach(var userId in userIds) { - foreach(var userId in userIds) + var onlineClientContext = new OnlineClientContext(notification.TenantId, userId); + var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); + foreach (var onlineClient in onlineClients) { - var onlineClientContext = new OnlineClientContext(userId, tenantId); - var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); - foreach (var onlineClient in onlineClients) + try { var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); if (signalRClient == null) @@ -46,15 +44,16 @@ namespace LINGYUN.Abp.MessageService.SignalR.Notifications Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); continue; } - await signalRClient.SendAsync("getNotification", data); + + await signalRClient.SendAsync("getNotification", notification); + } + catch (Exception ex) + { + Logger.LogWarning("Could not send notifications to user: {0}", userId); + Logger.LogWarning("Send to user notifications error: {0}", ex.Message); } } } - catch(Exception ex) - { - //Logger.LogWarning("Could not send notification to user: " + userId); - Logger.LogWarning(ex.ToString(), ex); - } } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/Microsoft/AspNetCore/Builder/SignalRJwtTokenMiddleware.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/Microsoft/AspNetCore/Builder/SignalRJwtTokenMiddleware.cs new file mode 100644 index 000000000..c35a6c34f --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications.SignalR/Microsoft/AspNetCore/Builder/SignalRJwtTokenMiddleware.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Microsoft.AspNetCore.Builder +{ + public class SignalRJwtTokenMiddleware : IMiddleware, ITransientDependency + { + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + // 仅针对自定义的SignalR hub + if (context.Request.Path.StartsWithSegments("/signalr-hubs/notifications")) + { + if (context.User.Identity?.IsAuthenticated != true) + { + if (context.Request.Query.TryGetValue("access_token", out var accessToken)) + { + context.Request.Headers.Add("Authorization", $"Bearer {accessToken}"); + } + + } + } + await next(context); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj index 268dae169..60d5efeb9 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN.Abp.Notifications.csproj @@ -6,7 +6,7 @@ - + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs new file mode 100644 index 000000000..ec8c315e2 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/AbpNotificationModule.cs @@ -0,0 +1,14 @@ +using LINGYUN.Abp.Notifications.Internal; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Notifications +{ + public class AbpNotificationModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs index 523856eea..1e8411eb9 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationPublisher.cs @@ -6,6 +6,6 @@ namespace LINGYUN.Abp.Notifications { public interface INotificationPublisher { - Task PublishAsync(NotificationData data, IEnumerable userIds, Guid? tenantId); + Task PublishAsync(NotificationInfo notification, IEnumerable userIds); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs deleted file mode 100644 index aed195b60..000000000 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationSender.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.Notifications -{ - public interface INotificationSender - { - Task SendAsync(NotificationData data, Guid userId, Guid? tenantId); - Task SendAsync(NotificationData data, IEnumerable userIds, Guid? tenantId); - } -} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs index e35c2a4aa..e7d0074e5 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/INotificationStore.cs @@ -8,6 +8,8 @@ namespace LINGYUN.Abp.Notifications { Task InsertUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); + Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable userIds, string notificationName); + Task DeleteUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName); Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName); @@ -22,10 +24,14 @@ namespace LINGYUN.Abp.Notifications Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId); + Task InsertUserNotificationsAsync(NotificationInfo notification, IEnumerable userIds); + Task DeleteUserNotificationAsync(Guid? tenantId, Guid userId, long notificationId); Task GetNotificationOrNullAsync(Guid? tenantId, long notificationId); - Task ChangeUserNotificationReadStateAsync(Guid? tenantId, Guid userId, string notificationName, NotificationReadState readState); + Task> GetUserNotificationsAsync(Guid? tenantId, Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10); + + Task ChangeUserNotificationReadStateAsync(Guid? tenantId, Guid userId, long notificationId, NotificationReadState readState); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs new file mode 100644 index 000000000..1e470ee39 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/LINGYUN/Abp/Notifications/Internal/DefaultNotificationDispatcher.cs @@ -0,0 +1,34 @@ +using System.Linq; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Notifications.Internal +{ + internal class DefaultNotificationDispatcher : INotificationDispatcher + { + private readonly INotificationStore _notificationStore; + private readonly INotificationPublisher _notificationPublisher; + public DefaultNotificationDispatcher( + INotificationStore notificationStore, + INotificationPublisher notificationPublisher) + { + _notificationStore = notificationStore; + _notificationPublisher = notificationPublisher; + } + + public async Task DispatcheAsync(NotificationInfo notification) + { + // 持久化通知 + await _notificationStore.InsertNotificationAsync(notification); + + // 获取用户订阅列表 + var userSubscriptions = await _notificationStore.GetSubscriptionsAsync(notification.TenantId, notification.Name); + + // 持久化用户通知 + var subscriptionUserIds = userSubscriptions.Select(us => us.UserId); + await _notificationStore.InsertUserNotificationsAsync(notification, subscriptionUserIds); + + // 发布用户通知 + await _notificationPublisher.PublishAsync(notification, subscriptionUserIds); + } + } +} 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 3f1826be9..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 @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; namespace LINGYUN.Abp.Notifications { @@ -6,8 +7,9 @@ namespace LINGYUN.Abp.Notifications { public Guid? TenantId { get; set; } public string Name { get; set; } + [JsonConverter(typeof(HexLongConverter))] + public long Id { get; set; } public NotificationData Data { get; set; } - public DateTime? ExpirationTime { get; set; } public DateTime CreationTime { get; set; } public NotificationType NotificationType { get; set; } public NotificationSeverity NotificationSeverity { get; set; } @@ -16,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/common/LINGYUN.Abp.Notifications/Newtonsoft/Json/HexLongConverter.cs b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/Newtonsoft/Json/HexLongConverter.cs new file mode 100644 index 000000000..e28c43cda --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.Notifications/Newtonsoft/Json/HexLongConverter.cs @@ -0,0 +1,30 @@ +using System; + +namespace Newtonsoft.Json +{ + public class HexLongConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + long v = value is ulong ? (long)(ulong)value : (long)value; + writer.WriteValue(v.ToString()); + } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string value = reader.Value as string; + long lValue = long.Parse(value); + return typeof(ulong) == objectType ? (object)(ulong)lValue : lValue; + } + public override bool CanConvert(Type objectType) + { + switch (objectType.FullName) + { + case "System.Int64": + case "System.UInt64": + return true; + default: + return false; + } + } + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN.Abp.RealTime.csproj b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN.Abp.RealTime.csproj new file mode 100644 index 000000000..268dae169 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN.Abp.RealTime.csproj @@ -0,0 +1,12 @@ + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/AbpRealTimeModule.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/AbpRealTimeModule.cs new file mode 100644 index 000000000..f4282a301 --- /dev/null +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/AbpRealTimeModule.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.RealTime +{ + public class AbpRealTimeModule : AbpModule + { + } +} diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClient.cs similarity index 77% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClient.cs index 9106ad1b3..00f465a89 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClient.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClient.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public interface IOnlineClient { @@ -13,7 +13,9 @@ namespace LINGYUN.Abp.IM Guid? UserId { get; } - string[] Roles { get; } + string UserAccount { get; } + + string UserName { get; } DateTime ConnectTime { get; } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientManager.cs similarity index 94% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientManager.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientManager.cs index 67008fc02..7f83b96bb 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientManager.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientManager.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public interface IOnlineClientManager { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientStore.cs similarity index 91% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientStore.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientStore.cs index ef7e704c8..9affcabbc 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/IOnlineClientStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/IOnlineClientStore.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public interface IOnlineClientStore { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/InMemoryOnlineClientStore.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/InMemoryOnlineClientStore.cs similarity index 97% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/InMemoryOnlineClientStore.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/InMemoryOnlineClientStore.cs index 5e93ddfd3..20b8de95c 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/InMemoryOnlineClientStore.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/InMemoryOnlineClientStore.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using Volo.Abp.DependencyInjection; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public class InMemoryOnlineClientStore : IOnlineClientStore, ISingletonDependency { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClient.cs similarity index 83% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClient.cs index 0771f485d..43dc48b1c 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClient.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClient.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { [Serializable] public class OnlineClient : IOnlineClient @@ -18,9 +18,10 @@ namespace LINGYUN.Abp.IM public Guid? TenantId { get; set; } - public Guid? UserId { get; set; } + public Guid? UserId { get; } + public string UserAccount { get; set; } - public string[] Roles { get; set; } + public string UserName { get; set; } public DateTime ConnectTime { get; set; } @@ -41,18 +42,16 @@ namespace LINGYUN.Abp.IM public OnlineClient() { - Roles = new string[0]; ConnectTime = DateTime.Now; } - public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId, params string[] roles) + public OnlineClient(string connectionId, string ipAddress, Guid? tenantId, Guid? userId) : this() { ConnectionId = connectionId; IpAddress = ipAddress; TenantId = tenantId; UserId = userId; - Roles = roles; Properties = new Dictionary(); } @@ -63,7 +62,7 @@ namespace LINGYUN.Abp.IM "-- ConnectionId:", ConnectionId, "-- Connection Time:", ConnectTime, "-- IpAddress:", IpAddress ?? "::1", - "-- UserId:", UserId.HasValue ? UserId.Value.ToString() : "None", + "-- UserName:", UserName, "-- TenantId:", TenantId.HasValue ? TenantId.Value.ToString() : "None"); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientContext.cs similarity index 69% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientContext.cs index e27877c3e..38ef6e05a 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientContext.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientContext.cs @@ -1,6 +1,6 @@ using System; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public class OnlineClientContext { @@ -8,10 +8,10 @@ namespace LINGYUN.Abp.IM public Guid UserId { get; } - public OnlineClientContext(Guid userId, Guid? tenantId) + public OnlineClientContext(Guid? tenantId, Guid userId) { - UserId = userId; TenantId = tenantId; + UserId = userId; } } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientEventArgs.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientEventArgs.cs similarity index 86% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientEventArgs.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientEventArgs.cs index a2e459529..dffdece95 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientEventArgs.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public class OnlineClientEventArgs : EventArgs { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientExtensions.cs similarity index 67% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientExtensions.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientExtensions.cs index 6dc956615..6f9acfb3f 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientExtensions.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientExtensions.cs @@ -1,6 +1,6 @@ using JetBrains.Annotations; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public static class OnlineClientExtensions { @@ -8,7 +8,7 @@ namespace LINGYUN.Abp.IM public static OnlineClientContext ToClientContextOrNull(this IOnlineClient onlineClient) { return onlineClient.UserId.HasValue - ? new OnlineClientContext(onlineClient.ConnectionId, onlineClient.UserId.Value, onlineClient.TenantId) + ? new OnlineClientContext(onlineClient.TenantId, onlineClient.UserId.Value) : null; } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManager.cs similarity index 93% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManager.cs index c82594930..e02405cf4 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManager.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManager.cs @@ -6,7 +6,7 @@ using System.Linq; using Volo.Abp; using Volo.Abp.DependencyInjection; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public class OnlineClientManager : IOnlineClientManager, ISingletonDependency { @@ -101,8 +101,7 @@ namespace LINGYUN.Abp.IM Check.NotNull(context, nameof(context)); return GetAllClients() - .Where(c => c.UserId == context.UserId && c.TenantId == context.TenantId) - .WhereIf(context.Roles.Length > 0, c => c.Roles.Any(role => context.Roles.Contains(role))) + .Where(c => c.TenantId == context.TenantId && c.UserId.Equals(context.UserId)) .ToImmutableList(); } } diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManagerExtensions.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManagerExtensions.cs similarity index 95% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManagerExtensions.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManagerExtensions.cs index 5a51135b5..ad69bb5cf 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineClientManagerExtensions.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineClientManagerExtensions.cs @@ -2,7 +2,7 @@ using System.Linq; using Volo.Abp; -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public static class OnlineClientManagerExtensions { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineUserEventArgs.cs b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineUserEventArgs.cs similarity index 87% rename from aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineUserEventArgs.cs rename to aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineUserEventArgs.cs index 4ce24f1a9..1c5708cb4 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.IM/LINGYUN/Abp/IM/OnlineUserEventArgs.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.RealTime/LINGYUN/Abp/RealTime/Client/OnlineUserEventArgs.cs @@ -1,4 +1,4 @@ -namespace LINGYUN.Abp.IM +namespace LINGYUN.Abp.RealTime.Client { public class OnlineUserEventArgs : OnlineClientEventArgs { diff --git a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs index 5ee48c601..36690094b 100644 --- a/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs +++ b/aspnet-core/modules/common/LINGYUN.Abp.Sms.Aliyun/LINYUN/Abp/Sms/Aliyun/AliyunSmsSender.cs @@ -115,7 +115,9 @@ namespace LINYUN.Abp.Sms.Aliyun { if (Environment.IsDevelopment()) { - Check.NotNullOrWhiteSpace(Options.DeveloperPhoneNumber, nameof(Options.DeveloperPhoneNumber)); + // check phone number length... + Check.NotNullOrWhiteSpace(Options.DeveloperPhoneNumber, nameof(Options.DeveloperPhoneNumber), + maxLength: 11, minLength: 11); request.AddQueryParameters("PhoneNumbers", Options.DeveloperPhoneNumber); } else 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.Domain.Shared.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj index 1cf822808..799cfdfd1 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN.Abp.MessageService.Domain.Shared.csproj @@ -6,7 +6,7 @@ - + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/MessageServiceResource.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/MessageServiceResource.cs new file mode 100644 index 000000000..6f918bea7 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Localization/MessageServiceResource.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.MessageService.Localization +{ + [LocalizationResourceName("MessageService")] + public class MessageServiceResource + { + } +} 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/MessageServiceSettingNames.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/MessageServiceSettingNames.cs new file mode 100644 index 000000000..0b4a121fe --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/MessageServiceSettingNames.cs @@ -0,0 +1,16 @@ +namespace LINGYUN.Abp.MessageService +{ + public class MessageServiceSettingNames + { + public const string GroupName = "Abp.MessageService"; + + public class Notifications + { + public const string Default = GroupName + ".Notifications"; + /// + /// 清理过期消息批次 + /// + public const string CleanupExpirationBatchCount = Default + ".CleanupExpirationBatchCount"; + } + } +} 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.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs new file mode 100644 index 000000000..03536e0da --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/Notifications/CleanupNotificationJobArgs.cs @@ -0,0 +1,16 @@ +using System; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class CleanupNotificationJobArgs + { + /// + /// 清理大小 + /// + public int Count { get; set; } + /// + /// 清理租户 + /// + public Guid? TenantId { get; set; } + } +} 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 64% 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 index 62b2da9d0..83de31bff 100644 --- 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 @@ -6,8 +6,6 @@ public const int MaxDataLength = 1024 * 1024; - public const int MaxTypeNameLength = 256; - - public const int MaxAssemblyQualifiedNameLength = 512; + public const int MaxTypeNameLength = 512; } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs deleted file mode 100644 index 0fe9e94df..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain.Shared/LINGYUN/Abp/MessageService/ReadStatus.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace LINGYUN.Abp.MessageService -{ - /// - /// 读取状态 - /// - public enum ReadStatus : sbyte - { - /// - /// 已读 - /// - Read = 0, - /// - /// 未读 - /// - UnRead = 10 - } -} 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 76% 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 index ad3011801..d7a583b55 100644 --- 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 @@ -3,7 +3,5 @@ public class SubscribeConsts { public const int MaxNotificationNameLength = 100; - - public const int MaxRoleNameLength = 64; } } 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 cb3747869..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,11 +5,25 @@ + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDbProperties.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDbProperties.cs new file mode 100644 index 000000000..6a87fed45 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDbProperties.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.MessageService +{ + public class AbpMessageServiceDbProperties + { + public const string DefaultTablePrefix = "App"; + + public const string DefaultSchema = null; + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs index 78da839db..b48c045fd 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/AbpMessageServiceDomainModule.cs @@ -1,9 +1,18 @@ -using Volo.Abp.Modularity; +using LINGYUN.Abp.MessageService.Mapper; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; namespace LINGYUN.Abp.MessageService { + [DependsOn(typeof(AbpAutoMapperModule))] public class AbpMessageServiceDomainModule : AbpModule { - + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.AddProfile(validate: true); + }); + } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs new file mode 100644 index 000000000..7a342922e --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/BackgroundJobs/NotificationExpritionCleanupJob.cs @@ -0,0 +1,37 @@ +using LINGYUN.Abp.MessageService.Notifications; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.BackgroundJobs +{ + public class NotificationExpritionCleanupJob : AsyncBackgroundJob + { + private readonly ICurrentTenant _currentTenant; + private readonly IUnitOfWorkManager _unitOfWorkManager; + private readonly INotificationRepository _notificationRepository; + public NotificationExpritionCleanupJob( + ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, + INotificationRepository notificationRepository) + { + _currentTenant = currentTenant; + _unitOfWorkManager = unitOfWorkManager; + _notificationRepository = notificationRepository; + } + + public override async Task ExecuteAsync(CleanupNotificationJobArgs args) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (_currentTenant.Change(args.TenantId)) + { + await _notificationRepository.DeleteExpritionAsync(args.Count); + + await unitOfWork.SaveChangesAsync(); + } + } + } + } +} 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 new file mode 100644 index 000000000..631b50e39 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Mapper/MessageServiceDomainAutoMapperProfile.cs @@ -0,0 +1,57 @@ +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; + +namespace LINGYUN.Abp.MessageService.Mapper +{ + public class MessageServiceDomainAutoMapperProfile : Profile + { + public MessageServiceDomainAutoMapperProfile() + { + CreateMap() + .ForMember(dto => dto.Id, map => map.MapFrom(src => src.NotificationId)) + .ForMember(dto => dto.Name, map => map.MapFrom(src => src.NotificationName)) + .ForMember(dto => dto.NotificationType, map => map.MapFrom(src => src.Type)) + .ForMember(dto => dto.NotificationSeverity, map => map.MapFrom(src => src.Severity)) + .ForMember(dto => dto.Data, map => map.MapFrom((src, nfi) => + { + var notificationDataType = Type.GetType(src.NotificationTypeName); + var notificationData = JsonConvert.DeserializeObject(src.NotificationData, notificationDataType); + if(notificationData != null) + { + return notificationData as NotificationData; + } + return new NotificationData(); + })); + + 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 995e5a29a..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Messages/ChatMessage.cs +++ /dev/null @@ -1,34 +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; } - /// - /// 阅读状态 - /// - public virtual ReadStatus ReadStatus { 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.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationRepository.cs new file mode 100644 index 000000000..dc91fff44 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationRepository.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public interface INotificationRepository : IBasicRepository + { + Task GetByIdAsync(long notificationId); + + Task DeleteExpritionAsync(int batchCount); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs deleted file mode 100644 index 3d6ae41b6..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/INotificationStore.cs +++ /dev/null @@ -1,11 +0,0 @@ -using LINGYUN.Abp.Notifications; -using System; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.MessageService.Notifications -{ - public interface INotificationStore - { - Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId); - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs new file mode 100644 index 000000000..73f7bf28a --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/IUserNotificationRepository.cs @@ -0,0 +1,19 @@ +using LINGYUN.Abp.Notifications; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public interface IUserNotificationRepository : IBasicRepository + { + Task InsertUserNotificationsAsync(IEnumerable userNotifications); + + Task GetByIdAsync(Guid userId, long notificationId); + + Task> GetNotificationsAsync(Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10); + + Task ChangeUserNotificationReadStateAsync(Guid userId, long notificationId, NotificationReadState readState); + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs index 911511771..329ae9140 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/Notification.cs @@ -10,6 +10,7 @@ namespace LINGYUN.Abp.MessageService.Notifications { public virtual Guid? TenantId { get; protected set; } public virtual NotificationSeverity Severity { get; protected set; } + public virtual NotificationType Type { get; set; } public virtual long NotificationId { get; protected set; } public virtual string NotificationName { get; protected set; } public virtual string NotificationData { get; protected set; } @@ -24,7 +25,12 @@ namespace LINGYUN.Abp.MessageService.Notifications NotificationName = name; NotificationData = data; NotificationTypeName = dataType; - CreationTime = DateTime.Now; + Type = NotificationType.Application; + } + + public void SetTenantId(Guid? tenantId) + { + TenantId = tenantId; } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs index df76ef4af..a24a3dae8 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationDispatcher.cs @@ -1,47 +1,40 @@ -using LINGYUN.Abp.MessageService.Subscriptions; -using LINGYUN.Abp.MessageService.Utils; -using LINGYUN.Abp.Notifications; +using LINGYUN.Abp.Notifications; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; -using Volo.Abp.Json; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; namespace LINGYUN.Abp.MessageService.Notifications { public class NotificationDispatcher : INotificationDispatcher, ITransientDependency { - protected IJsonSerializer JsonSerializer { get; } - protected ICurrentTenant CurrentTenant { get; } - protected ISubscribeStore SubscribeStore { get; } protected INotificationStore NotificationStore { get; } - protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager.Current; - protected IUnitOfWorkManager UnitOfWorkManager { get; } protected INotificationPublisher NotificationPublisher { get; } - protected ISnowflakeIdGenerator SnowflakeIdGenerator { get; } + public NotificationDispatcher( + INotificationStore notificationStore, + INotificationPublisher notificationPublisher) + { + NotificationStore = notificationStore; + NotificationPublisher = notificationPublisher; + } - [UnitOfWork] public virtual async Task DispatcheAsync(NotificationInfo notification) { - using (CurrentTenant.Change(notification.TenantId)) + var subscribes = await NotificationStore.GetSubscriptionsAsync(notification.TenantId, notification.Name); + foreach (var subscribe in subscribes) { - var subscribeUsers = await SubscribeStore.GetUserSubscribesAsync(notification.Name); - foreach(var userId in subscribeUsers) - { - await NotificationStore.InsertUserNotificationAsync(notification, userId); - } - await CurrentUnitOfWork.SaveChangesAsync(); - - await NotifyAsync(notification.Data, notification.TenantId, subscribeUsers); + await NotificationStore.InsertUserNotificationAsync(notification, subscribe.UserId); } + + var subscribeUsers = subscribes.Select(s => s.UserId); + await NotifyAsync(notification, subscribeUsers); } - protected virtual async Task NotifyAsync(NotificationData data, Guid? tenantId, IEnumerable userIds) + protected virtual async Task NotifyAsync(NotificationInfo notification, IEnumerable userIds) { - await NotificationPublisher.PublishAsync(data, userIds, tenantId); + await NotificationPublisher.PublishAsync(notification, userIds); } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs new file mode 100644 index 000000000..d0130281e --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/NotificationStore.cs @@ -0,0 +1,254 @@ +using LINGYUN.Abp.MessageService.Subscriptions; +using LINGYUN.Abp.MessageService.Utils; +using LINGYUN.Abp.Notifications; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Services; +using Volo.Abp.Json; +using Volo.Abp.ObjectMapping; +using Volo.Abp.Uow; + +namespace LINGYUN.Abp.MessageService.Notifications +{ + public class NotificationStore : DomainService, INotificationStore + { + private readonly IObjectMapper _objectMapper; + private readonly IUnitOfWorkManager _unitOfWorkManager; + + private IJsonSerializer _jsonSerializer; + protected IJsonSerializer JsonSerializer => LazyGetRequiredService(ref _jsonSerializer); + + private ISnowflakeIdGenerator _snowflakeIdGenerator; + protected ISnowflakeIdGenerator SnowflakeIdGenerator => LazyGetRequiredService(ref _snowflakeIdGenerator); + + private INotificationRepository _notificationRepository; + protected INotificationRepository NotificationRepository => LazyGetRequiredService(ref _notificationRepository); + + private IUserNotificationRepository _userNotificationRepository; + protected IUserNotificationRepository UserNotificationRepository => LazyGetRequiredService(ref _userNotificationRepository); + + private IUserSubscribeRepository _userSubscribeRepository; + protected IUserSubscribeRepository UserSubscribeRepository => LazyGetRequiredService(ref _userSubscribeRepository); + + public NotificationStore( + IObjectMapper objectMapper, + IUnitOfWorkManager unitOfWorkManager) + { + _objectMapper = objectMapper; + _unitOfWorkManager = unitOfWorkManager; + } + + [UnitOfWork] + public async Task ChangeUserNotificationReadStateAsync(Guid? tenantId, Guid userId, long notificationId, NotificationReadState readState) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + await UserNotificationRepository.ChangeUserNotificationReadStateAsync(userId, notificationId, readState); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task DeleteNotificationAsync(NotificationInfo notification) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(notification.TenantId)) + { + var notify = await NotificationRepository.GetByIdAsync(notification.Id); + await NotificationRepository.DeleteAsync(notify.Id); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task DeleteUserNotificationAsync(Guid? tenantId, Guid userId, long notificationId) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + var notify = await UserNotificationRepository.GetByIdAsync(userId, notificationId); + await UserNotificationRepository.DeleteAsync(notify.Id); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task DeleteUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + var userSubscribe = await UserSubscribeRepository.GetUserSubscribeAsync(notificationName, userId); + await UserSubscribeRepository.DeleteAsync(userSubscribe.Id); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + public async Task GetNotificationOrNullAsync(Guid? tenantId, long notificationId) + { + using (CurrentTenant.Change(tenantId)) + { + var notification = await NotificationRepository.GetByIdAsync(notificationId); + + return _objectMapper.Map(notification); + } + } + + public async Task> GetSubscriptionsAsync(Guid? tenantId, string notificationName) + { + using (CurrentTenant.Change(tenantId)) + { + var userSubscriptions = await UserSubscribeRepository.GetSubscribesAsync(notificationName); + + return _objectMapper.Map, List>(userSubscriptions); + } + } + + public async Task> GetUserNotificationsAsync(Guid? tenantId, Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10) + { + using (CurrentTenant.Change(tenantId)) + { + var notifications = await UserNotificationRepository.GetNotificationsAsync(userId, readState, maxResultCount); + + return _objectMapper.Map, List>(notifications); + } + } + + public async Task> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId) + { + using (CurrentTenant.Change(tenantId)) + { + var userSubscriptionNames = await UserSubscribeRepository.GetUserSubscribesAsync(userId); + + var userSubscriptions = new List(); + + userSubscriptionNames.ForEach(name => userSubscriptions.Add( + new NotificationSubscriptionInfo + { + UserId = userId, + TenantId = tenantId, + NotificationName = name + })); + + return userSubscriptions; + } + } + + [UnitOfWork] + public async Task InsertNotificationAsync(NotificationInfo notification) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(notification.TenantId)) + { + var notifyId = SnowflakeIdGenerator.Create(); + // 保存主键,防止前端js long类型溢出 + notification.Data["id"] = notifyId.ToString(); + + var notify = new Notification(notifyId, notification.Name, + notification.Data.GetType().AssemblyQualifiedName, + JsonSerializer.Serialize(notification.Data), notification.NotificationSeverity) + { + CreationTime = Clock.Now, + Type = notification.NotificationType, + ExpirationTime = Clock.Now.AddDays(60) + }; + notify.SetTenantId(notification.TenantId); + + await NotificationRepository.InsertAsync(notify); + + notification.Id = notify.NotificationId; + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task InsertUserNotificationAsync(NotificationInfo notification, Guid userId) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(notification.TenantId)) + { + var userNotification = new UserNotification(notification.Id, userId); + await UserNotificationRepository.InsertAsync(userNotification); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task InsertUserSubscriptionAsync(Guid? tenantId, Guid userId, string notificationName) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + + var userSubscription = new UserSubscribe(notificationName, userId) + { + CreationTime = Clock.Now + }; + + await UserSubscribeRepository.InsertAsync(userSubscription); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + [UnitOfWork] + public async Task InsertUserSubscriptionAsync(Guid? tenantId, IEnumerable userIds, string notificationName) + { + using (var unitOfWork = _unitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(tenantId)) + { + var userSubscribes = new List(); + + foreach(var userId in userIds) + { + userSubscribes.Add(new UserSubscribe(notificationName, userId)); + } + + await UserSubscribeRepository.InsertUserSubscriptionAsync(userSubscribes); + + await unitOfWork.SaveChangesAsync(); + } + } + } + + public async Task IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName) + { + using (CurrentTenant.Change(tenantId)) + return await UserSubscribeRepository.UserSubscribeExistsAysnc(notificationName, userId); + } + + public async Task InsertUserNotificationsAsync(NotificationInfo notification, IEnumerable userIds) + { + var userNofitications = new List(); + foreach(var userId in userIds) + { + var userNofitication = new UserNotification(notification.Id, userId); + userNofitications.Add(userNofitication); + } + await UserNotificationRepository.InsertUserNotificationsAsync(userNofitications); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs index 76741a1b7..2099b4d06 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Notifications/UserNotification.cs @@ -1,4 +1,5 @@ -using System; +using LINGYUN.Abp.Notifications; +using System; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; @@ -9,12 +10,18 @@ namespace LINGYUN.Abp.MessageService.Notifications public virtual Guid? TenantId { get; protected set; } public virtual Guid UserId { get; protected set; } public virtual long NotificationId { get; protected set; } - public virtual ReadStatus ReadStatus { get; protected set; } + public virtual NotificationReadState ReadStatus { get; protected set; } protected UserNotification() { } public UserNotification(long notificationId, Guid userId) { UserId = userId; NotificationId = notificationId; + ReadStatus = NotificationReadState.UnRead; + } + + public void ChangeReadState(NotificationReadState readStatus) + { + ReadStatus = readStatus; } } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs deleted file mode 100644 index b3a7fef01..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeStore.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace LINGYUN.Abp.MessageService.Subscriptions -{ - public interface ISubscribeStore - { - Task> GetUserSubscribesAsync(string notificationName); - Task UserSubscribeAsync(string notificationName, Guid userId); - Task UserUnSubscribeAsync(string notificationName, Guid userId); - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs similarity index 66% rename from aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs rename to aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs index 13c264548..0615db628 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/ISubscribeRepository.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/IUserSubscribeRepository.cs @@ -5,14 +5,18 @@ using Volo.Abp.Domain.Repositories; namespace LINGYUN.Abp.MessageService.Subscriptions { - public interface ISubscribeRepository : IBasicRepository + public interface IUserSubscribeRepository : IBasicRepository { Task UserSubscribeExistsAysnc(string notificationName, Guid userId); Task GetUserSubscribeAsync(string notificationName, Guid userId); + Task> GetSubscribesAsync(string notificationName); + Task> GetUserSubscribesAsync(Guid userId); Task> GetUserSubscribesAsync(string notificationName); + + Task InsertUserSubscriptionAsync(IEnumerable userSubscribes); } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs deleted file mode 100644 index 23f052e20..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/RoleSubscribe.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Volo.Abp.Auditing; - -namespace LINGYUN.Abp.MessageService.Subscriptions -{ - public class RoleSubscribe : Subscribe, IHasCreationTime - { - public virtual string RoleName { get; set; } - public virtual DateTime CreationTime { get; set; } - protected RoleSubscribe() { } - public RoleSubscribe(string notificationName, string roleName) : base(notificationName) - { - RoleName = roleName; - CreationTime = DateTime.Now; - } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs index 2fdc1306d..4fb6dbc1e 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/Subscribe.cs @@ -1,12 +1,14 @@ using System; +using Volo.Abp.Auditing; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; namespace LINGYUN.Abp.MessageService.Subscriptions { - public abstract class Subscribe : Entity, IMultiTenant + public abstract class Subscribe : Entity, IMultiTenant, IHasCreationTime { public virtual Guid? TenantId { get; protected set; } + public virtual DateTime CreationTime { get; set; } public virtual string NotificationName { get; protected set; } protected Subscribe() { } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs deleted file mode 100644 index cefc653f6..000000000 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/SubscribeStore.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; - -namespace LINGYUN.Abp.MessageService.Subscriptions -{ - public class SubscribeStore : ISubscribeStore, ITransientDependency - { - protected ISubscribeRepository SubscribeRepository { get; } - - public SubscribeStore(ISubscribeRepository subscribeRepository) - { - SubscribeRepository = subscribeRepository; - } - - public virtual async Task> GetUserSubscribesAsync(string notificationName) - { - return await SubscribeRepository.GetUserSubscribesAsync(notificationName); - } - - public virtual async Task UserSubscribeAsync(string notificationName, Guid userId) - { - var userSubscribeExists = await SubscribeRepository.UserSubscribeExistsAysnc(notificationName, userId); - if (!userSubscribeExists) - { - var userSbuscribe = new UserSubscribe(notificationName, userId); - await SubscribeRepository.InsertAsync(userSbuscribe); - } - } - - public virtual async Task UserUnSubscribeAsync(string notificationName, Guid userId) - { - var userSubscribe = await SubscribeRepository.GetUserSubscribeAsync(notificationName, userId); - if (userSubscribe != null) - { - await SubscribeRepository.DeleteAsync(userSubscribe); - } - } - } -} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs index a3012dd17..5c5f03c4c 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Subscriptions/UserSubscribe.cs @@ -5,12 +5,10 @@ namespace LINGYUN.Abp.MessageService.Subscriptions { public class UserSubscribe : Subscribe, IHasCreationTime { - public virtual DateTime CreationTime { get; set; } public virtual Guid UserId { get; set; } protected UserSubscribe() { } public UserSubscribe(string notificationName, Guid userId) : base(notificationName) { - CreationTime = DateTime.Now; UserId = userId; } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs index 22609c5e0..310f419de 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.Domain/LINGYUN/Abp/MessageService/Utils/ISnowflakeIdGenerator.cs @@ -2,6 +2,6 @@ { public interface ISnowflakeIdGenerator { - long NextId(); + long Create(); } } diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj new file mode 100644 index 000000000..3ce788c0a --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + 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 new file mode 100644 index 000000000..aee1cc373 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/AbpMessageServiceEntityFrameworkCoreModule.cs @@ -0,0 +1,31 @@ +using LINGYUN.Abp.MessageService.Messages; +using LINGYUN.Abp.MessageService.Notifications; +using LINGYUN.Abp.MessageService.Subscriptions; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + [DependsOn( + typeof(AbpMessageServiceDomainModule), + typeof(AbpEntityFrameworkCoreModule))] + public class AbpMessageServiceEntityFrameworkCoreModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddRepository(); + 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/MessageServiceDbContext.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContext.cs new file mode 100644 index 000000000..4f7fbb22d --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContext.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + [ConnectionStringName("MessageService")] + public class MessageServiceDbContext : AbpDbContext + { + public MessageServiceDbContext(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ConfigureMessageService(options => + { + options.TablePrefix = AbpMessageServiceDbProperties.DefaultTablePrefix; + options.Schema = AbpMessageServiceDbProperties.DefaultSchema; + }); + + base.OnModelCreating(modelBuilder); + } + } +} 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 new file mode 100644 index 000000000..71e42ab07 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceDbContextModelCreatingExtensions.cs @@ -0,0 +1,160 @@ +using LINGYUN.Abp.MessageService.Messages; +using LINGYUN.Abp.MessageService.Notifications; +using LINGYUN.Abp.MessageService.Subscriptions; +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + public static class MessageServiceDbContextModelCreatingExtensions + { + public static void ConfigureMessageService( + this ModelBuilder builder, + Action optionsAction = null) + { + Check.NotNull(builder, nameof(builder)); + + var options = new MessageServiceModelBuilderConfigurationOptions(); + + optionsAction?.Invoke(options); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "Notifications", options.Schema); + + b.Property(p => p.NotificationName).HasMaxLength(NotificationConsts.MaxNameLength).IsRequired(); + b.Property(p => p.NotificationTypeName).HasMaxLength(NotificationConsts.MaxTypeNameLength).IsRequired(); + b.Property(p => p.NotificationData).HasMaxLength(NotificationConsts.MaxDataLength).IsRequired(); + + b.ConfigureMultiTenant(); + b.ConfigureCreationTime(); + + b.HasIndex(p => p.NotificationName); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserNotifications", options.Schema); + + b.ConfigureMultiTenant(); + + b.HasIndex(p => new { p.TenantId, p.UserId, p.NotificationId }) + .HasName("IX_Tenant_User_Notification_Id"); + }); + + builder.Entity(b => + { + b.ToTable(options.TablePrefix + "UserSubscribes", options.Schema); + + b.Property(p => p.NotificationName).HasMaxLength(SubscribeConsts.MaxNotificationNameLength).IsRequired(); + + b.ConfigureCreationTime(); + 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/EntityFrameworkCore/MessageServiceModelBuilderConfigurationOptions.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceModelBuilderConfigurationOptions.cs new file mode 100644 index 000000000..049ae7d54 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/EntityFrameworkCore/MessageServiceModelBuilderConfigurationOptions.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace LINGYUN.Abp.MessageService.EntityFrameworkCore +{ + public class MessageServiceModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions + { + public MessageServiceModelBuilderConfigurationOptions( + [NotNull] string tablePrefix = AbpMessageServiceDbProperties.DefaultTablePrefix, + [CanBeNull] string schema = AbpMessageServiceDbProperties.DefaultSchema) + : base( + tablePrefix, + schema) + { + + } + } +} 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/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreNotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreNotificationRepository.cs new file mode 100644 index 000000000..f6fd96e39 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreNotificationRepository.cs @@ -0,0 +1,36 @@ +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.Notifications +{ + public class EfCoreNotificationRepository : EfCoreRepository, + INotificationRepository, ITransientDependency + { + public EfCoreNotificationRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task DeleteExpritionAsync(int batchCount) + { + var notifications = await DbSet + .Where(x => x.ExpirationTime <= DateTime.Now) + .Take(batchCount) + .ToArrayAsync(); + + DbSet.RemoveRange(notifications); + } + + public async Task GetByIdAsync(long notificationId) + { + return await DbSet.Where(x => x.NotificationId.Equals(notificationId)).FirstOrDefaultAsync(); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs new file mode 100644 index 000000000..96d4f55e7 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Notifications/EfCoreUserNotificationRepository.cs @@ -0,0 +1,58 @@ +using LINGYUN.Abp.MessageService.EntityFrameworkCore; +using LINGYUN.Abp.Notifications; +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.Notifications +{ + public class EfCoreUserNotificationRepository : EfCoreRepository, + IUserNotificationRepository, ITransientDependency + { + public EfCoreUserNotificationRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task InsertUserNotificationsAsync(IEnumerable userNotifications) + { + await DbSet.AddRangeAsync(userNotifications); + } + + public async Task ChangeUserNotificationReadStateAsync(Guid userId, long notificationId, NotificationReadState readState) + { + var userNofitication = await GetByIdAsync(userId, notificationId); + userNofitication.ChangeReadState(readState); + + DbSet.Update(userNofitication); + } + + public async Task GetByIdAsync(Guid userId, long notificationId) + { + var userNofitication = await DbSet + .Where(x => x.NotificationId.Equals(notificationId) && x.UserId.Equals(userId)) + .FirstOrDefaultAsync(); + + return userNofitication; + } + + public async Task> GetNotificationsAsync(Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10) + { + + var userNofitications = await (from un in DbContext.Set() + join n in DbContext.Set() + on un.NotificationId equals n.NotificationId + where un.UserId.Equals(userId) && un.ReadStatus.Equals(readState) + select n) + .Take(maxResultCount) + .ToListAsync(); + return userNofitications; + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs new file mode 100644 index 000000000..898701772 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.EntityFrameworkCore/LINGYUN/Abp/MessageService/Subscriptions/EfCoreUserSubscribeRepository.cs @@ -0,0 +1,68 @@ +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.Subscriptions +{ + public class EfCoreUserSubscribeRepository : EfCoreRepository, + IUserSubscribeRepository, ITransientDependency + { + public EfCoreUserSubscribeRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } + + public async Task> GetSubscribesAsync(string notificationName) + { + var userSubscribes = await DbSet.Where(x => x.NotificationName.Equals(notificationName)).ToListAsync(); + + return userSubscribes; + } + + public async Task GetUserSubscribeAsync(string notificationName, Guid userId) + { + var userSubscribe = await DbSet + .Where(x => x.UserId.Equals(userId) && x.NotificationName.Equals(notificationName)) + .FirstOrDefaultAsync(); + + return userSubscribe; + } + + public async Task> GetUserSubscribesAsync(Guid userId) + { + var userSubscribeNames = await DbSet + .Where(x => x.UserId.Equals(userId)) + .Select(x => x.NotificationName) + .ToListAsync(); + + return userSubscribeNames; + } + + public async Task> GetUserSubscribesAsync(string notificationName) + { + var subscribeUsers = await DbSet + .Where(x => x.NotificationName.Equals(notificationName)) + .Select(x => x.UserId) + .ToListAsync(); + + return subscribeUsers; + } + + public async Task InsertUserSubscriptionAsync(IEnumerable userSubscribes) + { + await DbSet.AddRangeAsync(userSubscribes); + } + + public async Task UserSubscribeExistsAysnc(string notificationName, Guid userId) + { + return await DbSet.AnyAsync(x => x.UserId.Equals(userId) && x.NotificationName.Equals(notificationName)); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN.Abp.MessageService.HttpApi.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN.Abp.MessageService.HttpApi.csproj new file mode 100644 index 000000000..fd6a1743a --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN.Abp.MessageService.HttpApi.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp3.1 + + + + + + + + diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiModule.cs b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiModule.cs new file mode 100644 index 000000000..ec2306605 --- /dev/null +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.HttpApi/LINGYUN/Abp/MessageService/AbpMessageServiceHttpApiModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.MessageService +{ + [DependsOn( + typeof(AbpAspNetCoreMvcModule) + )] + public class AbpMessageServiceHttpApiModule : AbpModule + { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpMessageServiceHttpApiModule).Assembly); + }); + } + } +} diff --git a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj index d014cb2da..ea1854834 100644 --- a/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj +++ b/aspnet-core/modules/message/LINGYUN.Abp.MessageService.SignalR/LINGYUN.Abp.MessageService.SignalR.csproj @@ -10,4 +10,8 @@ + + + + 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/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs index 5a5666258..8eb8eae72 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs @@ -67,6 +67,8 @@ namespace LINGYUN.ApiGateway var env = context.GetEnvironment(); app.UseAuditing(); + // 启用ws协议 + app.UseWebSockets(); app.UseOcelot().Wait(); } diff --git a/vueJs/.env.development b/vueJs/.env.development index 00f064f35..18653b2fa 100644 --- a/vueJs/.env.development +++ b/vueJs/.env.development @@ -3,6 +3,8 @@ VUE_APP_BASE_MOCK_API = '/dev-api' VUE_APP_BASE_API = '/api' +#Signalr +VUE_APP_SIGNALR_SERVER = '/signalr-hubs' VUE_APP_BASE_IDENTITY_SERVICE = '/api/identity' 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/package-lock.json b/vueJs/package-lock.json index 76d0c5e14..cabe035e0 100644 --- a/vueJs/package-lock.json +++ b/vueJs/package-lock.json @@ -1989,6 +1989,26 @@ } } }, + "@microsoft/signalr": { + "version": "3.1.4", + "resolved": "https://registry.npm.taobao.org/@microsoft/signalr/download/@microsoft/signalr-3.1.4.tgz", + "integrity": "sha1-EILSBjvi0E1LRpnGovsXIyEn/0M=", + "requires": { + "eventsource": "^1.0.7", + "request": "^2.88.0", + "ws": "^6.0.0" + }, + "dependencies": { + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npm.taobao.org/ws/download/ws-6.2.1.tgz?cache=0&sync_timestamp=1589091396925&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fws%2Fdownload%2Fws-6.2.1.tgz", + "integrity": "sha1-RC/fCkftZPWbal2P8TD0dI7VJPs=", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npm.taobao.org/@mrmlnc/readdir-enhanced/download/@mrmlnc/readdir-enhanced-2.2.1.tgz", @@ -3830,7 +3850,6 @@ "version": "6.12.2", "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.2.tgz?cache=0&sync_timestamp=1587338460514&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.2.tgz", "integrity": "sha1-xinF7O0XuvMUQ3kY0tqIyZ1ZWM0=", - "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4030,7 +4049,6 @@ "version": "0.2.4", "resolved": "https://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz", "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -4076,8 +4094,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", @@ -4105,8 +4122,7 @@ "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.1.tgz?cache=0&sync_timestamp=1574271725892&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync-limiter%2Fdownload%2Fasync-limiter-1.0.1.tgz", - "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=", - "dev": true + "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=" }, "async-validator": { "version": "1.8.5", @@ -4119,8 +4135,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.2", @@ -4168,14 +4183,12 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.9.1", "resolved": "https://registry.npm.taobao.org/aws4/download/aws4-1.9.1.tgz", - "integrity": "sha1-fjPY99RJs/ZzzXLeuavcVS2+Uo4=", - "dev": true + "integrity": "sha1-fjPY99RJs/ZzzXLeuavcVS2+Uo4=" }, "axios": { "version": "0.19.2", @@ -4631,7 +4644,6 @@ "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "requires": { "tweetnacl": "^0.14.3" } @@ -5218,8 +5230,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "cfb": { "version": "1.1.4", @@ -5845,7 +5856,6 @@ "version": "1.0.8", "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -6848,7 +6858,6 @@ "version": "1.14.1", "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -7175,8 +7184,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegate": { "version": "3.2.0", @@ -7438,7 +7446,6 @@ "version": "0.1.2", "resolved": "https://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -8354,7 +8361,6 @@ "version": "1.0.7", "resolved": "https://registry.npm.taobao.org/eventsource/download/eventsource-1.0.7.tgz", "integrity": "sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=", - "dev": true, "requires": { "original": "^1.0.0" } @@ -8588,8 +8594,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=", - "dev": true + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" }, "extend-shallow": { "version": "3.0.2", @@ -8758,8 +8763,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "faker": { "version": "4.1.0", @@ -8769,8 +8773,7 @@ "fast-deep-equal": { "version": "3.1.1", "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.1.tgz", - "integrity": "sha1-VFFFB3xQFJHjOxXsQIwpQ3bpSuQ=", - "dev": true + "integrity": "sha1-VFFFB3xQFJHjOxXsQIwpQ3bpSuQ=" }, "fast-glob": { "version": "2.2.7", @@ -8789,8 +8792,7 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", - "dev": true + "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=" }, "fast-levenshtein": { "version": "2.0.6", @@ -9041,8 +9043,7 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "fork-ts-checker-webpack-plugin": { "version": "3.1.1", @@ -9185,7 +9186,6 @@ "version": "2.3.3", "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz", "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -9970,7 +9970,6 @@ "version": "0.1.7", "resolved": "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -10085,14 +10084,12 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npm.taobao.org/har-validator/download/har-validator-5.1.3.tgz", "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", - "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -10458,7 +10455,6 @@ "version": "1.2.0", "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -11147,8 +11143,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-utf8": { "version": "0.2.1", @@ -11193,8 +11188,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { "version": "2.0.5", @@ -14375,8 +14369,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { "version": "11.12.0", @@ -14435,14 +14428,12 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz?cache=0&sync_timestamp=1567740732347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema%2Fdownload%2Fjson-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" }, "json-stable-stringify": { "version": "1.0.1", @@ -14462,8 +14453,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json3": { "version": "3.3.3", @@ -14508,7 +14498,6 @@ "version": "1.4.1", "resolved": "https://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -16207,14 +16196,12 @@ "mime-db": { "version": "1.44.0", "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz", - "integrity": "sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I=", - "dev": true + "integrity": "sha1-+hHF6wrKEzS0Izy01S8QxaYnL5I=" }, "mime-types": { "version": "2.1.27", "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.27.tgz?cache=0&sync_timestamp=1587700357177&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.27.tgz", "integrity": "sha1-R5SfmOJ56lMRn1ci4PNOUpvsAJ8=", - "dev": true, "requires": { "mime-db": "1.44.0" } @@ -16720,8 +16707,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=", - "dev": true + "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=" }, "object-assign": { "version": "4.1.1", @@ -16962,7 +16948,6 @@ "version": "1.0.2", "resolved": "https://registry.npm.taobao.org/original/download/original-1.0.2.tgz", "integrity": "sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=", - "dev": true, "requires": { "url-parse": "^1.4.3" } @@ -17258,8 +17243,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { "version": "2.2.2", @@ -18223,8 +18207,7 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", - "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=", - "dev": true + "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ=" }, "public-encrypt": { "version": "4.0.3", @@ -18275,8 +18258,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" }, "q": { "version": "1.5.1", @@ -18286,8 +18268,7 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz?cache=0&sync_timestamp=1585168614364&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", - "dev": true + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" }, "query-string": { "version": "4.3.4", @@ -18314,8 +18295,7 @@ "querystringify": { "version": "2.1.1", "resolved": "https://registry.npm.taobao.org/querystringify/download/querystringify-2.1.1.tgz", - "integrity": "sha1-YOWl/WSn+L+k0qsu1v30yFutFU4=", - "dev": true + "integrity": "sha1-YOWl/WSn+L+k0qsu1v30yFutFU4=" }, "ramda": { "version": "0.24.1", @@ -18661,7 +18641,6 @@ "version": "2.88.2", "resolved": "https://registry.npm.taobao.org/request/download/request-2.88.2.tgz?cache=0&sync_timestamp=1581439006948&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frequest%2Fdownload%2Frequest-2.88.2.tgz", "integrity": "sha1-1zyRhzHLWofaBH4gcjQUb2ZNErM=", - "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -18727,8 +18706,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, "resize-observer-polyfill": { "version": "1.5.1", @@ -18863,8 +18841,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafer-buffer%2Fdownload%2Fsafer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", - "dev": true + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" }, "sane": { "version": "4.1.0", @@ -19644,7 +19621,6 @@ "version": "1.16.1", "resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz", "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -20422,7 +20398,6 @@ "version": "2.5.0", "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.5.0.tgz?cache=0&sync_timestamp=1584645708631&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftough-cookie%2Fdownload%2Ftough-cookie-2.5.0.tgz", "integrity": "sha1-zZ+yoKodWhK0c72fuW+j3P9lreI=", - "dev": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -20820,7 +20795,6 @@ "version": "0.6.0", "resolved": "https://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -20828,8 +20802,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz?cache=0&sync_timestamp=1581364304221&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftweetnacl%2Fdownload%2Ftweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-check": { "version": "0.3.2", @@ -21075,7 +21048,6 @@ "version": "4.2.2", "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.2.2.tgz", "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -21119,7 +21091,6 @@ "version": "1.4.7", "resolved": "https://registry.npm.taobao.org/url-parse/download/url-parse-1.4.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Furl-parse%2Fdownload%2Furl-parse-1.4.7.tgz", "integrity": "sha1-qKg1NejACjFuQDpdtKwbm4U64ng=", - "dev": true, "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -21179,8 +21150,7 @@ "uuid": { "version": "3.4.0", "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-3.4.0.tgz?cache=0&sync_timestamp=1588192972951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-3.4.0.tgz", - "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=", - "dev": true + "integrity": "sha1-sj5DWK+oogL+ehAK8fX4g/AgB+4=" }, "v-click-outside-x": { "version": "3.7.1", @@ -21237,7 +21207,6 @@ "version": "1.10.0", "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", diff --git a/vueJs/package.json b/vueJs/package.json index d0924faf8..b8f34b978 100644 --- a/vueJs/package.json +++ b/vueJs/package.json @@ -15,6 +15,7 @@ "test:unit": "jest --clearCache && vue-cli-service test:unit" }, "dependencies": { + "@microsoft/signalr": "^3.1.4", "@tinymce/tinymce-vue": "^3.2.0", "axios": "^0.19.2", "clipboard": "^2.0.6", diff --git a/vueJs/src/api/abpconfiguration.ts b/vueJs/src/api/abpconfiguration.ts index 41ecea8ac..1ab7735dd 100644 --- a/vueJs/src/api/abpconfiguration.ts +++ b/vueJs/src/api/abpconfiguration.ts @@ -90,6 +90,8 @@ export interface IAbpConfiguration { multiTenancy: MultiTenancy objectExtensions: any setting: Setting + + getSetting(key: string): string | undefined } export class AbpConfiguration implements IAbpConfiguration { @@ -111,4 +113,11 @@ export class AbpConfiguration implements IAbpConfiguration { this.multiTenancy = new MultiTenancy() this.currentTenant = new CurrentTenant() } + + public getSetting(key: string) { + if (this.setting.values && this.setting.values[key]) { + return this.setting.values[key] + } + return undefined + } } diff --git a/vueJs/src/components/Notification/index.vue b/vueJs/src/components/Notification/index.vue new file mode 100644 index 000000000..7c7d78f14 --- /dev/null +++ b/vueJs/src/components/Notification/index.vue @@ -0,0 +1,205 @@ + + + + + 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') }}) diff --git a/vueJs/src/lang/zh.ts b/vueJs/src/lang/zh.ts index c7af72e08..06c9d733b 100644 --- a/vueJs/src/lang/zh.ts +++ b/vueJs/src/lang/zh.ts @@ -90,6 +90,9 @@ export default { login: { title: '系统登录', logIn: '登录', + register: '注册', + notAccount: '没有账户?', + existsAccount: '已有账户?', userLogin: '用户密码登录', phoneLogin: '手机免密登录', tenantName: '租户', diff --git a/vueJs/src/layout/components/Navbar/index.vue b/vueJs/src/layout/components/Navbar/index.vue index 04141c333..9e25830e4 100644 --- a/vueJs/src/layout/components/Navbar/index.vue +++ b/vueJs/src/layout/components/Navbar/index.vue @@ -23,6 +23,7 @@ + { - const token = getItem(tokenKey) + const token = getItem(refreshTokenKey) if (token) { UserApiService.refreshToken(token).then(result => { const token = result.token_type + ' ' + result.access_token diff --git a/vueJs/src/views/admin/tenants/index.vue b/vueJs/src/views/admin/tenants/index.vue index 338b18701..5a331563a 100644 --- a/vueJs/src/views/admin/tenants/index.vue +++ b/vueJs/src/views/admin/tenants/index.vue @@ -78,7 +78,7 @@