From 5305ad1018d3b8dea501c5e3fc10576b22373352 Mon Sep 17 00:00:00 2001 From: Vashchuk Nikita Date: Tue, 29 Jun 2021 11:40:20 +0300 Subject: [PATCH] Added models, DbWorker, publisher, sender. --- ASC.Web.sln | 6 ++ common/ASC.Webhooks/ASC.Webhooks.csproj | 33 ++++++++ .../ASC.Webhooks/Dao/Models/WebhooksConfig.cs | 10 +++ .../Dao/Models/WebhooksPayload.cs | 15 ++++ common/ASC.Webhooks/Dao/WebhooksDbContext.cs | 81 +++++++++++++++++++ common/ASC.Webhooks/DbWorker.cs | 37 +++++++++ .../Properties/launchSettings.json | 27 +++++++ common/ASC.Webhooks/WebhookPublisher.cs | 49 +++++++++++ common/ASC.Webhooks/WebhookSender.cs | 66 +++++++++++++++ 9 files changed, 324 insertions(+) create mode 100644 common/ASC.Webhooks/ASC.Webhooks.csproj create mode 100644 common/ASC.Webhooks/Dao/Models/WebhooksConfig.cs create mode 100644 common/ASC.Webhooks/Dao/Models/WebhooksPayload.cs create mode 100644 common/ASC.Webhooks/Dao/WebhooksDbContext.cs create mode 100644 common/ASC.Webhooks/DbWorker.cs create mode 100644 common/ASC.Webhooks/Properties/launchSettings.json create mode 100644 common/ASC.Webhooks/WebhookPublisher.cs create mode 100644 common/ASC.Webhooks/WebhookSender.cs diff --git a/ASC.Web.sln b/ASC.Web.sln index f8af10e8e5..2abc9a460f 100644 --- a/ASC.Web.sln +++ b/ASC.Web.sln @@ -89,6 +89,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.SsoAuth.Svc", "common\s EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.CRM.BackgroundTasks", "products\ASC.CRM\BackgroundTasks\ASC.CRM.BackgroundTasks.csproj", "{E52C0E35-A05C-437F-8FF2-3E0AC9F81433}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Webhooks", "common\ASC.Webhooks\ASC.Webhooks.csproj", "{760BFF3A-1A67-43A1-A94C-78D11A4BB1E6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -251,6 +253,10 @@ Global {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Debug|Any CPU.Build.0 = Debug|Any CPU {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Release|Any CPU.ActiveCfg = Release|Any CPU {E52C0E35-A05C-437F-8FF2-3E0AC9F81433}.Release|Any CPU.Build.0 = Release|Any CPU + {760BFF3A-1A67-43A1-A94C-78D11A4BB1E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {760BFF3A-1A67-43A1-A94C-78D11A4BB1E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {760BFF3A-1A67-43A1-A94C-78D11A4BB1E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {760BFF3A-1A67-43A1-A94C-78D11A4BB1E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/common/ASC.Webhooks/ASC.Webhooks.csproj b/common/ASC.Webhooks/ASC.Webhooks.csproj new file mode 100644 index 0000000000..38196708ce --- /dev/null +++ b/common/ASC.Webhooks/ASC.Webhooks.csproj @@ -0,0 +1,33 @@ + + + + net5.0 + false + $(DefaultItemExcludes); + false + false + Library + + + + none + false + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/common/ASC.Webhooks/Dao/Models/WebhooksConfig.cs b/common/ASC.Webhooks/Dao/Models/WebhooksConfig.cs new file mode 100644 index 0000000000..13ebe76542 --- /dev/null +++ b/common/ASC.Webhooks/Dao/Models/WebhooksConfig.cs @@ -0,0 +1,10 @@ +#nullable disable + +namespace ASC.Webhooks.Dao.Models +{ + public partial class WebhooksConfig + { + public int TenantId { get; set; } + public string Uri { get; set; } + } +} diff --git a/common/ASC.Webhooks/Dao/Models/WebhooksPayload.cs b/common/ASC.Webhooks/Dao/Models/WebhooksPayload.cs new file mode 100644 index 0000000000..ec0b19e264 --- /dev/null +++ b/common/ASC.Webhooks/Dao/Models/WebhooksPayload.cs @@ -0,0 +1,15 @@ +using System; + +#nullable disable + +namespace ASC.Webhooks.Dao.Models +{ + public partial class WebhooksPayload + { + public int Id { get; set; } + public int TenantId { get; set; } + public string Data { get; set; } + public DateTime CreationTime { get; set; } + public EventName Event { get; set; } + } +} diff --git a/common/ASC.Webhooks/Dao/WebhooksDbContext.cs b/common/ASC.Webhooks/Dao/WebhooksDbContext.cs new file mode 100644 index 0000000000..a2202a70f3 --- /dev/null +++ b/common/ASC.Webhooks/Dao/WebhooksDbContext.cs @@ -0,0 +1,81 @@ +using ASC.Core.Common.EF; +using ASC.Webhooks.Dao.Models; + +using Microsoft.EntityFrameworkCore; + +#nullable disable + +namespace ASC.Webhooks.Dao +{ + public partial class WebhooksDbContext : BaseDbContext + { + public WebhooksDbContext() + { + } + + public WebhooksDbContext(DbContextOptions options) + : base(options) + { + } + + public virtual DbSet WebhooksConfigs { get; set; } + public virtual DbSet WebhooksPayloads { get; set; } + +// protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +// { +// if (!optionsBuilder.IsConfigured) +// { +//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263. +// optionsBuilder.UseMySQL("server=localhost;port=3306;database=onlyoffice;uid=root;password=onlyoffice"); +// } +// } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => new { e.TenantId, e.Uri }) + .HasName("PRIMARY"); + + entity.ToTable("webhooks_config"); + + entity.Property(e => e.TenantId).HasColumnType("int unsigned"); + + entity.Property(e => e.Uri) + .HasMaxLength(50) + .HasColumnName("URI") + .HasDefaultValueSql("''"); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e => new { e.Id }) + .HasName("PRIMARY"); + + entity.ToTable("webhooks_payload"); + + entity.Property(e => e.Id) + .HasColumnType("int") + .HasColumnName("ID") + .ValueGeneratedOnAdd(); + + entity.Property(e => e.Data) + .IsRequired() + .HasColumnType("json"); + + entity.Property(e => e.Event) + .HasColumnType("varchar") + .HasColumnName("EventID") + .HasMaxLength(50); + + entity.Property(e => e.TenantId) + .HasColumnType("int unsigned") + .HasColumnName("TenantID"); + }); + + OnModelCreatingPartial(modelBuilder); + } + + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); + } +} diff --git a/common/ASC.Webhooks/DbWorker.cs b/common/ASC.Webhooks/DbWorker.cs new file mode 100644 index 0000000000..a2f3b23566 --- /dev/null +++ b/common/ASC.Webhooks/DbWorker.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; + +using ASC.Common; +using ASC.Core.Common.EF; +using ASC.Webhooks.Dao; +using ASC.Webhooks.Dao.Models; + +namespace ASC.Webhooks +{ + [Scope] + public class DbWorker + { + public WebhooksDbContext webhooksContext { get; } + public DbWorker(DbContextManager dbContext) + { + webhooksContext = dbContext.Get("webhooks"); + } + + public void WriteToJournal(WebhooksPayload webhook) + { + webhooksContext.WebhooksPayloads.Add(webhook); + webhooksContext.SaveChanges(); + } + + public void AddWebhookConfig(WebhooksConfig webhooksConfig) + { + webhooksContext.WebhooksConfigs.Add(webhooksConfig); + webhooksContext.SaveChanges(); + } + + public List GetWebhookUri(int tenant) + { + return webhooksContext.WebhooksConfigs.Where(t => t.TenantId == tenant).Select(it => it.Uri).ToList(); + } + } +} diff --git a/common/ASC.Webhooks/Properties/launchSettings.json b/common/ASC.Webhooks/Properties/launchSettings.json new file mode 100644 index 0000000000..2ddd5acc1a --- /dev/null +++ b/common/ASC.Webhooks/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63599/", + "sslPort": 44357 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ASC.Webhooks": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/common/ASC.Webhooks/WebhookPublisher.cs b/common/ASC.Webhooks/WebhookPublisher.cs new file mode 100644 index 0000000000..d65f90b6fe --- /dev/null +++ b/common/ASC.Webhooks/WebhookPublisher.cs @@ -0,0 +1,49 @@ +using System; +using System.Text.Json; + +using ASC.Common; +using ASC.Core; +using ASC.Webhooks.Dao.Models; + +namespace ASC.Webhooks +{ + [Scope] + public class WebhookPublisher + { + private DbWorker DbWorker { get; } + private TenantManager TenantManager { get; } + private WebhookSender WebhookSender { get; } + + public WebhookPublisher(DbWorker dbWorker, TenantManager tenantManager, WebhookSender webhookSender) + { + DbWorker = dbWorker; + TenantManager = tenantManager; + WebhookSender = webhookSender; + } + + public void Publish(EventName name) + { + var result = WebhookSender.Send(name); + + if (result) + { + var tenantId = TenantManager.GetCurrentTenant().TenantId; + + var webhooksPayload = new WebhooksPayload + { + TenantId = tenantId, + Event = name, + CreationTime = DateTime.UtcNow, + Data = JsonSerializer.Serialize(name), + }; + + DbWorker.WriteToJournal(webhooksPayload); + } + } + } + public struct EventName + { + public const string NewUserRegistered = "NewUserRegistered"; + public const string TenantDeleted = "TenantDeleted"; + } +} diff --git a/common/ASC.Webhooks/WebhookSender.cs b/common/ASC.Webhooks/WebhookSender.cs new file mode 100644 index 0000000000..5f8925c773 --- /dev/null +++ b/common/ASC.Webhooks/WebhookSender.cs @@ -0,0 +1,66 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Text.Json; + +using ASC.Common; +using ASC.Core; + +namespace ASC.Webhooks +{ + [Scope] + public class WebhookSender + { + private DbWorker DbWorker { get; } + private TenantManager TenantManager { get; } + public WebhookSender(DbWorker dbWorker, TenantManager tenantManager) + { + DbWorker = dbWorker; + TenantManager = tenantManager; + } + + public bool Send(EventName eventName) + { + var tenantId = TenantManager.GetCurrentTenant().TenantId; + var requestURIList = DbWorker.GetWebhookUri(tenantId); + foreach (var requestUrl in requestURIList) + { + try + { + var webRequest = WebRequest.Create(requestUrl); + webRequest.Method = "POST"; + webRequest.ContentType = "application/json"; + webRequest.Headers.Add("Secret", GetSecret("secretKey")); + + var data = JsonSerializer.Serialize(eventName); + + var encoding = new UTF8Encoding(); + byte[] bytes = encoding.GetBytes(data); + webRequest.ContentLength = bytes.Length; + using (var writeStream = webRequest.GetRequestStream()) + { + writeStream.Write(bytes, 0, bytes.Length); + } + + using (var webResponse = webRequest.GetResponse()) + using (var reader = new StreamReader(webResponse.GetResponseStream())) + { + string responseFromServer = reader.ReadToEnd(); + return true; + } + } + catch (Exception ex) + { + continue; + } + } + return false; + } + + private string GetSecret(string secretKey) + { + return ""; + } + } +}