84 changed files with 2027 additions and 209 deletions
@ -0,0 +1,21 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.EntityFrameworkCore |
||||
|
{ |
||||
|
public class MessageServiceHostMigrationsDbContext : AbpDbContext<MessageServiceHostMigrationsDbContext> |
||||
|
{ |
||||
|
public MessageServiceHostMigrationsDbContext(DbContextOptions<MessageServiceHostMigrationsDbContext> options) |
||||
|
: base(options) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder) |
||||
|
{ |
||||
|
base.OnModelCreating(modelBuilder); |
||||
|
|
||||
|
modelBuilder.ConfigureMessageService(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<MessageServiceHostMigrationsDbContext> |
||||
|
{ |
||||
|
public MessageServiceHostMigrationsDbContext CreateDbContext(string[] args) |
||||
|
{ |
||||
|
var configuration = BuildConfiguration(); |
||||
|
|
||||
|
var builder = new DbContextOptionsBuilder<MessageServiceHostMigrationsDbContext>() |
||||
|
.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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace>LINGYUN.Abp.MessageService</RootNamespace> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3"> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.1.3" /> |
||||
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="3.1.3" /> |
||||
|
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" /> |
||||
|
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> |
||||
|
<PackageReference Include="Serilog.Enrichers.Assembly" Version="2.0.0" /> |
||||
|
<PackageReference Include="Serilog.Enrichers.Process" Version="2.0.1" /> |
||||
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" /> |
||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> |
||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.MultiTenancy" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.EntityFrameworkCore.MySQL" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.TenantManagement.EntityFrameworkCore" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\modules\common\LINGYUN.Abp.IM.SignalR\LINGYUN.Abp.IM.SignalR.csproj" /> |
||||
|
<ProjectReference Include="..\modules\common\LINGYUN.Abp.Notifications.SignalR\LINGYUN.Abp.Notifications.SignalR.csproj" /> |
||||
|
<ProjectReference Include="..\modules\message\LINGYUN.Abp.MessageService.EntityFrameworkCore\LINGYUN.Abp.MessageService.EntityFrameworkCore.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,143 @@ |
|||||
|
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.Builder; |
||||
|
using Microsoft.AspNetCore.DataProtection; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using Microsoft.OpenApi.Models; |
||||
|
using StackExchange.Redis; |
||||
|
using System; |
||||
|
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(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<AbpDbContextOptions>(options => |
||||
|
{ |
||||
|
options.UseMySQL(); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpMessageServiceHttpApiHostModule>("LINGYUN.Abp.MessageService"); |
||||
|
}); |
||||
|
|
||||
|
// 多租户
|
||||
|
Configure<AbpMultiTenancyOptions>(options => |
||||
|
{ |
||||
|
options.IsEnabled = true; |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpTenantResolveOptions>(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<AbpLocalizationOptions>(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() ? "Platform_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.UseAuthentication(); |
||||
|
// jwt
|
||||
|
app.UseJwtTokenMiddleware(); |
||||
|
// 多租户
|
||||
|
app.UseMultiTenancy(); |
||||
|
// Swagger
|
||||
|
app.UseSwagger(); |
||||
|
// Swagger可视化界面
|
||||
|
app.UseSwaggerUI(options => |
||||
|
{ |
||||
|
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support MessageService API"); |
||||
|
}); |
||||
|
// 审计日志
|
||||
|
app.UseAuditing(); |
||||
|
// 路由
|
||||
|
app.UseConfiguredEndpoints(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,130 @@ |
|||||
|
// <auto-generated />
|
||||
|
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<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnName("CreationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<DateTime?>("ExpirationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<string>("NotificationData") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(1048576); |
||||
|
|
||||
|
b.Property<long>("NotificationId") |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<string>("NotificationName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(100); |
||||
|
|
||||
|
b.Property<string>("NotificationTypeName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(512) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(512); |
||||
|
|
||||
|
b.Property<sbyte>("Severity") |
||||
|
.HasColumnType("tinyint"); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<int>("Type") |
||||
|
.HasColumnType("int"); |
||||
|
|
||||
|
b.HasKey("Id"); |
||||
|
|
||||
|
b.HasIndex("NotificationName"); |
||||
|
|
||||
|
b.ToTable("AppNotifications"); |
||||
|
}); |
||||
|
|
||||
|
modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => |
||||
|
{ |
||||
|
b.Property<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<long>("NotificationId") |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<sbyte>("ReadStatus") |
||||
|
.HasColumnType("tinyint"); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<Guid>("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<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnName("CreationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<string>("NotificationName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(100); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<Guid>("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
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<long>(nullable: false) |
||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
||||
|
TenantId = table.Column<Guid>(nullable: true), |
||||
|
Severity = table.Column<sbyte>(nullable: false), |
||||
|
Type = table.Column<int>(nullable: false), |
||||
|
NotificationId = table.Column<long>(nullable: false), |
||||
|
NotificationName = table.Column<string>(maxLength: 100, nullable: false), |
||||
|
NotificationData = table.Column<string>(maxLength: 1048576, nullable: false), |
||||
|
NotificationTypeName = table.Column<string>(maxLength: 512, nullable: false), |
||||
|
ExpirationTime = table.Column<DateTime>(nullable: true), |
||||
|
CreationTime = table.Column<DateTime>(nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_AppNotifications", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "AppUserNotifications", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<long>(nullable: false) |
||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
||||
|
TenantId = table.Column<Guid>(nullable: true), |
||||
|
UserId = table.Column<Guid>(nullable: false), |
||||
|
NotificationId = table.Column<long>(nullable: false), |
||||
|
ReadStatus = table.Column<sbyte>(nullable: false) |
||||
|
}, |
||||
|
constraints: table => |
||||
|
{ |
||||
|
table.PrimaryKey("PK_AppUserNotifications", x => x.Id); |
||||
|
}); |
||||
|
|
||||
|
migrationBuilder.CreateTable( |
||||
|
name: "AppUserSubscribes", |
||||
|
columns: table => new |
||||
|
{ |
||||
|
Id = table.Column<long>(nullable: false) |
||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), |
||||
|
TenantId = table.Column<Guid>(nullable: true), |
||||
|
CreationTime = table.Column<DateTime>(nullable: false), |
||||
|
NotificationName = table.Column<string>(maxLength: 100, nullable: false), |
||||
|
UserId = table.Column<Guid>(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"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,128 @@ |
|||||
|
// <auto-generated />
|
||||
|
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.Notifications.Notification", b => |
||||
|
{ |
||||
|
b.Property<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnName("CreationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<DateTime?>("ExpirationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<string>("NotificationData") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(1048576); |
||||
|
|
||||
|
b.Property<long>("NotificationId") |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<string>("NotificationName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(100); |
||||
|
|
||||
|
b.Property<string>("NotificationTypeName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(512) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(512); |
||||
|
|
||||
|
b.Property<sbyte>("Severity") |
||||
|
.HasColumnType("tinyint"); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<int>("Type") |
||||
|
.HasColumnType("int"); |
||||
|
|
||||
|
b.HasKey("Id"); |
||||
|
|
||||
|
b.HasIndex("NotificationName"); |
||||
|
|
||||
|
b.ToTable("AppNotifications"); |
||||
|
}); |
||||
|
|
||||
|
modelBuilder.Entity("LINGYUN.Abp.MessageService.Notifications.UserNotification", b => |
||||
|
{ |
||||
|
b.Property<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<long>("NotificationId") |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<sbyte>("ReadStatus") |
||||
|
.HasColumnType("tinyint"); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<Guid>("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<long>("Id") |
||||
|
.ValueGeneratedOnAdd() |
||||
|
.HasColumnType("bigint"); |
||||
|
|
||||
|
b.Property<DateTime>("CreationTime") |
||||
|
.HasColumnName("CreationTime") |
||||
|
.HasColumnType("datetime(6)"); |
||||
|
|
||||
|
b.Property<string>("NotificationName") |
||||
|
.IsRequired() |
||||
|
.HasColumnType("varchar(100) CHARACTER SET utf8mb4") |
||||
|
.HasMaxLength(100); |
||||
|
|
||||
|
b.Property<Guid?>("TenantId") |
||||
|
.HasColumnName("TenantId") |
||||
|
.HasColumnType("char(36)"); |
||||
|
|
||||
|
b.Property<Guid>("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
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<Startup>(); |
||||
|
}) |
||||
|
.UseSerilog() |
||||
|
.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
@ -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" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<AbpMessageServiceHttpApiHostModule>(); |
||||
|
} |
||||
|
|
||||
|
public void Configure(IApplicationBuilder app) |
||||
|
{ |
||||
|
app.InitializeApplication(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
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] |
||||
|
[HubRoute("messages")] |
||||
|
public class AbpMessageHub : OnlineClientHubBase |
||||
|
{ |
||||
|
private readonly IMessageStore _messageStore; |
||||
|
|
||||
|
public AbpMessageHub( |
||||
|
IMessageStore messageStore) |
||||
|
{ |
||||
|
_messageStore = messageStore; |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 客户端调用发送消息方法
|
||||
|
/// </summary>
|
||||
|
/// <param name="chatMessage"></param>
|
||||
|
/// <returns></returns>
|
||||
|
[HubMethodName("SendMessage")] |
||||
|
public virtual async Task SendMessageAsync(ChatMessage chatMessage) |
||||
|
{ |
||||
|
// 持久化
|
||||
|
await _messageStore.StoreMessageAsync(chatMessage); |
||||
|
|
||||
|
if (!chatMessage.GroupName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var signalRClient = Clients.Group(chatMessage.GroupName); |
||||
|
if (signalRClient == null) |
||||
|
{ |
||||
|
Logger.LogDebug("Can not get group " + chatMessage.GroupName + " from SignalR hub!"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
await signalRClient.SendAsync("getChatMessage", chatMessage); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupName); |
||||
|
Logger.LogWarning("Send group message error: {0}", ex.Message); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId); |
||||
|
var onlineClients = OnlineClientManager.GetAllByContext(onlineClientContext); |
||||
|
foreach (var onlineClient in onlineClients) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var signalRClient = 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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,89 @@ |
|||||
|
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<SignalRMessageSender> Logger { protected get; set; } |
||||
|
|
||||
|
private readonly IOnlineClientManager _onlineClientManager; |
||||
|
|
||||
|
private readonly IHubContext<AbpMessageHub> _hubContext; |
||||
|
|
||||
|
private readonly IMessageStore _messageStore; |
||||
|
|
||||
|
public SignalRMessageSender( |
||||
|
IOnlineClientManager onlineClientManager, |
||||
|
IHubContext<AbpMessageHub> hubContext, |
||||
|
IMessageStore messageStore) |
||||
|
{ |
||||
|
_hubContext = hubContext; |
||||
|
_messageStore = messageStore; |
||||
|
_onlineClientManager = onlineClientManager; |
||||
|
|
||||
|
Logger = NullLogger<SignalRMessageSender>.Instance; |
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 服务端调用发送消息方法
|
||||
|
/// </summary>
|
||||
|
/// <param name="chatMessage"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public async Task SendMessageAsync(ChatMessage chatMessage) |
||||
|
{ |
||||
|
// 持久化
|
||||
|
await _messageStore.StoreMessageAsync(chatMessage); |
||||
|
|
||||
|
if (!chatMessage.GroupName.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var signalRClient = _hubContext.Clients.Group(chatMessage.GroupName); |
||||
|
if (signalRClient == null) |
||||
|
{ |
||||
|
Logger.LogDebug("Can not get group " + chatMessage.GroupName + " from SignalR hub!"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
await signalRClient.SendAsync("getChatMessage", chatMessage); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogWarning("Could not send message to group: {0}", chatMessage.GroupName); |
||||
|
Logger.LogWarning("Send group message error: {0}", ex.Message); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var onlineClientContext = new OnlineClientContext(chatMessage.TenantId, chatMessage.ToUserId); |
||||
|
var onlineClients = _onlineClientManager.GetAllByContext(onlineClientContext); |
||||
|
foreach (var onlineClient in onlineClients) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var signalRClient = _hubContext.Clients.Client(onlineClient.ConnectionId); |
||||
|
if (signalRClient == null) |
||||
|
{ |
||||
|
Logger.LogDebug("Can not get user " + onlineClientContext.UserId + " with connectionId " + onlineClient.ConnectionId + " from SignalR hub!"); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
await signalRClient.SendAsync("getChatMessage", chatMessage); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogWarning("Could not send message to user: {0}", chatMessage.ToUserId); |
||||
|
Logger.LogWarning("Send to user message error: {0}", ex.Message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace LINGYUN.Abp.IM.Group |
||||
|
{ |
||||
|
public class GroupChat |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
public int MaxUserLength { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Group |
||||
|
{ |
||||
|
public interface IUserGroupStore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 获取用户所在通讯组列表
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="userId"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<IEnumerable<GroupChat>> GetUserGroupsAsync(Guid? tenantId, Guid userId); |
||||
|
/// <summary>
|
||||
|
/// 获取通讯组所有用户
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="groupId"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<IEnumerable<UserGroup>> GetGroupUsersAsync(Guid? tenantId, long groupId); |
||||
|
/// <summary>
|
||||
|
/// 用户加入通讯组
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="userId"></param>
|
||||
|
/// <param name="groupId"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task AddUserToGroupAsync(Guid? tenantId, Guid userId, long groupId); |
||||
|
/// <summary>
|
||||
|
/// 用户退出通讯组
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="userId"></param>
|
||||
|
/// <param name="groupId"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task RemoveUserFormGroupAsync(Guid? tenantId, Guid userId, long groupId); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public class ChatMessage |
||||
|
{ |
||||
|
public Guid? TenantId { get; set; } |
||||
|
public string GroupName { get; set; } |
||||
|
public Guid FormUserId { get; set; } |
||||
|
public Guid ToUserId { get; set; } |
||||
|
public string Content { get; set; } |
||||
|
public DateTime SendTime { get; set; } |
||||
|
public MessageType MessageType { get; set; } = MessageType.Text; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public interface IMessageSender |
||||
|
{ |
||||
|
Task SendMessageAsync(ChatMessage chatMessage); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public interface IMessageStore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 存储聊天记录
|
||||
|
/// </summary>
|
||||
|
/// <param name="chatMessage"></param>
|
||||
|
/// <param name="formUserId"></param>
|
||||
|
/// <param name="toUserId"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task StoreMessageAsync(ChatMessage chatMessage); |
||||
|
/// <summary>
|
||||
|
/// 获取群组聊天记录
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="groupName"></param>
|
||||
|
/// <param name="maxResultCount"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<ChatMessage>> GetGroupMessageAsync(Guid tenantId, string groupName, int maxResultCount = 10); |
||||
|
/// <summary>
|
||||
|
/// 获取与某个用户的聊天记录
|
||||
|
/// </summary>
|
||||
|
/// <param name="tenantId"></param>
|
||||
|
/// <param name="userId"></param>
|
||||
|
/// <param name="maxResultCount"></param>
|
||||
|
/// <returns></returns>
|
||||
|
Task<List<ChatMessage>> GetChatMessageAsync(Guid tenantId, Guid userId, int maxResultCount = 10); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
namespace LINGYUN.Abp.IM.Messages |
||||
|
{ |
||||
|
public enum MessageType |
||||
|
{ |
||||
|
Text = 0, |
||||
|
Image = 10, |
||||
|
Link = 20, |
||||
|
Video = 30 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="2.8.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Ddd.Application" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Notifications\LINGYUN.Abp.Notifications.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.RealTime\LINGYUN.Abp.RealTime.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -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 |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.SignalR; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Application.Dtos; |
||||
|
using Volo.Abp.AspNetCore.SignalR; |
||||
|
using Volo.Abp.Users; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Notifications.SignalR.Hubs |
||||
|
{ |
||||
|
[Authorize] |
||||
|
[HubRoute("notifications")] |
||||
|
public class AbpNotificationsHub : OnlineClientHubBase |
||||
|
{ |
||||
|
private INotificationStore _notificationStore; |
||||
|
protected INotificationStore NotificationStore => LazyGetRequiredService(ref _notificationStore); |
||||
|
|
||||
|
[HubMethodName("GetNotification")] |
||||
|
public virtual async Task<ListResultDto<NotificationInfo>> GetNotificationAsync(NotificationReadState readState = NotificationReadState.UnRead) |
||||
|
{ |
||||
|
var userNotifications = await NotificationStore.GetUserNotificationsAsync(CurrentTenant.Id, CurrentUser.GetId(), readState); |
||||
|
|
||||
|
return new ListResultDto<NotificationInfo>(userNotifications); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,68 @@ |
|||||
|
using LINGYUN.Abp.RealTime.Client; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.AspNetCore.SignalR; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Notifications.SignalR |
||||
|
{ |
||||
|
public abstract class OnlineClientHubBase : AbpHub |
||||
|
{ |
||||
|
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() |
||||
|
{ |
||||
|
return new OnlineClient(Context.ConnectionId, GetClientIpAddress(), |
||||
|
CurrentTenant.Id, CurrentUser.Id) |
||||
|
{ |
||||
|
ConnectTime = Clock.Now |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetClientIpAddress() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return HttpContextAccessor.HttpContext?.Connection?.RemoteIpAddress?.ToString(); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Logger.LogException(ex, LogLevel.Warning); |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<INotificationDispatcher, DefaultNotificationDispatcher>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<Guid> userIds, Guid? tenantId); |
|
||||
} |
|
||||
} |
|
||||
@ -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.InsertUserSubscriptionAsync(notification.TenantId, subscriptionUserIds, notification.Name); |
||||
|
|
||||
|
// 发布用户通知
|
||||
|
await _notificationPublisher.PublishAsync(notification, subscriptionUserIds); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Core" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.RealTime |
||||
|
{ |
||||
|
public class AbpRealTimeModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,6 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
|
||||
namespace LINGYUN.Abp.IM |
namespace LINGYUN.Abp.RealTime.Client |
||||
{ |
{ |
||||
public interface IOnlineClientStore |
public interface IOnlineClientStore |
||||
{ |
{ |
||||
@ -1,6 +1,6 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace LINGYUN.Abp.IM |
namespace LINGYUN.Abp.RealTime.Client |
||||
{ |
{ |
||||
public class OnlineClientEventArgs : EventArgs |
public class OnlineClientEventArgs : EventArgs |
||||
{ |
{ |
||||
@ -1,4 +1,4 @@ |
|||||
namespace LINGYUN.Abp.IM |
namespace LINGYUN.Abp.RealTime.Client |
||||
{ |
{ |
||||
public class OnlineUserEventArgs : OnlineClientEventArgs |
public class OnlineUserEventArgs : OnlineClientEventArgs |
||||
{ |
{ |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Localization |
||||
|
{ |
||||
|
[LocalizationResourceName("MessageService")] |
||||
|
public class MessageServiceResource |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -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"; |
||||
|
/// <summary>
|
||||
|
/// 清理过期消息批次
|
||||
|
/// </summary>
|
||||
|
public const string CleanupExpirationBatchCount = Default + ".CleanupExpirationBatchCount"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Notifications |
||||
|
{ |
||||
|
public class CleanupNotificationJobArgs |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 清理大小
|
||||
|
/// </summary>
|
||||
|
public int Count { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 清理租户
|
||||
|
/// </summary>
|
||||
|
public Guid? TenantId { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,17 +0,0 @@ |
|||||
namespace LINGYUN.Abp.MessageService |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 读取状态
|
|
||||
/// </summary>
|
|
||||
public enum ReadStatus : sbyte |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 已读
|
|
||||
/// </summary>
|
|
||||
Read = 0, |
|
||||
/// <summary>
|
|
||||
/// 未读
|
|
||||
/// </summary>
|
|
||||
UnRead = 10 |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
namespace LINGYUN.Abp.MessageService |
||||
|
{ |
||||
|
public class AbpMessageServiceDbProperties |
||||
|
{ |
||||
|
public const string DefaultTablePrefix = "App"; |
||||
|
|
||||
|
public const string DefaultSchema = null; |
||||
|
} |
||||
|
} |
||||
@ -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<CleanupNotificationJobArgs> |
||||
|
{ |
||||
|
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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
using AutoMapper; |
||||
|
using LINGYUN.Abp.MessageService.Notifications; |
||||
|
using LINGYUN.Abp.MessageService.Subscriptions; |
||||
|
using LINGYUN.Abp.Notifications; |
||||
|
using Newtonsoft.Json; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Mapper |
||||
|
{ |
||||
|
public class MessageServiceDomainAutoMapperProfile : Profile |
||||
|
{ |
||||
|
public MessageServiceDomainAutoMapperProfile() |
||||
|
{ |
||||
|
CreateMap<Notification, NotificationInfo>() |
||||
|
.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<UserSubscribe, NotificationSubscriptionInfo>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Abp.MessageService.Notifications |
||||
|
{ |
||||
|
public interface INotificationRepository : IBasicRepository<Notification, long> |
||||
|
{ |
||||
|
Task<Notification> GetByIdAsync(long notificationId); |
||||
|
|
||||
|
Task DeleteExpritionAsync(int batchCount); |
||||
|
} |
||||
|
} |
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,17 @@ |
|||||
|
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<UserNotification, long> |
||||
|
{ |
||||
|
Task<UserNotification> GetByIdAsync(Guid userId, long notificationId); |
||||
|
|
||||
|
Task<List<Notification>> GetNotificationsAsync(Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10); |
||||
|
|
||||
|
Task ChangeUserNotificationReadStateAsync(Guid userId, long notificationId, NotificationReadState readState); |
||||
|
} |
||||
|
} |
||||
@ -1,47 +1,40 @@ |
|||||
using LINGYUN.Abp.MessageService.Subscriptions; |
using LINGYUN.Abp.Notifications; |
||||
using LINGYUN.Abp.MessageService.Utils; |
|
||||
using LINGYUN.Abp.Notifications; |
|
||||
using System; |
using System; |
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Json; |
|
||||
using Volo.Abp.MultiTenancy; |
|
||||
using Volo.Abp.Uow; |
|
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Notifications |
namespace LINGYUN.Abp.MessageService.Notifications |
||||
{ |
{ |
||||
public class NotificationDispatcher : INotificationDispatcher, ITransientDependency |
public class NotificationDispatcher : INotificationDispatcher, ITransientDependency |
||||
{ |
{ |
||||
protected IJsonSerializer JsonSerializer { get; } |
|
||||
protected ICurrentTenant CurrentTenant { get; } |
|
||||
protected ISubscribeStore SubscribeStore { get; } |
|
||||
protected INotificationStore NotificationStore { get; } |
protected INotificationStore NotificationStore { get; } |
||||
protected IUnitOfWork CurrentUnitOfWork => UnitOfWorkManager.Current; |
|
||||
protected IUnitOfWorkManager UnitOfWorkManager { get; } |
|
||||
protected INotificationPublisher NotificationPublisher { 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) |
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); |
await NotificationStore.InsertUserNotificationAsync(notification, subscribe.UserId); |
||||
foreach(var userId in subscribeUsers) |
|
||||
{ |
|
||||
await NotificationStore.InsertUserNotificationAsync(notification, userId); |
|
||||
} |
|
||||
await CurrentUnitOfWork.SaveChangesAsync(); |
|
||||
|
|
||||
await NotifyAsync(notification.Data, notification.TenantId, subscribeUsers); |
|
||||
} |
} |
||||
|
|
||||
|
var subscribeUsers = subscribes.Select(s => s.UserId); |
||||
|
await NotifyAsync(notification, subscribeUsers); |
||||
} |
} |
||||
|
|
||||
protected virtual async Task NotifyAsync(NotificationData data, Guid? tenantId, IEnumerable<Guid> userIds) |
protected virtual async Task NotifyAsync(NotificationInfo notification, IEnumerable<Guid> userIds) |
||||
{ |
{ |
||||
await NotificationPublisher.PublishAsync(data, userIds, tenantId); |
await NotificationPublisher.PublishAsync(notification, userIds); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,239 @@ |
|||||
|
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<NotificationInfo> GetNotificationOrNullAsync(Guid? tenantId, long notificationId) |
||||
|
{ |
||||
|
using (CurrentTenant.Change(tenantId)) |
||||
|
{ |
||||
|
var notification = await NotificationRepository.GetByIdAsync(notificationId); |
||||
|
|
||||
|
return _objectMapper.Map<Notification, NotificationInfo>(notification); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task<List<NotificationSubscriptionInfo>> GetSubscriptionsAsync(Guid? tenantId, string notificationName) |
||||
|
{ |
||||
|
using (CurrentTenant.Change(tenantId)) |
||||
|
{ |
||||
|
var userSubscriptions = await UserSubscribeRepository.GetSubscribesAsync(notificationName); |
||||
|
|
||||
|
return _objectMapper.Map<List<UserSubscribe>, List<NotificationSubscriptionInfo>>(userSubscriptions); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task<List<NotificationInfo>> 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<Notification>, List<NotificationInfo>>(notifications); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task<List<NotificationSubscriptionInfo>> GetUserSubscriptionsAsync(Guid? tenantId, Guid userId) |
||||
|
{ |
||||
|
using (CurrentTenant.Change(tenantId)) |
||||
|
{ |
||||
|
var userSubscriptionNames = await UserSubscribeRepository.GetUserSubscribesAsync(userId); |
||||
|
|
||||
|
var userSubscriptions = new List<NotificationSubscriptionInfo>(); |
||||
|
|
||||
|
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 notify = new Notification(SnowflakeIdGenerator.Create(), 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<Guid> userIds, string notificationName) |
||||
|
{ |
||||
|
using (var unitOfWork = _unitOfWorkManager.Begin()) |
||||
|
{ |
||||
|
using (CurrentTenant.Change(tenantId)) |
||||
|
{ |
||||
|
var userSubscribes = new List<UserSubscribe>(); |
||||
|
|
||||
|
foreach(var userId in userIds) |
||||
|
{ |
||||
|
userSubscribes.Add(new UserSubscribe(notificationName, userId)); |
||||
|
} |
||||
|
|
||||
|
await UserSubscribeRepository.InsertUserSubscriptionAsync(userSubscribes); |
||||
|
|
||||
|
await unitOfWork.SaveChangesAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public async Task<bool> IsSubscribedAsync(Guid? tenantId, Guid userId, string notificationName) |
||||
|
{ |
||||
|
using (CurrentTenant.Change(tenantId)) |
||||
|
return await UserSubscribeRepository.UserSubscribeExistsAysnc(notificationName, userId); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,13 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace LINGYUN.Abp.MessageService.Subscriptions |
|
||||
{ |
|
||||
public interface ISubscribeStore |
|
||||
{ |
|
||||
Task<List<Guid>> GetUserSubscribesAsync(string notificationName); |
|
||||
Task UserSubscribeAsync(string notificationName, Guid userId); |
|
||||
Task UserUnSubscribeAsync(string notificationName, Guid userId); |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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<List<Guid>> 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); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,16 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="2.8.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.MessageService.Domain\LINGYUN.Abp.MessageService.Domain.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,26 @@ |
|||||
|
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<MessageServiceDbContext>(options => |
||||
|
{ |
||||
|
options.AddRepository<Notification, INotificationRepository>(); |
||||
|
options.AddRepository<UserNotification, IUserNotificationRepository>(); |
||||
|
options.AddRepository<UserSubscribe, IUserSubscribeRepository>(); |
||||
|
|
||||
|
options.AddDefaultRepositories(includeAllEntities: true); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<MessageServiceDbContext> |
||||
|
{ |
||||
|
public MessageServiceDbContext(DbContextOptions<MessageServiceDbContext> options) |
||||
|
: base(options) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder) |
||||
|
{ |
||||
|
modelBuilder.ConfigureMessageService(options => |
||||
|
{ |
||||
|
options.TablePrefix = AbpMessageServiceDbProperties.DefaultTablePrefix; |
||||
|
options.Schema = AbpMessageServiceDbProperties.DefaultSchema; |
||||
|
}); |
||||
|
|
||||
|
base.OnModelCreating(modelBuilder); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
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<MessageServiceModelBuilderConfigurationOptions> optionsAction = null) |
||||
|
{ |
||||
|
Check.NotNull(builder, nameof(builder)); |
||||
|
|
||||
|
var options = new MessageServiceModelBuilderConfigurationOptions(); |
||||
|
|
||||
|
optionsAction?.Invoke(options); |
||||
|
|
||||
|
builder.Entity<Notification>(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<UserNotification>(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<UserSubscribe>(b => |
||||
|
{ |
||||
|
b.ToTable(options.TablePrefix + "UserSubscribes", options.Schema); |
||||
|
|
||||
|
b.Property(p => p.NotificationName).HasMaxLength(SubscribeConsts.MaxNotificationNameLength).IsRequired(); |
||||
|
|
||||
|
b.ConfigureCreationTime(); |
||||
|
b.ConfigureMultiTenant(); |
||||
|
|
||||
|
b.ConfigureMultiTenant(); |
||||
|
b.HasIndex(p => new { p.TenantId, p.UserId, p.NotificationName }) |
||||
|
.HasName("IX_Tenant_User_Notification_Name") |
||||
|
.IsUnique(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<MessageServiceDbContext, Notification, long>, |
||||
|
INotificationRepository, ITransientDependency |
||||
|
{ |
||||
|
public EfCoreNotificationRepository( |
||||
|
IDbContextProvider<MessageServiceDbContext> 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<Notification> GetByIdAsync(long notificationId) |
||||
|
{ |
||||
|
return await DbSet.Where(x => x.NotificationId.Equals(notificationId)).FirstOrDefaultAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
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<MessageServiceDbContext, UserNotification, long>, |
||||
|
IUserNotificationRepository, ITransientDependency |
||||
|
{ |
||||
|
public EfCoreUserNotificationRepository( |
||||
|
IDbContextProvider<MessageServiceDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
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<UserNotification> 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<List<Notification>> GetNotificationsAsync(Guid userId, NotificationReadState readState = NotificationReadState.UnRead, int maxResultCount = 10) |
||||
|
{ |
||||
|
|
||||
|
var userNofitications = await (from un in DbContext.Set<UserNotification>() |
||||
|
join n in DbContext.Set<Notification>() |
||||
|
on un.NotificationId equals n.NotificationId |
||||
|
where un.UserId.Equals(userId) && un.ReadStatus.Equals(readState) |
||||
|
select n) |
||||
|
.Take(maxResultCount) |
||||
|
.ToListAsync(); |
||||
|
return userNofitications; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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<MessageServiceDbContext, UserSubscribe, long>, |
||||
|
IUserSubscribeRepository, ITransientDependency |
||||
|
{ |
||||
|
public EfCoreUserSubscribeRepository( |
||||
|
IDbContextProvider<MessageServiceDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public async Task<List<UserSubscribe>> GetSubscribesAsync(string notificationName) |
||||
|
{ |
||||
|
var userSubscribes = await DbSet.Where(x => x.NotificationName.Equals(notificationName)).ToListAsync(); |
||||
|
|
||||
|
return userSubscribes; |
||||
|
} |
||||
|
|
||||
|
public async Task<UserSubscribe> 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<List<string>> GetUserSubscribesAsync(Guid userId) |
||||
|
{ |
||||
|
var userSubscribeNames = await DbSet |
||||
|
.Where(x => x.UserId.Equals(userId)) |
||||
|
.Select(x => x.NotificationName) |
||||
|
.ToListAsync(); |
||||
|
|
||||
|
return userSubscribeNames; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<Guid>> 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<UserSubscribe> userSubscribes) |
||||
|
{ |
||||
|
await DbSet.AddRangeAsync(userSubscribes); |
||||
|
} |
||||
|
|
||||
|
public async Task<bool> UserSubscribeExistsAysnc(string notificationName, Guid userId) |
||||
|
{ |
||||
|
return await DbSet.AnyAsync(x => x.UserId.Equals(userId) && x.NotificationName.Equals(notificationName)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue