From 2abeda189edf486e97225b554f6e8ccb9ac32e47 Mon Sep 17 00:00:00 2001 From: dorthl Date: Fri, 14 Apr 2023 14:52:42 +0800 Subject: [PATCH 001/248] Bump to .net 7.0 --- .gitignore | 2 ++ Blogifier.sln | 5 +++-- src/Blogifier.Admin/Blogifier.Admin.csproj | 14 ++++++------- src/Blogifier.Core/Blogifier.Core.csproj | 22 ++++++++++---------- src/Blogifier.Shared/Blogifier.Shared.csproj | 4 ++-- src/Blogifier/Blogifier.csproj | 8 +++---- src/Blogifier/Properties/launchSettings.json | 4 ++-- tests/Blogifier.Tests/Blogifier.Tests.csproj | 10 ++++----- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 9b70681f6..dc8e74502 100644 --- a/.gitignore +++ b/.gitignore @@ -350,3 +350,5 @@ MigrationBackup/ .ionide/ .DS_Store +Blog.db-shm +Blog.db-wal diff --git a/Blogifier.sln b/Blogifier.sln index e10a69835..dd57848e3 100644 --- a/Blogifier.sln +++ b/Blogifier.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.0.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 MinimumVisualStudioVersion = 16.0.0.0 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blogifier", "src\Blogifier\Blogifier.csproj", "{30113938-1040-459A-A0B6-3663E9534C8B}" EndProject @@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{512E41FF-2 docs\04-Localization.md = docs\04-Localization.md docs\05-Emails.md = docs\05-Emails.md docs\06-Newsletters.md = docs\06-Newsletters.md + README.md = README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{8DDBCDEC-BFD8-4737-93BD-5259C3AE9CAE}" diff --git a/src/Blogifier.Admin/Blogifier.Admin.csproj b/src/Blogifier.Admin/Blogifier.Admin.csproj index a6a78d806..d4636eaa2 100644 --- a/src/Blogifier.Admin/Blogifier.Admin.csproj +++ b/src/Blogifier.Admin/Blogifier.Admin.csproj @@ -1,16 +1,16 @@ - net6.0 + net7.0 - + - - - + + + - - + + diff --git a/src/Blogifier.Core/Blogifier.Core.csproj b/src/Blogifier.Core/Blogifier.Core.csproj index cf64daf5e..682e21f3d 100644 --- a/src/Blogifier.Core/Blogifier.Core.csproj +++ b/src/Blogifier.Core/Blogifier.Core.csproj @@ -1,7 +1,7 @@ - net6.0 + net7.0 3.0.0.0 blogifierdotnet Blogifier is an open-source publishing platform Written in ASP.NET and Blazor WebAssembly. @@ -12,21 +12,21 @@ - - - + + + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/src/Blogifier.Shared/Blogifier.Shared.csproj b/src/Blogifier.Shared/Blogifier.Shared.csproj index eca93f3c6..c30f9f412 100644 --- a/src/Blogifier.Shared/Blogifier.Shared.csproj +++ b/src/Blogifier.Shared/Blogifier.Shared.csproj @@ -1,11 +1,11 @@ - net6.0 + net7.0 - + diff --git a/src/Blogifier/Blogifier.csproj b/src/Blogifier/Blogifier.csproj index e463cd6ba..95ad2e8e9 100644 --- a/src/Blogifier/Blogifier.csproj +++ b/src/Blogifier/Blogifier.csproj @@ -1,19 +1,19 @@  - net6.0 + net7.0 true - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Blogifier/Properties/launchSettings.json b/src/Blogifier/Properties/launchSettings.json index b7852472e..d6b5230fc 100644 --- a/src/Blogifier/Properties/launchSettings.json +++ b/src/Blogifier/Properties/launchSettings.json @@ -10,7 +10,7 @@ "profiles": { "IIS Express": { "commandName": "IISExpress", - "launchBrowser": true, + "launchBrowser": false, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" @@ -19,7 +19,7 @@ "Blogifier": { "commandName": "Project", "dotnetRunMessages": "true", - "launchBrowser": true, + "launchBrowser": false, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "applicationUrl": "http://localhost:5000", "environmentVariables": { diff --git a/tests/Blogifier.Tests/Blogifier.Tests.csproj b/tests/Blogifier.Tests/Blogifier.Tests.csproj index d0116a81f..7f8b84df7 100644 --- a/tests/Blogifier.Tests/Blogifier.Tests.csproj +++ b/tests/Blogifier.Tests/Blogifier.Tests.csproj @@ -1,17 +1,17 @@ - net6.0 + net7.0 - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From ccc82985b235d10d202452984d563ea46730c4f5 Mon Sep 17 00:00:00 2001 From: dorthl Date: Fri, 14 Apr 2023 16:18:58 +0800 Subject: [PATCH 002/248] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Blogifier.sln | 1 + src/Blogifier.Core/Blogifier.Core.csproj | 4 - src/Blogifier.Core/Data/AppDbContext.cs | 22 -- .../Data/Migrations/20210404234633_Init.cs | 280 --------------- ...ner.cs => 20230414081641_Init.Designer.cs} | 180 +++++----- .../Data/Migrations/20230414081641_Init.cs | 336 ++++++++++++++++++ .../Migrations/AppDbContextModelSnapshot.cs | 177 ++++----- .../Extensions/ServiceCollectionExtensions.cs | 92 +++-- .../Providers/AuthorProvider.cs | 1 - src/Blogifier.Shared/Domain/Author.cs | 51 +-- src/Blogifier.Shared/Domain/Blog.cs | 12 +- src/Blogifier.Shared/Domain/Category.cs | 24 +- src/Blogifier.Shared/Domain/MailSetting.cs | 15 +- src/Blogifier.Shared/Domain/Newsletter.cs | 13 +- src/Blogifier.Shared/Domain/Post.cs | 13 +- src/Blogifier.Shared/Domain/Subscriber.cs | 15 +- src/Blogifier/Program.cs | 61 ++-- src/Blogifier/Startup.cs | 7 +- src/Blogifier/appsettings.json | 14 +- 19 files changed, 673 insertions(+), 645 deletions(-) delete mode 100644 src/Blogifier.Core/Data/Migrations/20210404234633_Init.cs rename src/Blogifier.Core/Data/Migrations/{20210404234633_Init.Designer.cs => 20230414081641_Init.Designer.cs} (72%) create mode 100644 src/Blogifier.Core/Data/Migrations/20230414081641_Init.cs diff --git a/Blogifier.sln b/Blogifier.sln index dd57848e3..77af191d5 100644 --- a/Blogifier.sln +++ b/Blogifier.sln @@ -32,6 +32,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "data", "data", "{84FCDE15-5 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "items", "items", "{D2E9C8BA-AC43-4A35-88D9-8D63D26884B8}" ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore Dockerfile = Dockerfile EndProjectSection EndProject diff --git a/src/Blogifier.Core/Blogifier.Core.csproj b/src/Blogifier.Core/Blogifier.Core.csproj index 682e21f3d..0a6b68e08 100644 --- a/src/Blogifier.Core/Blogifier.Core.csproj +++ b/src/Blogifier.Core/Blogifier.Core.csproj @@ -33,8 +33,4 @@ - - - - diff --git a/src/Blogifier.Core/Data/AppDbContext.cs b/src/Blogifier.Core/Data/AppDbContext.cs index a9e0f4c5a..d51d880dd 100644 --- a/src/Blogifier.Core/Data/AppDbContext.cs +++ b/src/Blogifier.Core/Data/AppDbContext.cs @@ -36,28 +36,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasOne(pt => pt.Category) .WithMany(t => t.PostCategories) .HasForeignKey(pt => pt.CategoryId); - - string sql = "getdate()"; - - if (_options.Extensions != null) - { - foreach (var ext in _options.Extensions) - { - if (ext.GetType().ToString().StartsWith("Microsoft.EntityFrameworkCore.Sqlite")) - { - sql = "DATE('now')"; - break; - } - } - } - - modelBuilder.Entity().Property(b => b.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(p => p.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(a => a.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(c => c.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(s => s.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(n => n.DateUpdated).HasDefaultValueSql(sql); - modelBuilder.Entity().Property(n => n.DateUpdated).HasDefaultValueSql(sql); } } } diff --git a/src/Blogifier.Core/Data/Migrations/20210404234633_Init.cs b/src/Blogifier.Core/Data/Migrations/20210404234633_Init.cs deleted file mode 100644 index 0e46d99cb..000000000 --- a/src/Blogifier.Core/Data/Migrations/20210404234633_Init.cs +++ /dev/null @@ -1,280 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Blogifier.Core.Data.Migrations -{ - public partial class Init : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Blogs", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Title = table.Column(type: "TEXT", maxLength: 160, nullable: true), - Description = table.Column(type: "TEXT", maxLength: 450, nullable: true), - Theme = table.Column(type: "TEXT", maxLength: 160, nullable: true), - IncludeFeatured = table.Column(type: "INTEGER", nullable: false), - ItemsPerPage = table.Column(type: "INTEGER", nullable: false), - Cover = table.Column(type: "TEXT", maxLength: 160, nullable: true), - Logo = table.Column(type: "TEXT", maxLength: 160, nullable: true), - HeaderScript = table.Column(type: "TEXT", maxLength: 2000, nullable: true), - FooterScript = table.Column(type: "TEXT", maxLength: 2000, nullable: true), - AnalyticsListType = table.Column(type: "INTEGER", nullable: false), - AnalyticsPeriod = table.Column(type: "INTEGER", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')") - }, - constraints: table => - { - table.PrimaryKey("PK_Blogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Categories", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Content = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Description = table.Column(type: "TEXT", maxLength: 255, nullable: true), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')") - }, - constraints: table => - { - table.PrimaryKey("PK_Categories", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Authors", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Email = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Password = table.Column(type: "TEXT", maxLength: 160, nullable: false), - DisplayName = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Bio = table.Column(type: "TEXT", maxLength: 2000, nullable: true), - Avatar = table.Column(type: "TEXT", maxLength: 400, nullable: true), - IsAdmin = table.Column(type: "INTEGER", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')"), - BlogId = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Authors", x => x.Id); - table.ForeignKey( - name: "FK_Authors_Blogs_BlogId", - column: x => x.BlogId, - principalTable: "Blogs", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "MailSettings", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Host = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Port = table.Column(type: "INTEGER", nullable: false), - UserEmail = table.Column(type: "TEXT", maxLength: 120, nullable: false), - UserPassword = table.Column(type: "TEXT", maxLength: 120, nullable: false), - FromName = table.Column(type: "TEXT", maxLength: 120, nullable: false), - FromEmail = table.Column(type: "TEXT", maxLength: 120, nullable: false), - ToName = table.Column(type: "TEXT", maxLength: 120, nullable: false), - Enabled = table.Column(type: "INTEGER", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')"), - BlogId = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_MailSettings", x => x.Id); - table.ForeignKey( - name: "FK_MailSettings_Blogs_BlogId", - column: x => x.BlogId, - principalTable: "Blogs", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Subscribers", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Email = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Ip = table.Column(type: "TEXT", maxLength: 80, nullable: true), - Country = table.Column(type: "TEXT", maxLength: 120, nullable: true), - Region = table.Column(type: "TEXT", maxLength: 120, nullable: true), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')"), - BlogId = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Subscribers", x => x.Id); - table.ForeignKey( - name: "FK_Subscribers_Blogs_BlogId", - column: x => x.BlogId, - principalTable: "Blogs", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Posts", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AuthorId = table.Column(type: "INTEGER", nullable: false), - PostType = table.Column(type: "INTEGER", nullable: false), - Title = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Slug = table.Column(type: "TEXT", maxLength: 160, nullable: false), - Description = table.Column(type: "TEXT", maxLength: 450, nullable: false), - Content = table.Column(type: "TEXT", nullable: false), - Cover = table.Column(type: "TEXT", maxLength: 160, nullable: true), - PostViews = table.Column(type: "INTEGER", nullable: false), - Rating = table.Column(type: "REAL", nullable: false), - IsFeatured = table.Column(type: "INTEGER", nullable: false), - Selected = table.Column(type: "INTEGER", nullable: false), - Published = table.Column(type: "TEXT", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')"), - BlogId = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Posts", x => x.Id); - table.ForeignKey( - name: "FK_Posts_Authors_AuthorId", - column: x => x.AuthorId, - principalTable: "Authors", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Posts_Blogs_BlogId", - column: x => x.BlogId, - principalTable: "Blogs", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Newsletters", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - PostId = table.Column(type: "INTEGER", nullable: false), - Success = table.Column(type: "INTEGER", nullable: false), - DateCreated = table.Column(type: "TEXT", nullable: false), - DateUpdated = table.Column(type: "TEXT", nullable: false, defaultValueSql: "DATE('now')") - }, - constraints: table => - { - table.PrimaryKey("PK_Newsletters", x => x.Id); - table.ForeignKey( - name: "FK_Newsletters_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "PostCategories", - columns: table => new - { - PostId = table.Column(type: "INTEGER", nullable: false), - CategoryId = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_PostCategories", x => new { x.PostId, x.CategoryId }); - table.ForeignKey( - name: "FK_PostCategories_Categories_CategoryId", - column: x => x.CategoryId, - principalTable: "Categories", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_PostCategories_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_Authors_BlogId", - table: "Authors", - column: "BlogId"); - - migrationBuilder.CreateIndex( - name: "IX_MailSettings_BlogId", - table: "MailSettings", - column: "BlogId"); - - migrationBuilder.CreateIndex( - name: "IX_Newsletters_PostId", - table: "Newsletters", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_PostCategories_CategoryId", - table: "PostCategories", - column: "CategoryId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_AuthorId", - table: "Posts", - column: "AuthorId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_BlogId", - table: "Posts", - column: "BlogId"); - - migrationBuilder.CreateIndex( - name: "IX_Subscribers_BlogId", - table: "Subscribers", - column: "BlogId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "MailSettings"); - - migrationBuilder.DropTable( - name: "Newsletters"); - - migrationBuilder.DropTable( - name: "PostCategories"); - - migrationBuilder.DropTable( - name: "Subscribers"); - - migrationBuilder.DropTable( - name: "Categories"); - - migrationBuilder.DropTable( - name: "Posts"); - - migrationBuilder.DropTable( - name: "Authors"); - - migrationBuilder.DropTable( - name: "Blogs"); - } - } -} diff --git a/src/Blogifier.Core/Data/Migrations/20210404234633_Init.Designer.cs b/src/Blogifier.Core/Data/Migrations/20230414081641_Init.Designer.cs similarity index 72% rename from src/Blogifier.Core/Data/Migrations/20210404234633_Init.Designer.cs rename to src/Blogifier.Core/Data/Migrations/20230414081641_Init.Designer.cs index 5220e37c2..4b73e9499 100644 --- a/src/Blogifier.Core/Data/Migrations/20210404234633_Init.Designer.cs +++ b/src/Blogifier.Core/Data/Migrations/20230414081641_Init.Designer.cs @@ -6,60 +6,64 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace Blogifier.Core.Data.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20210404234633_Init")] + [Migration("20230414081641_Init")] partial class Init { + /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "5.0.1"); + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Blogifier.Shared.Author", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Avatar") .HasMaxLength(400) - .HasColumnType("TEXT"); + .HasColumnType("varchar(400)"); b.Property("Bio") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Email") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("IsAdmin") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("Password") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -72,55 +76,55 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AnalyticsListType") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AnalyticsPeriod") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Cover") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .HasMaxLength(450) - .HasColumnType("TEXT"); + .HasColumnType("varchar(450)"); b.Property("FooterScript") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("HeaderScript") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("IncludeFeatured") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("ItemsPerPage") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Logo") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Theme") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Title") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -131,24 +135,24 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Content") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .HasMaxLength(255) - .HasColumnType("TEXT"); + .HasColumnType("varchar(255)"); b.HasKey("Id"); @@ -159,54 +163,54 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Enabled") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("FromEmail") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("FromName") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("Host") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Port") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("ToName") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("UserEmail") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("UserPassword") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.HasKey("Id"); @@ -219,21 +223,21 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("PostId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Success") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.HasKey("Id"); @@ -246,62 +250,62 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AuthorId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Content") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("longtext"); b.Property("Cover") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .IsRequired() .HasMaxLength(450) - .HasColumnType("TEXT"); + .HasColumnType("varchar(450)"); b.Property("IsFeatured") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("PostType") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("PostViews") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Published") - .HasColumnType("TEXT"); + .HasColumnType("datetime(6)"); b.Property("Rating") - .HasColumnType("REAL"); + .HasColumnType("double"); b.Property("Selected") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("Slug") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Title") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -315,10 +319,10 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("Blogifier.Shared.PostCategory", b => { b.Property("PostId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("CategoryId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.HasKey("PostId", "CategoryId"); @@ -331,35 +335,35 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Country") .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Email") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Ip") .HasMaxLength(80) - .HasColumnType("TEXT"); + .HasColumnType("varchar(80)"); b.Property("Region") .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.HasKey("Id"); diff --git a/src/Blogifier.Core/Data/Migrations/20230414081641_Init.cs b/src/Blogifier.Core/Data/Migrations/20230414081641_Init.cs new file mode 100644 index 000000000..156389798 --- /dev/null +++ b/src/Blogifier.Core/Data/Migrations/20230414081641_Init.cs @@ -0,0 +1,336 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Blogifier.Core.Data.Migrations +{ + /// + public partial class Init : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterDatabase() + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Blogs", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Title = table.Column(type: "varchar(160)", maxLength: 160, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "varchar(450)", maxLength: 450, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Theme = table.Column(type: "varchar(160)", maxLength: 160, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + IncludeFeatured = table.Column(type: "tinyint(1)", nullable: false), + ItemsPerPage = table.Column(type: "int", nullable: false), + Cover = table.Column(type: "varchar(160)", maxLength: 160, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Logo = table.Column(type: "varchar(160)", maxLength: 160, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + HeaderScript = table.Column(type: "varchar(2000)", maxLength: 2000, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + FooterScript = table.Column(type: "varchar(2000)", maxLength: 2000, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + AnalyticsListType = table.Column(type: "int", nullable: false), + AnalyticsPeriod = table.Column(type: "int", nullable: false), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn) + }, + constraints: table => + { + table.PrimaryKey("PK_Blogs", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Categories", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Content = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "varchar(255)", maxLength: 255, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn) + }, + constraints: table => + { + table.PrimaryKey("PK_Categories", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Authors", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Email = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Password = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Bio = table.Column(type: "varchar(2000)", maxLength: 2000, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Avatar = table.Column(type: "varchar(400)", maxLength: 400, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + IsAdmin = table.Column(type: "tinyint(1)", nullable: false), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn), + BlogId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Authors", x => x.Id); + table.ForeignKey( + name: "FK_Authors_Blogs_BlogId", + column: x => x.BlogId, + principalTable: "Blogs", + principalColumn: "Id"); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "MailSettings", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Host = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Port = table.Column(type: "int", nullable: false), + UserEmail = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + UserPassword = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + FromName = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + FromEmail = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ToName = table.Column(type: "varchar(120)", maxLength: 120, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Enabled = table.Column(type: "tinyint(1)", nullable: false), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn), + BlogId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_MailSettings", x => x.Id); + table.ForeignKey( + name: "FK_MailSettings_Blogs_BlogId", + column: x => x.BlogId, + principalTable: "Blogs", + principalColumn: "Id"); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Subscribers", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Email = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Ip = table.Column(type: "varchar(80)", maxLength: 80, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Country = table.Column(type: "varchar(120)", maxLength: 120, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Region = table.Column(type: "varchar(120)", maxLength: 120, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn), + BlogId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Subscribers", x => x.Id); + table.ForeignKey( + name: "FK_Subscribers_Blogs_BlogId", + column: x => x.BlogId, + principalTable: "Blogs", + principalColumn: "Id"); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Posts", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + AuthorId = table.Column(type: "int", nullable: false), + PostType = table.Column(type: "int", nullable: false), + Title = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Slug = table.Column(type: "varchar(160)", maxLength: 160, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "varchar(450)", maxLength: 450, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Content = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Cover = table.Column(type: "varchar(160)", maxLength: 160, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + PostViews = table.Column(type: "int", nullable: false), + Rating = table.Column(type: "double", nullable: false), + IsFeatured = table.Column(type: "tinyint(1)", nullable: false), + Selected = table.Column(type: "tinyint(1)", nullable: false), + Published = table.Column(type: "datetime(6)", nullable: false), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn), + BlogId = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Posts", x => x.Id); + table.ForeignKey( + name: "FK_Posts_Authors_AuthorId", + column: x => x.AuthorId, + principalTable: "Authors", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Posts_Blogs_BlogId", + column: x => x.BlogId, + principalTable: "Blogs", + principalColumn: "Id"); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "Newsletters", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + PostId = table.Column(type: "int", nullable: false), + Success = table.Column(type: "tinyint(1)", nullable: false), + DateCreated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + DateUpdated = table.Column(type: "datetime(6)", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn) + }, + constraints: table => + { + table.PrimaryKey("PK_Newsletters", x => x.Id); + table.ForeignKey( + name: "FK_Newsletters_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "PostCategories", + columns: table => new + { + PostId = table.Column(type: "int", nullable: false), + CategoryId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PostCategories", x => new { x.PostId, x.CategoryId }); + table.ForeignKey( + name: "FK_PostCategories_Categories_CategoryId", + column: x => x.CategoryId, + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_PostCategories_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_Authors_BlogId", + table: "Authors", + column: "BlogId"); + + migrationBuilder.CreateIndex( + name: "IX_MailSettings_BlogId", + table: "MailSettings", + column: "BlogId"); + + migrationBuilder.CreateIndex( + name: "IX_Newsletters_PostId", + table: "Newsletters", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_PostCategories_CategoryId", + table: "PostCategories", + column: "CategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_AuthorId", + table: "Posts", + column: "AuthorId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_BlogId", + table: "Posts", + column: "BlogId"); + + migrationBuilder.CreateIndex( + name: "IX_Subscribers_BlogId", + table: "Subscribers", + column: "BlogId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "MailSettings"); + + migrationBuilder.DropTable( + name: "Newsletters"); + + migrationBuilder.DropTable( + name: "PostCategories"); + + migrationBuilder.DropTable( + name: "Subscribers"); + + migrationBuilder.DropTable( + name: "Categories"); + + migrationBuilder.DropTable( + name: "Posts"); + + migrationBuilder.DropTable( + name: "Authors"); + + migrationBuilder.DropTable( + name: "Blogs"); + } + } +} diff --git a/src/Blogifier.Core/Data/Migrations/AppDbContextModelSnapshot.cs b/src/Blogifier.Core/Data/Migrations/AppDbContextModelSnapshot.cs index 1c56d30ec..b524a4e52 100644 --- a/src/Blogifier.Core/Data/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Blogifier.Core/Data/Migrations/AppDbContextModelSnapshot.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace Blogifier.Core.Data.Migrations { [DbContext(typeof(AppDbContext))] @@ -14,50 +16,51 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "5.0.1"); + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Blogifier.Shared.Author", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Avatar") .HasMaxLength(400) - .HasColumnType("TEXT"); + .HasColumnType("varchar(400)"); b.Property("Bio") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("DisplayName") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Email") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("IsAdmin") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("Password") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -70,55 +73,55 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AnalyticsListType") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AnalyticsPeriod") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Cover") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .HasMaxLength(450) - .HasColumnType("TEXT"); + .HasColumnType("varchar(450)"); b.Property("FooterScript") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("HeaderScript") .HasMaxLength(2000) - .HasColumnType("TEXT"); + .HasColumnType("varchar(2000)"); b.Property("IncludeFeatured") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("ItemsPerPage") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Logo") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Theme") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Title") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -129,24 +132,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Content") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .HasMaxLength(255) - .HasColumnType("TEXT"); + .HasColumnType("varchar(255)"); b.HasKey("Id"); @@ -157,54 +160,54 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Enabled") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("FromEmail") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("FromName") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("Host") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Port") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("ToName") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("UserEmail") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("UserPassword") .IsRequired() .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.HasKey("Id"); @@ -217,21 +220,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("PostId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Success") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.HasKey("Id"); @@ -244,62 +247,62 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("AuthorId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Content") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("longtext"); b.Property("Cover") .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Description") .IsRequired() .HasMaxLength(450) - .HasColumnType("TEXT"); + .HasColumnType("varchar(450)"); b.Property("IsFeatured") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("PostType") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("PostViews") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Published") - .HasColumnType("TEXT"); + .HasColumnType("datetime(6)"); b.Property("Rating") - .HasColumnType("REAL"); + .HasColumnType("double"); b.Property("Selected") - .HasColumnType("INTEGER"); + .HasColumnType("tinyint(1)"); b.Property("Slug") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Title") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.HasKey("Id"); @@ -313,10 +316,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Blogifier.Shared.PostCategory", b => { b.Property("PostId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("CategoryId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.HasKey("PostId", "CategoryId"); @@ -329,35 +332,35 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("BlogId") - .HasColumnType("INTEGER"); + .HasColumnType("int"); b.Property("Country") .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.Property("DateCreated") - .HasColumnType("TEXT"); + .ValueGeneratedOnAdd() + .HasColumnType("datetime(6)"); b.Property("DateUpdated") - .ValueGeneratedOnAdd() - .HasColumnType("TEXT") - .HasDefaultValueSql("DATE('now')"); + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("datetime(6)"); b.Property("Email") .IsRequired() .HasMaxLength(160) - .HasColumnType("TEXT"); + .HasColumnType("varchar(160)"); b.Property("Ip") .HasMaxLength(80) - .HasColumnType("TEXT"); + .HasColumnType("varchar(80)"); b.Property("Region") .HasMaxLength(120) - .HasColumnType("TEXT"); + .HasColumnType("varchar(120)"); b.HasKey("Id"); diff --git a/src/Blogifier.Core/Extensions/ServiceCollectionExtensions.cs b/src/Blogifier.Core/Extensions/ServiceCollectionExtensions.cs index 00c002d95..09767e114 100644 --- a/src/Blogifier.Core/Extensions/ServiceCollectionExtensions.cs +++ b/src/Blogifier.Core/Extensions/ServiceCollectionExtensions.cs @@ -3,58 +3,48 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Pomelo.EntityFrameworkCore.MySql.Infrastructure; -using System; namespace Blogifier.Core.Extensions { - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddBlogDatabase(this IServiceCollection services, IConfiguration configuration) - { - var section = configuration.GetSection("Blogifier"); - var conn = section.GetValue("ConnString"); - - if (section.GetValue("DbProvider") == "SQLite") - services.AddDbContext(o => o.UseSqlite(conn)); - - if (section.GetValue("DbProvider") == "SqlServer") - services.AddDbContext(o => o.UseSqlServer(conn)); - - if (section.GetValue("DbProvider") == "Postgres") - services.AddDbContext(o => o.UseNpgsql(conn)); - - //TODO: this is not tested - if (section.GetValue("DbProvider") == "MySql") - { - //services.AddDbContextPool( - // dbContextOptions => dbContextOptions.UseMySql( - // section.GetValue("ConnString"), - // new MySqlServerVersion(new Version(8, 0, 21)), - // mySqlOptions => mySqlOptions.HasCharSet("utf8mb4", DelegationModes.ApplyToAll) //CharSetBehavior(CharSetBehavior.NeverAppend) - // ) - //); - } - services.AddDatabaseDeveloperPageExceptionFilter(); - return services; - } - - public static IServiceCollection AddBlogProviders(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - return services; - } - } + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddBlogDatabase(this IServiceCollection services, IConfiguration configuration) + { + var section = configuration.GetSection("Blogifier"); + var conn = section.GetValue("ConnString"); + + if (section.GetValue("DbProvider") == "SQLite") + services.AddDbContext(o => o.UseSqlite(conn)); + + if (section.GetValue("DbProvider") == "SqlServer") + services.AddDbContext(o => o.UseSqlServer(conn)); + + if (section.GetValue("DbProvider") == "Postgres") + services.AddDbContext(o => o.UseNpgsql(conn)); + + if (section.GetValue("DbProvider") == "MySql") + services.AddDbContext(o => o.UseMySql(conn, ServerVersion.AutoDetect(conn))); + + services.AddDatabaseDeveloperPageExceptionFilter(); + return services; + } + + public static IServiceCollection AddBlogProviders(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + return services; + } + } } diff --git a/src/Blogifier.Core/Providers/AuthorProvider.cs b/src/Blogifier.Core/Providers/AuthorProvider.cs index 180eb480f..9c8d8f3d4 100644 --- a/src/Blogifier.Core/Providers/AuthorProvider.cs +++ b/src/Blogifier.Core/Providers/AuthorProvider.cs @@ -85,7 +85,6 @@ public async Task Register(RegisterModel model) Description = "Short Blog Description", Theme = "Standard", ItemsPerPage = 10, - DateCreated = DateTime.UtcNow }; _db.Blogs.Add(blog); diff --git a/src/Blogifier.Shared/Domain/Author.cs b/src/Blogifier.Shared/Domain/Author.cs index dc213f63c..94a012bdb 100644 --- a/src/Blogifier.Shared/Domain/Author.cs +++ b/src/Blogifier.Shared/Domain/Author.cs @@ -1,34 +1,35 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { - public class Author - { - public Author() { } + public class Author + { + public Author() { } - public int Id { get; set; } + public int Id { get; set; } - [Required] - [EmailAddress] - [StringLength(160)] - public string Email { get; set; } - [Required] - [StringLength(160)] - public string Password { get; set; } - [Required] - [StringLength(160)] - public string DisplayName { get; set; } - [StringLength(2000)] - public string Bio { get; set; } - [StringLength(400)] - public string Avatar { get; set; } - public bool IsAdmin { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - - public List Posts { get; set; } - } + [Required] + [EmailAddress] + [StringLength(160)] + public string Email { get; set; } + [Required] + [StringLength(160)] + public string Password { get; set; } + [Required] + [StringLength(160)] + public string DisplayName { get; set; } + [StringLength(2000)] + public string Bio { get; set; } + [StringLength(400)] + public string Avatar { get; set; } + public bool IsAdmin { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } + public List Posts { get; set; } + } } diff --git a/src/Blogifier.Shared/Domain/Blog.cs b/src/Blogifier.Shared/Domain/Blog.cs index 35cc661b8..1a75aca2c 100644 --- a/src/Blogifier.Shared/Domain/Blog.cs +++ b/src/Blogifier.Shared/Domain/Blog.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { - public class Blog + public class Blog { public int Id { get; set; } [StringLength(160)] @@ -23,13 +24,12 @@ public class Blog public string HeaderScript { get; set; } [StringLength(2000)] public string FooterScript { get; set; } - public int AnalyticsListType { get; set; } public int AnalyticsPeriod { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } public List Posts { get; set; } public List Authors { get; set; } } diff --git a/src/Blogifier.Shared/Domain/Category.cs b/src/Blogifier.Shared/Domain/Category.cs index 8434e3278..824c0a02b 100644 --- a/src/Blogifier.Shared/Domain/Category.cs +++ b/src/Blogifier.Shared/Domain/Category.cs @@ -1,23 +1,23 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { - public class Category - { - public Category() { } - - public int Id { get; set; } - [Required] - [StringLength(120)] - public string Content { get; set; } + public class Category + { + public Category() { } + public int Id { get; set; } + [Required] + [StringLength(120)] + public string Content { get; set; } [StringLength(255)] public string Description { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } public List PostCategories { get; set; } } } diff --git a/src/Blogifier.Shared/Domain/MailSetting.cs b/src/Blogifier.Shared/Domain/MailSetting.cs index dfb6556c4..5a2c65f6f 100644 --- a/src/Blogifier.Shared/Domain/MailSetting.cs +++ b/src/Blogifier.Shared/Domain/MailSetting.cs @@ -1,12 +1,12 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { public class MailSetting { public int Id { get; set; } - [Required] [StringLength(160)] public string Host { get; set; } @@ -18,7 +18,6 @@ public class MailSetting [Required] [StringLength(120)] public string UserPassword { get; set; } - [Required] [StringLength(120)] public string FromName { get; set; } @@ -30,10 +29,10 @@ public class MailSetting [StringLength(120)] public string ToName { get; set; } public bool Enabled { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - - public Blog Blog { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } + public Blog Blog { get; set; } } } diff --git a/src/Blogifier.Shared/Domain/Newsletter.cs b/src/Blogifier.Shared/Domain/Newsletter.cs index 983f536b9..811410437 100644 --- a/src/Blogifier.Shared/Domain/Newsletter.cs +++ b/src/Blogifier.Shared/Domain/Newsletter.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { @@ -7,10 +8,10 @@ public class Newsletter public int Id { get; set; } public int PostId { get; set; } public bool Success { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - - public Post Post { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } + public Post Post { get; set; } } } diff --git a/src/Blogifier.Shared/Domain/Post.cs b/src/Blogifier.Shared/Domain/Post.cs index eac93ed5f..d8695ca3f 100644 --- a/src/Blogifier.Shared/Domain/Post.cs +++ b/src/Blogifier.Shared/Domain/Post.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { - public class Post + public class Post { public Post() { } @@ -30,12 +31,12 @@ public Post() { } public double Rating { get; set; } public bool IsFeatured { get; set; } public bool Selected { get; set; } - public DateTime Published { get; set; } - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - - public Blog Blog { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } + public Blog Blog { get; set; } public List PostCategories { get; set; } } } diff --git a/src/Blogifier.Shared/Domain/Subscriber.cs b/src/Blogifier.Shared/Domain/Subscriber.cs index b822f65e8..120f84e9a 100644 --- a/src/Blogifier.Shared/Domain/Subscriber.cs +++ b/src/Blogifier.Shared/Domain/Subscriber.cs @@ -1,14 +1,13 @@ -using System; +using System; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace Blogifier.Shared { public class Subscriber { public Subscriber() { } - public int Id { get; set; } - [Required] [EmailAddress] [StringLength(160)] @@ -19,10 +18,10 @@ public Subscriber() { } public string Country { get; set; } [StringLength(120)] public string Region { get; set; } - - public DateTime DateCreated { get; set; } - public DateTime DateUpdated { get; set; } - - public Blog Blog { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public DateTime DateCreated { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Computed)] + public DateTime DateUpdated { get; set; } + public Blog Blog { get; set; } } } diff --git a/src/Blogifier/Program.cs b/src/Blogifier/Program.cs index fdd7af2a4..316d387ea 100644 --- a/src/Blogifier/Program.cs +++ b/src/Blogifier/Program.cs @@ -1,43 +1,46 @@ -using Blogifier.Core.Data; +using Blogifier.Core.Data; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using System; using System.IO; using System.Linq; namespace Blogifier { - public class Program - { - public static void Main(string[] args) - { - var host = CreateHostBuilder(args).Build(); + public class Program + { + public static void Main(string[] args) + { + var host = CreateHostBuilder(args).Build(); - using (var scope = host.Services.CreateScope()) - { - var services = scope.ServiceProvider; - var dbContext = services.GetRequiredService(); + using (var scope = host.Services.CreateScope()) + { + var services = scope.ServiceProvider; + var dbContext = services.GetRequiredService(); - try - { - if (dbContext.Database.GetPendingMigrations().Any()) - dbContext.Database.Migrate(); - } - catch { } - } + try + { + if (dbContext.Database.GetPendingMigrations().Any()) + dbContext.Database.Migrate(); + } + catch (Exception ex) + { + } + } - host.Run(); - } + host.Run(); + } - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder - .UseContentRoot(Directory.GetCurrentDirectory()) - .UseIISIntegration() - .UseStartup(); - }); - } + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup(); + }); + } } diff --git a/src/Blogifier/Startup.cs b/src/Blogifier/Startup.cs index 9ed638358..24b4d3944 100644 --- a/src/Blogifier/Startup.cs +++ b/src/Blogifier/Startup.cs @@ -44,7 +44,7 @@ public void ConfigureServices(IServiceCollection services) services.AddBlogProviders(); - + services.AddControllersWithViews(); services.AddRazorPages(); @@ -75,10 +75,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseEndpoints(endpoints => { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}" - ); + endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); endpoints.MapRazorPages(); endpoints.MapFallbackToFile("admin/{*path:nonfile}", "index.html"); endpoints.MapFallbackToFile("account/{*path:nonfile}", "index.html"); diff --git a/src/Blogifier/appsettings.json b/src/Blogifier/appsettings.json index 3ff95ca99..962298f5d 100644 --- a/src/Blogifier/appsettings.json +++ b/src/Blogifier/appsettings.json @@ -7,11 +7,11 @@ } }, "AllowedHosts": "*", - "Blogifier": { - "DbProvider": "SQLite", - "ConnString": "Data Source=Blog.db", - "Salt": "SECRET-CHANGE-ME!", - "DemoMode": false, - "FileExtensions": "png,gif,jpeg,jpg,zip,7z,pdf,doc,docx,xls,xlsx,mp3,mp4,avi" - } + "Blogifier": { + "DbProvider": "MySql", + "ConnString": "server=8.136.119.251;user=root;password=5ba1c9ba7ca88541aada797c7242c5c4;database=blogifier_dev;", + "Salt": "SECRET-CHANGE-ME!", + "DemoMode": false, + "FileExtensions": "png,gif,jpeg,jpg,zip,7z,pdf,doc,docx,xls,xlsx,mp3,mp4,avi" + } } From f0cd635bf516ecd84c886aaf3fa0edb5cf39a22e Mon Sep 17 00:00:00 2001 From: dorthl Date: Fri, 14 Apr 2023 16:36:47 +0800 Subject: [PATCH 003/248] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Providers/StorageProvider.cs | 659 +++++++++--------- 1 file changed, 329 insertions(+), 330 deletions(-) diff --git a/src/Blogifier.Core/Providers/StorageProvider.cs b/src/Blogifier.Core/Providers/StorageProvider.cs index 8386d7bf7..e58426a3b 100644 --- a/src/Blogifier.Core/Providers/StorageProvider.cs +++ b/src/Blogifier.Core/Providers/StorageProvider.cs @@ -1,343 +1,342 @@ -using Blogifier.Core.Extensions; +using Blogifier.Core.Extensions; using Blogifier.Shared; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; -using System.Net; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; namespace Blogifier.Core.Providers { - public interface IStorageProvider - { - Task> GetThemes(); - bool FileExists(string path); - Task UploadFormFile(IFormFile file, string path = ""); - Task UploadFromWeb(Uri requestUri, string root, string path = ""); - Task UploadBase64Image(string baseImg, string root, string path = ""); - Task GetThemeSettings(string theme); - Task SaveThemeSettings(string theme, ThemeSettings settings); - } - - public class StorageProvider : IStorageProvider - { - private string _storageRoot; - private readonly string _slash = Path.DirectorySeparatorChar.ToString(); - private readonly IConfiguration _configuration; - - public StorageProvider(IConfiguration configuration) - { - _storageRoot = $"{ContentRoot}{_slash}wwwroot{_slash}data{_slash}"; - _configuration = configuration; - } - - public bool FileExists(string path) - { - Serilog.Log.Information($"File exists: {Path.Combine(ContentRoot, path)}"); - return File.Exists(Path.Combine(ContentRoot, path)); - } - - public async Task> GetThemes() - { - var themes = new List(); - var themesDirectory = Path.Combine(ContentRoot, $"Views{_slash}Themes"); - try - { - foreach (string dir in Directory.GetDirectories(themesDirectory)) - { - themes.Add(Path.GetFileName(dir)); - } - } - catch { } - return await Task.FromResult(themes); - } - - public async Task GetThemeSettings(string theme) - { - var settings = new ThemeSettings(); - var fileName = Path.Combine(ContentRoot, $"wwwroot{_slash}themes{_slash}{theme.ToLower()}{_slash}settings.json"); - if (File.Exists(fileName)) - { - try - { - string jsonString = File.ReadAllText(fileName); - settings = JsonSerializer.Deserialize(jsonString); - } - catch (Exception ex) - { - Serilog.Log.Error($"Error reading theme settings: {ex.Message}"); - return null; - } - } - - return await Task.FromResult(settings); - } - - public async Task SaveThemeSettings(string theme, ThemeSettings settings) - { - var fileName = Path.Combine(ContentRoot, $"wwwroot{_slash}themes{_slash}{theme.ToLower()}{_slash}settings.json"); - try - { - if (File.Exists(fileName)) - File.Delete(fileName); - - var options = new JsonSerializerOptions { WriteIndented = true, PropertyNameCaseInsensitive = true }; - - string jsonString = JsonSerializer.Serialize(settings, options); - - using FileStream createStream = File.Create(fileName); - await JsonSerializer.SerializeAsync(createStream, settings, options); - } - catch (Exception ex) - { - Serilog.Log.Error($"Error writing theme settings: {ex.Message}"); - return false; - } - return true; - } - - public async Task UploadFormFile(IFormFile file, string path = "") - { - path = path.Replace("/", _slash); - VerifyPath(path); - - var fileName = GetFileName(file.FileName); - - if(InvalidFileName(fileName)) - { - Serilog.Log.Error($"Invalid file name: {fileName}"); - return false; - } - - var filePath = string.IsNullOrEmpty(path) ? - Path.Combine(_storageRoot, fileName) : - Path.Combine(_storageRoot, path + _slash + fileName); - - Serilog.Log.Information($"Storage root: {_storageRoot}"); - Serilog.Log.Information($"Uploading file: {filePath}"); - try - { - using (var fileStream = new FileStream(filePath, FileMode.Create)) - { - await file.CopyToAsync(fileStream); - Serilog.Log.Information($"Uploaded file: {filePath}"); - } - } - catch (Exception ex) - { - Serilog.Log.Error($"Error uploading file: {ex.Message}"); - } - - return true; - } - - public async Task UploadFromWeb(Uri requestUri, string root, string path = "") - { - path = path.Replace("/", _slash); - VerifyPath(path); - - var fileName = TitleFromUri(requestUri); - var filePath = string.IsNullOrEmpty(path) ? - Path.Combine(_storageRoot, fileName) : - Path.Combine(_storageRoot, path + _slash + fileName); - - HttpClient client = new HttpClient(); - var response = await client.GetAsync(requestUri); - using (var fs = new FileStream(filePath, FileMode.CreateNew)) - { - await response.Content.CopyToAsync(fs); - return await Task.FromResult($"![{fileName}]({root}{PathToUrl(filePath)})"); - } - } - - public async Task UploadBase64Image(string baseImg, string root, string path = "") - { - path = path.Replace("/", _slash); - var fileName = ""; - - VerifyPath(path); - string imgSrc = GetImgSrcValue(baseImg); - - Random rnd = new Random(); - - if (imgSrc.StartsWith("data:image/png;base64,")) - { - fileName = string.Format("{0}.png", rnd.Next(1000, 9999)); - imgSrc = imgSrc.Replace("data:image/png;base64,", ""); - } - if (imgSrc.StartsWith("data:image/jpeg;base64,")) - { - fileName = string.Format("{0}.jpeg", rnd.Next(1000, 9999)); - imgSrc = imgSrc.Replace("data:image/jpeg;base64,", ""); - } - if (imgSrc.StartsWith("data:image/gif;base64,")) - { - fileName = string.Format("{0}.gif", rnd.Next(1000, 9999)); - imgSrc = imgSrc.Replace("data:image/gif;base64,", ""); - } - - var filePath = string.IsNullOrEmpty(path) ? - Path.Combine(_storageRoot, fileName) : - Path.Combine(_storageRoot, path + _slash + fileName); - - await File.WriteAllBytesAsync(filePath, Convert.FromBase64String(imgSrc)); - - return $"![{fileName}]({root}{PathToUrl(filePath)})"; - } - - #region Private members - - private string ContentRoot - { - get - { - string path = Directory.GetCurrentDirectory(); - string testsDirectory = $"tests{_slash}Blogifier.Tests"; - string appDirectory = $"src{_slash}Blogifier"; - - Serilog.Log.Information($"Current directory path: {path}"); - - // development unit test run - if (path.LastIndexOf(testsDirectory) > 0) - { - path = path.Substring(0, path.LastIndexOf(testsDirectory)); - Serilog.Log.Information($"Unit test path: {path}src{_slash}Blogifier"); - return $"{path}src{_slash}Blogifier"; - } - - // this needed to make sure we have correct data directory - // when running in debug mode in Visual Studio - // so instead of debug (src/Blogifier/bin/Debug..) - // will be used src/Blogifier/wwwroot/data - // !! this can mess up installs that have "src/Blogifier" in the path !! - if (path.LastIndexOf(appDirectory) > 0) - { - path = path.Substring(0, path.LastIndexOf(appDirectory)); - Serilog.Log.Information($"Development debug path: {path}src{_slash}Blogifier"); - return $"{path}src{_slash}Blogifier"; - } - Serilog.Log.Information($"Final path: {path}"); - return path; - } - } - - string GetFileName(string fileName) - { - // some browsers pass uploaded file name as short file name - // and others include the path; remove path part if needed - if (fileName.Contains(_slash)) - { - fileName = fileName.Substring(fileName.LastIndexOf(_slash)); - fileName = fileName.Replace(_slash, ""); - } - // when drag-and-drop or copy image to TinyMce editor - // it uses "mceclip0" as file name; randomize it for multiple uploads - if (fileName.StartsWith("mceclip0")) - { - Random rnd = new Random(); - fileName = fileName.Replace("mceclip0", rnd.Next(100000, 999999).ToString()); - } - return fileName. SanitizePath(); - } - - void VerifyPath(string path) - { - path = path.SanitizePath(); - - if (!string.IsNullOrEmpty(path)) - { - var dir = Path.Combine(_storageRoot, path); - - if (!Directory.Exists(dir)) - { - Directory.CreateDirectory(dir); - } - } - } - - string TitleFromUri(Uri uri) - { - var title = uri.ToString().ToLower(); - title = title.Replace("%2f", "/"); - - if (title.EndsWith(".axdx")) - { - title = title.Replace(".axdx", ""); - } - if (title.Contains("image.axd?picture=")) - { - title = title.Substring(title.IndexOf("image.axd?picture=") + 18); - } - if (title.Contains("file.axd?file=")) - { - title = title.Substring(title.IndexOf("file.axd?file=") + 14); - } - if (title.Contains("encrypted-tbn") || title.Contains("base64,")) - { - Random rnd = new Random(); - title = string.Format("{0}.png", rnd.Next(1000, 9999)); - } - - if (title.Contains("/")) - { - title = title.Substring(title.LastIndexOf("/")); - } - - title = title.Replace(" ", "-"); - - return title.Replace("/", "").SanitizeFileName(); - } - - string PathToUrl(string path) - { - string url = path.ReplaceIgnoreCase(_storageRoot, "").Replace(_slash, "/"); - return $"data/{url}"; - } - - string GetImgSrcValue(string imgTag) - { - if (!(imgTag.Contains("data:image") && imgTag.Contains("src="))) - return imgTag; - - int start = imgTag.IndexOf("src="); - int srcStart = imgTag.IndexOf("\"", start) + 1; - - if (srcStart < 2) - return imgTag; - - int srcEnd = imgTag.IndexOf("\"", srcStart); - - if (srcEnd < 1 || srcEnd <= srcStart) - return imgTag; - - return imgTag.Substring(srcStart, srcEnd - srcStart); - } - - bool InvalidFileName(string fileName) - { - List fileExtensions = new List() { "png", "gif", "jpeg", "jpg", "zip", "7z", "pdf", "doc", "docx", "xls", "xlsx", "mp3", "mp4", "avi" }; - string configFileExtensions = _configuration.GetSection("Blogifier").GetValue("FileExtensions"); - - if(!string.IsNullOrEmpty(configFileExtensions)) - { - fileExtensions = new List(configFileExtensions.Split(',')); - } - - foreach(string ext in fileExtensions) - { - if(fileName.EndsWith(ext)) - { - return false; - } - } - - return true; - } - - #endregion - } + public interface IStorageProvider + { + Task> GetThemes(); + bool FileExists(string path); + Task UploadFormFile(IFormFile file, string path = ""); + Task UploadFromWeb(Uri requestUri, string root, string path = ""); + Task UploadBase64Image(string baseImg, string root, string path = ""); + Task GetThemeSettings(string theme); + Task SaveThemeSettings(string theme, ThemeSettings settings); + } + + public class StorageProvider : IStorageProvider + { + private string _storageRoot; + private readonly string _slash = Path.DirectorySeparatorChar.ToString(); + private readonly IConfiguration _configuration; + + public StorageProvider(IConfiguration configuration) + { + _storageRoot = $"{ContentRoot}{_slash}wwwroot{_slash}data{_slash}"; + _configuration = configuration; + } + + public bool FileExists(string path) + { + Serilog.Log.Information($"File exists: {Path.Combine(ContentRoot, path)}"); + return File.Exists(Path.Combine(ContentRoot, path)); + } + + public async Task> GetThemes() + { + var themes = new List(); + var themesDirectory = Path.Combine(ContentRoot, $"Views{_slash}Themes"); + try + { + foreach (string dir in Directory.GetDirectories(themesDirectory)) + { + themes.Add(Path.GetFileName(dir)); + } + } + catch { } + return await Task.FromResult(themes); + } + + public async Task GetThemeSettings(string theme) + { + var settings = new ThemeSettings(); + var fileName = Path.Combine(ContentRoot, $"wwwroot{_slash}themes{_slash}{theme.ToLower()}{_slash}settings.json"); + if (File.Exists(fileName)) + { + try + { + string jsonString = File.ReadAllText(fileName); + settings = JsonSerializer.Deserialize(jsonString); + } + catch (Exception ex) + { + Serilog.Log.Error($"Error reading theme settings: {ex.Message}"); + return null; + } + } + + return await Task.FromResult(settings); + } + + public async Task SaveThemeSettings(string theme, ThemeSettings settings) + { + var fileName = Path.Combine(ContentRoot, $"wwwroot{_slash}themes{_slash}{theme.ToLower()}{_slash}settings.json"); + try + { + if (File.Exists(fileName)) + File.Delete(fileName); + + var options = new JsonSerializerOptions { WriteIndented = true, PropertyNameCaseInsensitive = true }; + + string jsonString = JsonSerializer.Serialize(settings, options); + + using FileStream createStream = File.Create(fileName); + await JsonSerializer.SerializeAsync(createStream, settings, options); + } + catch (Exception ex) + { + Serilog.Log.Error($"Error writing theme settings: {ex.Message}"); + return false; + } + return true; + } + + public async Task UploadFormFile(IFormFile file, string path = "") + { + path = path.Replace("/", _slash); + VerifyPath(path); + + var fileName = GetFileName(file.FileName); + + if (InvalidFileName(fileName)) + { + Serilog.Log.Error($"Invalid file name: {fileName}"); + return false; + } + + var filePath = string.IsNullOrEmpty(path) ? + Path.Combine(_storageRoot, fileName) : + Path.Combine(_storageRoot, path + _slash + fileName); + + Serilog.Log.Information($"Storage root: {_storageRoot}"); + Serilog.Log.Information($"Uploading file: {filePath}"); + try + { + using (var fileStream = new FileStream(filePath, FileMode.Create)) + { + await file.CopyToAsync(fileStream); + Serilog.Log.Information($"Uploaded file: {filePath}"); + } + } + catch (Exception ex) + { + Serilog.Log.Error($"Error uploading file: {ex.Message}"); + } + + return true; + } + + public async Task UploadFromWeb(Uri requestUri, string root, string path = "") + { + path = path.Replace("/", _slash); + VerifyPath(path); + + var fileName = TitleFromUri(requestUri); + var filePath = string.IsNullOrEmpty(path) ? + Path.Combine(_storageRoot, fileName) : + Path.Combine(_storageRoot, path + _slash + fileName); + + HttpClient client = new HttpClient(); + var response = await client.GetAsync(requestUri); + using (var fs = new FileStream(filePath, FileMode.CreateNew)) + { + await response.Content.CopyToAsync(fs); + return await Task.FromResult($"![{fileName}]({root}{PathToUrl(filePath)})"); + } + } + + public async Task UploadBase64Image(string baseImg, string root, string path = "") + { + path = path.Replace("/", _slash); + var fileName = ""; + + VerifyPath(path); + string imgSrc = GetImgSrcValue(baseImg); + + Random rnd = new Random(); + + if (imgSrc.StartsWith("data:image/png;base64,")) + { + fileName = string.Format("{0}.png", rnd.Next(1000, 9999)); + imgSrc = imgSrc.Replace("data:image/png;base64,", ""); + } + if (imgSrc.StartsWith("data:image/jpeg;base64,")) + { + fileName = string.Format("{0}.jpeg", rnd.Next(1000, 9999)); + imgSrc = imgSrc.Replace("data:image/jpeg;base64,", ""); + } + if (imgSrc.StartsWith("data:image/gif;base64,")) + { + fileName = string.Format("{0}.gif", rnd.Next(1000, 9999)); + imgSrc = imgSrc.Replace("data:image/gif;base64,", ""); + } + + var filePath = string.IsNullOrEmpty(path) ? + Path.Combine(_storageRoot, fileName) : + Path.Combine(_storageRoot, path + _slash + fileName); + + await File.WriteAllBytesAsync(filePath, Convert.FromBase64String(imgSrc)); + + return $"![{fileName}]({root}{PathToUrl(filePath)})"; + } + + #region Private members + + private string ContentRoot + { + get + { + string path = Directory.GetCurrentDirectory(); + string testsDirectory = $"tests{_slash}Blogifier.Tests"; + string appDirectory = $"src{_slash}Blogifier"; + + Serilog.Log.Information($"Current directory path: {path}"); + + // development unit test run + if (path.LastIndexOf(testsDirectory) > 0) + { + path = path.Substring(0, path.LastIndexOf(testsDirectory)); + Serilog.Log.Information($"Unit test path: {path}src{_slash}Blogifier"); + return $"{path}src{_slash}Blogifier"; + } + + // this needed to make sure we have correct data directory + // when running in debug mode in Visual Studio + // so instead of debug (src/Blogifier/bin/Debug..) + // will be used src/Blogifier/wwwroot/data + // !! this can mess up installs that have "src/Blogifier" in the path !! + if (path.LastIndexOf(appDirectory) > 0) + { + path = path.Substring(0, path.LastIndexOf(appDirectory)); + Serilog.Log.Information($"Development debug path: {path}src{_slash}Blogifier"); + return $"{path}src{_slash}Blogifier"; + } + Serilog.Log.Information($"Final path: {path}"); + return path; + } + } + + string GetFileName(string fileName) + { + // some browsers pass uploaded file name as short file name + // and others include the path; remove path part if needed + if (fileName.Contains(_slash)) + { + fileName = fileName.Substring(fileName.LastIndexOf(_slash)); + fileName = fileName.Replace(_slash, ""); + } + // when drag-and-drop or copy image to TinyMce editor + // it uses "mceclip0" as file name; randomize it for multiple uploads + if (fileName.StartsWith("mceclip0")) + { + Random rnd = new Random(); + fileName = fileName.Replace("mceclip0", rnd.Next(100000, 999999).ToString()); + } + return fileName.SanitizePath(); + } + + void VerifyPath(string path) + { + path = path.SanitizePath(); + + if (!string.IsNullOrEmpty(path)) + { + var dir = Path.Combine(_storageRoot, path); + + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + } + } + + string TitleFromUri(Uri uri) + { + var title = uri.ToString().ToLower(); + title = title.Replace("%2f", "/"); + + if (title.EndsWith(".axdx")) + { + title = title.Replace(".axdx", ""); + } + if (title.Contains("image.axd?picture=")) + { + title = title.Substring(title.IndexOf("image.axd?picture=") + 18); + } + if (title.Contains("file.axd?file=")) + { + title = title.Substring(title.IndexOf("file.axd?file=") + 14); + } + if (title.Contains("encrypted-tbn") || title.Contains("base64,")) + { + Random rnd = new Random(); + title = string.Format("{0}.png", rnd.Next(1000, 9999)); + } + + if (title.Contains("/")) + { + title = title.Substring(title.LastIndexOf("/")); + } + + title = title.Replace(" ", "-"); + + return title.Replace("/", "").SanitizeFileName(); + } + + string PathToUrl(string path) + { + string url = path.ReplaceIgnoreCase(_storageRoot, "").Replace(_slash, "/"); + return $"data/{url}"; + } + + string GetImgSrcValue(string imgTag) + { + if (!(imgTag.Contains("data:image") && imgTag.Contains("src="))) + return imgTag; + + int start = imgTag.IndexOf("src="); + int srcStart = imgTag.IndexOf("\"", start) + 1; + + if (srcStart < 2) + return imgTag; + + int srcEnd = imgTag.IndexOf("\"", srcStart); + + if (srcEnd < 1 || srcEnd <= srcStart) + return imgTag; + + return imgTag.Substring(srcStart, srcEnd - srcStart); + } + + bool InvalidFileName(string fileName) + { + List fileExtensions = new List() { "png", "gif", "jpeg", "jpg", "zip", "7z", "pdf", "doc", "docx", "xls", "xlsx", "mp3", "mp4", "avi" }; + string configFileExtensions = _configuration.GetSection("Blogifier").GetValue("FileExtensions"); + + if (!string.IsNullOrEmpty(configFileExtensions)) + { + fileExtensions = new List(configFileExtensions.Split(',')); + } + + foreach (string ext in fileExtensions) + { + if (fileName.EndsWith(ext)) + { + return false; + } + } + + return true; + } + + #endregion + } } From fb631665aeba462b8e3e960e72d60ab71fb4e243 Mon Sep 17 00:00:00 2001 From: dorthl Date: Fri, 14 Apr 2023 16:58:51 +0800 Subject: [PATCH 004/248] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Blogifier.Admin/Shared/NavMenu.razor | 34 +++++++++---------- .../Providers/StorageProvider.cs | 31 +++++++++++++---- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/Blogifier.Admin/Shared/NavMenu.razor b/src/Blogifier.Admin/Shared/NavMenu.razor index 403b235a5..d9a4be79b 100644 --- a/src/Blogifier.Admin/Shared/NavMenu.razor +++ b/src/Blogifier.Admin/Shared/NavMenu.razor @@ -34,13 +34,13 @@ @if (author.IsAdmin) { - + }
  • @@ -53,14 +53,14 @@