Browse Source

Merge pull request #19418 from abpframework/salihozkara/blogImprovements

Blogging module improvements and add single blog mode
pull/19537/head
oykuermann 2 years ago
committed by GitHub
parent
commit
0f14ed9d8b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1562
      modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20240404113615_SyncMigrations.Designer.cs
  2. 638
      modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20240404113615_SyncMigrations.cs
  3. 95
      modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs
  4. 1
      modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs
  5. 2
      modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Members/MemberAppService.cs
  6. 2
      modules/blogging/src/Volo.Blogging.Web/AbpBloggingWebAutoMapperProfile.cs
  7. 14
      modules/blogging/src/Volo.Blogging.Web/BloggingUrlOptions.cs
  8. 30
      modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs
  9. 6
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageHelper.cs
  10. 25
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageModel.cs
  11. 3
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml
  12. 12
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml.cs
  13. 6
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml
  14. 20
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml.cs
  15. 0
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.css
  16. 0
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.js
  17. 24
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml
  18. 26
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml.cs
  19. 4
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml
  20. 26
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs
  21. 43
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml
  22. 32
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml.cs
  23. 4
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml
  24. 22
      modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs

1562
modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20240404113615_SyncMigrations.Designer.cs

File diff suppressed because it is too large

638
modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20240404113615_SyncMigrations.cs

@ -0,0 +1,638 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
{
/// <inheritdoc />
public partial class SyncMigrations : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Twitter",
table: "BlgUsers",
type: "nvarchar(128)",
maxLength: 128,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(64)",
oldMaxLength: 64,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Linkedin",
table: "BlgUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(64)",
oldMaxLength: 64,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "JobTitle",
table: "BlgUsers",
type: "nvarchar(128)",
maxLength: 128,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(32)",
oldMaxLength: 32,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Github",
table: "BlgUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(64)",
oldMaxLength: 64,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgUsers",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgUsers",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Company",
table: "BlgUsers",
type: "nvarchar(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(128)",
oldMaxLength: 128,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgTags",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgTags",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgPosts",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgPosts",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgComments",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgComments",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgBlogs",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgBlogs",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpUsers",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpUsers",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpSecurityLogs",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpSecurityLogs",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpRoles",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpRoles",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpOrganizationUnits",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpOrganizationUnits",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpClaimTypes",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpClaimTypes",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpBlobs",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpBlobs",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpBlobContainers",
type: "nvarchar(max)",
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(max)",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpBlobContainers",
type: "nvarchar(40)",
maxLength: 40,
nullable: false,
defaultValue: "",
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40,
oldNullable: true);
migrationBuilder.CreateTable(
name: "AbpSettingDefinitions",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
DisplayName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
DefaultValue = table.Column<string>(type: "nvarchar(2048)", maxLength: 2048, nullable: true),
IsVisibleToClients = table.Column<bool>(type: "bit", nullable: false),
Providers = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
IsInherited = table.Column<bool>(type: "bit", nullable: false),
IsEncrypted = table.Column<bool>(type: "bit", nullable: false),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AbpSettingDefinitions", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_AbpSettingDefinitions_Name",
table: "AbpSettingDefinitions",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpSettingDefinitions");
migrationBuilder.AlterColumn<string>(
name: "Twitter",
table: "BlgUsers",
type: "nvarchar(64)",
maxLength: 64,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(128)",
oldMaxLength: 128,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Linkedin",
table: "BlgUsers",
type: "nvarchar(64)",
maxLength: 64,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "JobTitle",
table: "BlgUsers",
type: "nvarchar(32)",
maxLength: 32,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(128)",
oldMaxLength: 128,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Github",
table: "BlgUsers",
type: "nvarchar(64)",
maxLength: 64,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgUsers",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "Company",
table: "BlgUsers",
type: "nvarchar(128)",
maxLength: 128,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgTags",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgTags",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgPosts",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgPosts",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgComments",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgComments",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "BlgBlogs",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "BlgBlogs",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpUsers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpUsers",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpSecurityLogs",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpSecurityLogs",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpRoles",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpRoles",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpOrganizationUnits",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpOrganizationUnits",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpClaimTypes",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpClaimTypes",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpBlobs",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpBlobs",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "AbpBlobContainers",
type: "nvarchar(max)",
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(max)");
migrationBuilder.AlterColumn<string>(
name: "ConcurrencyStamp",
table: "AbpBlobContainers",
type: "nvarchar(40)",
maxLength: 40,
nullable: true,
oldClrType: typeof(string),
oldType: "nvarchar(40)",
oldMaxLength: 40);
}
}
}

95
modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer)
.HasAnnotation("ProductVersion", "7.0.1")
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@ -32,6 +32,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -44,6 +45,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("varbinary(max)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -73,11 +75,13 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -105,6 +109,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -114,6 +119,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -179,6 +185,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -187,6 +194,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -279,6 +287,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -291,6 +300,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("datetime2");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -340,6 +350,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -376,6 +387,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -660,6 +672,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -690,6 +703,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnType("int");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -898,6 +912,55 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.ToTable("AbpSettings", (string)null);
});
modelBuilder.Entity("Volo.Abp.SettingManagement.SettingDefinitionRecord", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<string>("DefaultValue")
.HasMaxLength(2048)
.HasColumnType("nvarchar(2048)");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("ExtraProperties")
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsEncrypted")
.HasColumnType("bit");
b.Property<bool>("IsInherited")
.HasColumnType("bit");
b.Property<bool>("IsVisibleToClients")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("Providers")
.HasMaxLength(1024)
.HasColumnType("nvarchar(1024)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("AbpSettingDefinitions", (string)null);
});
modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b =>
{
b.Property<Guid>("Id")
@ -906,6 +969,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -932,6 +996,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("Description");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -974,6 +1039,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -995,6 +1061,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1047,6 +1114,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1083,6 +1151,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("Description");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1158,6 +1227,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1184,6 +1254,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("Description");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
@ -1228,12 +1299,13 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("Biography");
b.Property<string>("Company")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)")
.HasColumnName("Company");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
@ -1251,12 +1323,13 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("EmailConfirmed");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("Github")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)")
.HasColumnName("Github");
b.Property<bool>("IsActive")
@ -1264,13 +1337,13 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("IsActive");
b.Property<string>("JobTitle")
.HasMaxLength(32)
.HasColumnType("nvarchar(32)")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasColumnName("JobTitle");
b.Property<string>("Linkedin")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)")
.HasColumnName("Linkedin");
b.Property<string>("Name")
@ -1299,8 +1372,8 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("TenantId");
b.Property<string>("Twitter")
.HasMaxLength(64)
.HasColumnType("nvarchar(64)")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)")
.HasColumnName("Twitter");
b.Property<string>("UserName")

1
modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs

@ -78,6 +78,7 @@ namespace Volo.BloggingTestApp
Configure<BloggingUrlOptions>(options =>
{
options.RoutePrefix = null;
options.SingleBlogMode.Enabled = true;
});
Configure<AbpDbConnectionOptions>(options =>

2
modules/blogging/src/Volo.Blogging.Application/Volo/Blogging/Members/MemberAppService.cs

@ -17,7 +17,7 @@ public class MemberAppService : BloggingAppServiceBase, IMemberAppService
public virtual async Task<BlogUserDto> FindAsync(string username)
{
var user = await _userRepository.FindAsync(x => x.UserName == username);
var user = await _userRepository.FindAsync(x => x.UserName == username && x.IsActive);
if (user == null)
{

2
modules/blogging/src/Volo.Blogging.Web/AbpBloggingWebAutoMapperProfile.cs

@ -1,6 +1,6 @@
using AutoMapper;
using Volo.Abp.AutoMapper;
using Volo.Blogging.Pages.Blog.Posts;
using Volo.Blogging.Pages.Blogs.Posts;
using Volo.Blogging.Posts;
namespace Volo.Blogging

14
modules/blogging/src/Volo.Blogging.Web/BloggingUrlOptions.cs

@ -20,6 +20,9 @@ namespace Volo.Blogging
/// Used to specify ignore paths if the route prefix is null or empty.
/// </summary>
public List<string> IgnoredPaths { get; } = new ();
public SingleBlogModeOptions SingleBlogMode { get; } = new ();
private string GetFormattedRoutePrefix()
{
@ -31,4 +34,15 @@ namespace Volo.Blogging
return _routePrefix.EnsureEndsWith('/').EnsureStartsWith('/');
}
}
public class SingleBlogModeOptions
{
/// <summary>
/// Determines whether to enable single blog mode by removing the blog name from the routing.
/// When enabled, only a single blog is allowed within the module.
/// </summary>
public bool Enabled { get; set; }
public string BlogName { get; set; }
}
}

30
modules/blogging/src/Volo.Blogging.Web/BloggingWebModule.cs

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@ -79,7 +80,7 @@ namespace Volo.Blogging
options.IgnoredPaths.AddRange(new[]
{
"error", "ApplicationConfigurationScript", "ServiceProxyScript", "Languages/Switch",
"ApplicationLocalizationScript"
"ApplicationLocalizationScript", "members"
});
});
@ -91,11 +92,26 @@ namespace Volo.Blogging
var routePrefix = urlOptions.RoutePrefix;
options.Conventions.AddPageRoute("/Blogs/Posts/Index", routePrefix + "{blogShortName:blogNameConstraint}");
options.Conventions.AddPageRoute("/Blogs/Posts/Detail", routePrefix + "{blogShortName:blogNameConstraint}/{postUrl}");
options.Conventions.AddPageRoute("/Blogs/Posts/Edit", routePrefix + "{blogShortName}/posts/{postId}/edit");
options.Conventions.AddPageRoute("/Blogs/Posts/New", routePrefix + "{blogShortName}/posts/new");
options.Conventions.AddPageRoute("/Members/Index", routePrefix + "members/{userName}");
if (urlOptions.SingleBlogMode.Enabled)
{
options.Conventions.AddPageRoute("/Blogs/Posts/Index", routePrefix);
options.Conventions.AddPageRoute("/Blogs/Posts/Detail", routePrefix + "{postUrl}");
options.Conventions.AddPageRoute("/Blogs/Posts/Edit", routePrefix + "posts/{postId}/edit");
options.Conventions.AddPageRoute("/Blogs/Posts/New", routePrefix + "posts/new");
}
else
{
if (!routePrefix.IsNullOrWhiteSpace())
{
options.Conventions.AddPageRoute("/Blogs/Index", routePrefix);
}
options.Conventions.AddPageRoute("/Blogs/Posts/Index", routePrefix + "{blogShortName:blogNameConstraint}");
options.Conventions.AddPageRoute("/Blogs/Posts/Detail", routePrefix + "{blogShortName:blogNameConstraint}/{postUrl}");
options.Conventions.AddPageRoute("/Blogs/Posts/Edit", routePrefix + "{blogShortName}/posts/{postId}/edit");
options.Conventions.AddPageRoute("/Blogs/Posts/New", routePrefix + "{blogShortName}/posts/new");
}
options.Conventions.AddPageRoute("/Blogs/Members/Index", routePrefix + "members/{userName}");
});
Configure<DynamicJavaScriptProxyOptions>(options =>

6
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageHelper.cs

@ -1,16 +1,14 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Markdig;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Localization;
using Markdig;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Pages.Blog
namespace Volo.Blogging.Pages.Blogs
{
public class BloggingPageHelper : ITransientDependency
{

25
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/BloggingPageModel.cs

@ -1,6 +1,11 @@
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
namespace Volo.Blogging.Pages.Blog
namespace Volo.Blogging.Pages.Blogs
{
public abstract class BloggingPageModel : AbpPageModel
{
@ -8,5 +13,21 @@ namespace Volo.Blogging.Pages.Blog
{
ObjectMapperContext = typeof(BloggingWebModule);
}
protected async Task<BlogDto> GetBlogAsync(IBlogAppService blogAppService, BloggingUrlOptions blogOptions, string blogShortName)
{
if (!blogOptions.SingleBlogMode.Enabled)
{
return await blogAppService.GetByShortNameAsync(blogShortName);
}
if (!blogOptions.SingleBlogMode.BlogName.IsNullOrEmpty())
{
return await blogAppService.GetByShortNameAsync(blogOptions.SingleBlogMode.BlogName);
}
var blogs = await blogAppService.GetListAsync();
return blogs.Items.Count == 1 ? blogs.Items[0] : blogs.Items.SingleOrDefault(x => x.ShortName == blogShortName);
}
}
}

3
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml

@ -1,9 +1,8 @@
@page
@using Volo.Blogging.Pages.Blog
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@inject IHtmlLocalizer<BloggingResource> L
@model IndexModel
@model Volo.Blogging.Pages.Blogs.IndexModel
@{
ViewBag.PageTitle = "Blogs";
}

12
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Index.cshtml.cs

@ -1,25 +1,33 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
namespace Volo.Blogging.Pages.Blog
namespace Volo.Blogging.Pages.Blogs
{
public class IndexModel : AbpPageModel
{
private readonly IBlogAppService _blogAppService;
private readonly BloggingUrlOptions _blogOptions;
public IReadOnlyList<BlogDto> Blogs { get; private set; }
public IndexModel(IBlogAppService blogAppService)
public IndexModel(IBlogAppService blogAppService, IOptions<BloggingUrlOptions> blogOptions)
{
_blogAppService = blogAppService;
_blogOptions = blogOptions.Value;
}
public virtual async Task<IActionResult> OnGetAsync()
{
if (_blogOptions.SingleBlogMode.Enabled)
{
return RedirectToPage("./Posts/Index");
}
var result = await _blogAppService.GetListAsync();
if (result.Items.Count == 1)

6
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml → modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml

@ -5,7 +5,7 @@
@using Volo.Abp.Users
@using Volo.Blogging.Areas.Blog.Helpers.TagHelpers
@using Volo.Blogging.Localization
@model Volo.Blogging.Pages.Members.IndexModel
@model Volo.Blogging.Pages.Blogs.Members.IndexModel
@inject IStringLocalizer<BloggingResource> L
@inject ICurrentUser CurrentUser
@{
@ -13,11 +13,11 @@
}
@section scripts {
<abp-script src="/Pages/Members/Index.js" />
<abp-script src="/Pages/Blogs/Members/Index.js" />
}
@section styles {
<abp-style src="/Pages/Members/Index.css"/>
<abp-style src="/Pages/Blogs/Members/Index.css"/>
}
<main>

20
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.cshtml.cs → modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.cshtml.cs

@ -3,12 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Blogs;
using Volo.Blogging.Members;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Members;
namespace Volo.Blogging.Pages.Blogs.Members;
public class IndexModel : AbpPageModel
{
@ -18,6 +19,8 @@ public class IndexModel : AbpPageModel
private readonly IBlogAppService _blogAppService;
private readonly BloggingUrlOptions _blogOptions;
public BlogUserDto User { get; set; }
public List<PostWithDetailsDto> Posts { get; set; }
@ -26,11 +29,12 @@ public class IndexModel : AbpPageModel
[BindProperty]
public CustomIdentityBlogUserUpdateDto CustomUserUpdate { get; set; }
public IndexModel(IPostAppService postAppService, IMemberAppService memberAppService, IBlogAppService blogAppService)
public IndexModel(IPostAppService postAppService, IMemberAppService memberAppService, IBlogAppService blogAppService, IOptions<BloggingUrlOptions> blogOptions)
{
_postAppService = postAppService;
_memberAppService = memberAppService;
_blogAppService = blogAppService;
_blogOptions = blogOptions.Value;
}
public async Task<IActionResult> OnGetAsync(string userName)
@ -58,20 +62,24 @@ public class IndexModel : AbpPageModel
public async Task<IActionResult> OnPostAsync()
{
await _memberAppService.UpdateUserProfileAsync(CustomUserUpdate);
return Redirect($"/members/{CurrentUser.UserName}");
return RedirectToPage("/Blogs/Members/Index", new { userName = CurrentUser.UserName });
}
public string GetBlogPostUrl(PostWithDetailsDto post)
{
if (_blogOptions.SingleBlogMode.Enabled)
{
return Url.Page("/Blogs/Posts/Detail", new { postUrl = post.Url });
}
var blogShortName = BlogShortNameMap[post.BlogId];
return "/" + blogShortName + "/" + post.Url;
return Url.Page("/Blogs/Posts/Detail", new { blogShortName = blogShortName, postUrl = post.Url });
}
public string GetMemberProfileUrl(BlogUserDto user)
{
return "/members/" + user.UserName;
return Url.Page("/Blogs/Members/Index", new { userName = user.UserName });
}
}

0
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.css → modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.css

0
modules/blogging/src/Volo.Blogging.Web/Pages/Members/Index.js → modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Members/Index.js

24
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml

@ -5,7 +5,6 @@
@using Microsoft.Extensions.Options
@using Volo.Abp.Users
@using Volo.Blogging
@using Volo.Blogging.Pages.Blog.Posts
@using Volo.Blogging.Areas.Blog.Helpers.TagHelpers
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.Prismjs
@using Volo.Blogging.SocialMedia
@ -14,11 +13,12 @@
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using Volo.Blogging.Localization
@using Volo.Blogging.Pages.Blog
@using Volo.Blogging.Pages.Blogs
@using Volo.Blogging.Pages.Blogs.Posts
@inject IHtmlLocalizer<BloggingResource> L
@inject BloggingPageHelper BloggingPageHelper
@inject ICurrentUser CurrentUser
@model DetailModel
@model Volo.Blogging.Pages.Blogs.Posts.DetailModel
@{
ViewBag.Title = Model.Post.Title;
ViewBag.Description = Model.Post.Description;
@ -67,7 +67,7 @@
<div class="col-auto pe-1">
@if (Model.Post.Writer != null)
{
<a href="/Members/@Model.Post.Writer.UserName" aria-label="Go to user profile">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" aria-label="Go to user profile">
<img gravatar-email="@Model.Post.Writer.Email" default-image="Identicon" class="article-avatar" alt="User Avatar"/>
</a>
}
@ -76,7 +76,7 @@
@if (Model.Post.Writer != null)
{
<h5 class="mt-2 mb-1">
<a href="/Members/@Model.Post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})">
@(Model.Post.Writer.UserName)
</a>
<span>@BloggingPageHelper.GetLocalizedTimeAgoText(Model.Post.CreationTime)</span>
@ -141,7 +141,7 @@
<div class="col-auto pe-2">
@if (Model.Post.Writer != null)
{
<a href="/Members/@Model.Post.Writer.UserName" aria-label="Go to user profile">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" aria-label="Go to user profile">
<img gravatar-email="@Model.Post.Writer.Email" default-image="Identicon" class="article-avatar rounded-circle" alt="User Avatar"/>
</a>
}
@ -151,7 +151,7 @@
{
<h5 class="mt-2 mb-1">
<a href="/Members/@Model.Post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})">
@if (Model.Post.Writer.Name != null && Model.Post.Writer.Surname != null)
{
<p class="fw-bold pt-2 fs-5">@Model.Post.Writer.Name @Model.Post.Writer.Surname</p>
@ -172,7 +172,7 @@
@if (CurrentUser.Id.HasValue && CurrentUser.Id.Value == Model.Post.Writer?.Id)
{
<a class="fw-lighter" href="/Members/@Model.Post.Writer?.UserName#edit-profile">@L["EditProfile"] <i class="fas fa-edit"></i></a>
<a class="fw-lighter" href="@(Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName}))#edit-profile">@L["EditProfile"] <i class="fas fa-edit"></i></a>
}
</div>
@if (Model.LatestPosts.Count > 1)
@ -194,14 +194,14 @@
{
<div class="row">
<div class="col-auto pe-1">
<a href="/Members/@post.Writer.UserName" aria-label="Go to user profile">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" aria-label="Go to user profile">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="last-post-image" alt="User Avatar"/>
</a>
</div>
<div class="col">
<h5 class="last-post-name">
<a href="/Members/@post.Writer!.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})">
@(post.Writer!.UserName)
</a>
</h5>
@ -456,13 +456,13 @@ else
var post = Model.PostsList[index];
<div class="post-item">
<div class="post-type-cont">
<a href="/members/@Model.Post.Writer.UserName" class="text-decoration-none">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" class="text-decoration-none">
<img gravatar-email="@Model.Post.Writer.Email" default-image="Identicon" class="post-member-img rounded-circle d-block"/>
</a>
</div>
<div class="post-detail-cont">
<div class="post-info fs-12 mb-2">
<a href="/members/@Model.Post.Writer.UserName" class="text-decoration-none">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = Model.Post.Writer.UserName})" class="text-decoration-none">
<span class="text-dark dot">@Model.Post.Writer.UserName</span>
</a>
<span class="text-dark-200">@post.CreationTime.ToString("MMMM yyyy")</span>

26
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Detail.cshtml.cs

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Microsoft.Extensions.Options;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
using Volo.Blogging.Comments;
@ -11,7 +11,7 @@ using Volo.Blogging.Comments.Dtos;
using Volo.Blogging.Pages.Blogs.Shared.Helpers;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Blog.Posts
namespace Volo.Blogging.Pages.Blogs.Posts
{
public class DetailModel : BloggingPageModel
{
@ -19,6 +19,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
private readonly IPostAppService _postAppService;
private readonly IBlogAppService _blogAppService;
private readonly ICommentAppService _commentAppService;
private readonly BloggingUrlOptions _blogOptions;
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
@ -47,11 +48,12 @@ namespace Volo.Blogging.Pages.Blog.Posts
[BindProperty(SupportsGet = true)]
public string TagName { get; set; }
public DetailModel(IPostAppService postAppService, IBlogAppService blogAppService, ICommentAppService commentAppService)
public DetailModel(IPostAppService postAppService, IBlogAppService blogAppService, ICommentAppService commentAppService, IOptions<BloggingUrlOptions> blogOptions)
{
_postAppService = postAppService;
_blogAppService = blogAppService;
_commentAppService = commentAppService;
_blogOptions = blogOptions.Value;
}
public virtual async Task<IActionResult> OnGetAsync()
@ -60,6 +62,17 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
return NotFound();
}
if (_blogOptions.SingleBlogMode.Enabled)
{
BlogShortName = _blogOptions.SingleBlogMode.BlogName;
}
Blog = await GetBlogAsync(_blogAppService, _blogOptions, BlogShortName);
if(Blog == null)
{
return NotFound();
}
await GetData();
@ -76,6 +89,12 @@ namespace Volo.Blogging.Pages.Blog.Posts
});
FocusCommentId = comment.Id;
Blog = await GetBlogAsync(_blogAppService, _blogOptions, BlogShortName);
if(Blog == null)
{
return NotFound();
}
await GetData();
@ -84,7 +103,6 @@ namespace Volo.Blogging.Pages.Blog.Posts
private async Task GetData()
{
Blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Post = await _postAppService.GetForReadingAsync(new GetPostInput { BlogId = Blog.Id, Url = PostUrl });
PostsList = Post.Writer != null

4
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml

@ -1,11 +1,11 @@
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor
@using Volo.Blogging.Pages.Blog.Posts
@using Volo.Blogging.Posts
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@using Volo.Blogging.Pages.Blogs.Posts
@inject IHtmlLocalizer<BloggingResource> L
@model EditModel
@model Volo.Blogging.Pages.Blogs.Posts.EditModel
@{
ViewBag.PageTitle = "Edit Blog Post";
}

26
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Edit.cshtml.cs

@ -1,24 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Validation;
using Volo.Blogging.Blogs;
using Volo.Blogging.Pages.Blogs.Shared.Helpers;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Blog.Posts
namespace Volo.Blogging.Pages.Blogs.Posts
{
public class EditModel : BloggingPageModel
{
private readonly IPostAppService _postAppService;
private readonly IBlogAppService _blogAppService;
private readonly IAuthorizationService _authorization;
private readonly BloggingUrlOptions _blogOptions;
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
@ -29,11 +31,12 @@ namespace Volo.Blogging.Pages.Blog.Posts
[BindProperty]
public EditPostViewModel Post { get; set; }
public EditModel(IPostAppService postAppService, IBlogAppService blogAppService, IAuthorizationService authorization)
public EditModel(IPostAppService postAppService, IBlogAppService blogAppService, IAuthorizationService authorization, IOptions<BloggingUrlOptions> blogOptions)
{
_postAppService = postAppService;
_blogAppService = blogAppService;
_authorization = authorization;
_blogOptions = blogOptions.Value;
}
public virtual async Task<ActionResult> OnGetAsync()
@ -42,6 +45,12 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
return Redirect("/");
}
if (_blogOptions.SingleBlogMode.Enabled)
{
BlogShortName = _blogOptions.SingleBlogMode.BlogName;
}
if (BlogNameControlHelper.IsProhibitedFileFormatName(BlogShortName))
{
return NotFound();
@ -73,7 +82,16 @@ namespace Volo.Blogging.Pages.Blog.Posts
var editedPost = await _postAppService.UpdateAsync(Post.Id, post);
var blog = await _blogAppService.GetAsync(editedPost.BlogId);
return RedirectToPage("/Blogs/Posts/Detail", new { blogShortName = blog.ShortName, postUrl = editedPost.Url });
Dictionary<string, object> routeValues = new()
{
{ nameof(DetailModel.PostUrl), editedPost.Url }
};
if (!_blogOptions.SingleBlogMode.Enabled)
{
routeValues.Add(nameof(DetailModel.BlogShortName), blog.ShortName);
}
return RedirectToPage("/Blogs/Posts/Detail", routeValues);
}
}

43
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml

@ -4,15 +4,17 @@
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.OwlCarousel
@using Volo.Blogging
@inject IAuthorizationService Authorization
@model Volo.Blogging.Pages.Blog.Posts.IndexModel
@model IndexModel
@using Microsoft.Extensions.Localization
@using Microsoft.Extensions.Options
@using Volo.Blogging.Localization
@using Volo.Blogging.Pages.Blog
@using IndexModel = Volo.Blogging.Pages.Blog.Posts.IndexModel
@using Volo.Blogging.Pages.Blogs
@using IndexModel = Volo.Blogging.Pages.Blogs.Posts.IndexModel
@inject IStringLocalizer<BloggingResource> L
@inject BloggingPageHelper BloggingPageHelper
@{
ViewBag.Title = "Read All Blog Posts";
var blogShortNameRouteParam = Model.BlogOptions.SingleBlogMode.Enabled ? null : Model.BlogShortName;
}
@section scripts {
<abp-script-bundle name="@typeof(IndexModel).FullName">
@ -27,7 +29,6 @@
<abp-style src="/Pages/Blogs/Shared/Styles/blog.css" />
</abp-style-bundle>
}
<div class="vs-blog blah">
<div class="container">
<div class="pb-3">
@ -39,18 +40,18 @@
var post = Model.Posts[index];
<div class="hero-articles">
<div class="img-container">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">
<img src="@post.CoverImage" class="hero-article-img" alt="@post.Title cover image">
</a>
</div>
<div class="hero-content pt-3">
<h2>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">@post.Title</a>
</h2>
<p class="article-sum">
@Html.Raw(BloggingPageHelper.GetShortContent(post.Content))
</p>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName" class="read-more-btn">@L["ContinueReading"] &#8594;</a>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam" class="read-more-btn">@L["ContinueReading"] &#8594;</a>
</div>
@if (post.Writer != null)
@ -60,13 +61,13 @@
<div class="user-card">
<div class="row">
<div class="col-auto pe-1">
<a href="/Members/@post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="article-avatar" alt="@post.Writer.UserName avatar" />
</a>
</div>
<div class="col ps-1">
<h5 class="mt-2 mb-1">
<a href="/Members/@post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
@post.Writer.UserName
</a>
<span>@BloggingPageHelper.GetLocalizedTimeAgoText(post.CreationTime)</span>
@ -84,7 +85,7 @@
<p class="tags">
@foreach (var tag in post.Tags)
{
<a asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@Model.BlogShortName" asp-route-tagName="@tag.Name" class="tag">@tag.Name</a>
<a asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@blogShortNameRouteParam" asp-route-tagName="@tag.Name" class="tag">@tag.Name</a>
}
</p>
@ -97,7 +98,7 @@
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Posts.Create))
{
<a class="btn btn-primary btn-rounded mb-3 active " asp-page="./New" asp-route-blogShortName="@Model.BlogShortName">@L["CreateANewPost"]</a>
<a class="btn btn-primary btn-rounded mb-3 active " asp-page="./New" asp-route-blogShortName="@blogShortNameRouteParam">@L["CreateANewPost"]</a>
}
<div class="list-group">
@ -109,14 +110,14 @@
<div class="row align-middle">
<div class="col-4">
<div class="img-container">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">
<img src="@post.CoverImage" class="box-article-img" alt="@post.Title cover image">
</a>
</div>
</div>
<div class="col-8 ps-0">
<h3 class="font-125">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">@post.Title</a>
</h3>
@if (post.Writer != null)
@ -127,7 +128,7 @@
@if (post.Writer != null)
{
<h5 class="mt-2 mb-1">
<a href="/Members/@post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
@post.Writer.UserName
</a>
<span>@BloggingPageHelper.GetLocalizedTimeAgoText(post.CreationTime)</span>
@ -169,19 +170,19 @@
<div class="row">
<div class="col-md-4">
<div class="img-container">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">
<img src="@post.CoverImage" class="box-article-img" alt="@post.Title cover image">
</a>
</div>
</div>
<div class="col">
<h3>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam">@post.Title</a>
</h3>
<p>
@Html.Raw(BloggingPageHelper.GetShortContent(post.Content))
</p>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName" class="read-more-btn">@L["ContinueReading"] &#8594;</a>
<a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@blogShortNameRouteParam" class="read-more-btn">@L["ContinueReading"] &#8594;</a>
@if (post.Writer != null)
{
@ -190,13 +191,13 @@
<div class="user-card">
<div class="row">
<div class="col-auto pe-1">
<a href="/Members/@post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
<img gravatar-email="@post.Writer.Email" default-image="Identicon" class="article-avatar" alt="@post.Writer.UserName avatar" />
</a>
</div>
<div class="col ps-1">
<h5 class="mt-2 mb-1">
<a href="/Members/@post.Writer.UserName">
<a href="@Url.Page("/Blogs/Members/Index", new {userName = post.Writer.UserName})">
@post.Writer.UserName
</a>
<span>@BloggingPageHelper.GetLocalizedTimeAgoText(post.CreationTime)</span>
@ -213,7 +214,7 @@
<p class="tags">
@foreach (var tag in post.Tags)
{
<a asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@Model.BlogShortName" asp-route-tagName="@tag.Name" class="tag">@tag.Name</a>
<a asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@blogShortNameRouteParam" asp-route-tagName="@tag.Name" class="tag">@tag.Name</a>
}
</p>
</div>
@ -234,7 +235,7 @@
<div class="tags">
@foreach (var popularTag in Model.PopularTags)
{
<a class="tag" asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@Model.BlogShortName" asp-route-tagName="@popularTag.Name">@popularTag.Name <small>(@popularTag.UsageCount)</small></a>
<a class="tag" asp-page="/Blogs/Posts/Index" asp-route-blogShortName="@blogShortNameRouteParam" asp-route-tagName="@popularTag.Name">@popularTag.Name <small>(@popularTag.UsageCount)</small></a>
}
</div>
</div>

32
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/Index.cshtml.cs

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Entities;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
@ -11,13 +10,14 @@ using Volo.Blogging.Posts;
using Volo.Blogging.Tagging;
using Volo.Blogging.Tagging.Dtos;
namespace Volo.Blogging.Pages.Blog.Posts
namespace Volo.Blogging.Pages.Blogs.Posts
{
public class IndexModel : BloggingPageModel
{
private readonly IPostAppService _postAppService;
private readonly IBlogAppService _blogAppService;
private readonly ITagAppService _tagAppService;
public BloggingUrlOptions BlogOptions { get; }
[BindProperty(SupportsGet = true)]
public string BlogShortName { get; set; }
@ -31,11 +31,12 @@ namespace Volo.Blogging.Pages.Blog.Posts
public IReadOnlyList<TagDto> PopularTags { get; set; }
public IndexModel(IPostAppService postAppService, IBlogAppService blogAppService, ITagAppService tagAppService)
public IndexModel(IPostAppService postAppService, IBlogAppService blogAppService, ITagAppService tagAppService, IOptions<BloggingUrlOptions> blogOptions)
{
_postAppService = postAppService;
_blogAppService = blogAppService;
_tagAppService = tagAppService;
BlogOptions = blogOptions.Value;
}
public virtual async Task<ActionResult> OnGetAsync()
@ -47,11 +48,18 @@ namespace Volo.Blogging.Pages.Blog.Posts
try
{
Blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Blog = await GetBlogAsync(_blogAppService, BlogOptions, BlogShortName);
if(Blog == null)
{
return BlogNotFoundResult();
}
BlogShortName = Blog.ShortName;
}
catch (EntityNotFoundException)
{
return RedirectToPage("/Blogs/Index");
{
return BlogNotFoundResult();
}
Posts = (await _postAppService.GetListByBlogIdAndTagNameAsync(Blog.Id, TagName)).Items;
@ -59,5 +67,15 @@ namespace Volo.Blogging.Pages.Blog.Posts
return Page();
}
protected virtual ActionResult BlogNotFoundResult()
{
if (BlogOptions.SingleBlogMode.Enabled)
{
return NotFound();
}
return RedirectToPage("/Blogs/Index");
}
}
}

4
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml

@ -1,11 +1,11 @@
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Packages.TuiEditor
@using Volo.Blogging.Pages.Blog.Posts
@using Volo.Blogging.Posts
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@using Volo.Blogging.Pages.Blogs.Posts
@inject IHtmlLocalizer<BloggingResource> L
@model NewModel
@model Volo.Blogging.Pages.Blogs.Posts.NewModel
@{
ViewBag.PageTitle = @L["NewBlogPost"];
}

22
modules/blogging/src/Volo.Blogging.Web/Pages/Blogs/Posts/New.cshtml.cs

@ -1,18 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Abp.Validation;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
using Volo.Blogging.Pages.Blogs.Shared.Helpers;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Blog.Posts
namespace Volo.Blogging.Pages.Blogs.Posts
{
public class NewModel : BloggingPageModel
{
@ -48,7 +48,9 @@ namespace Volo.Blogging.Pages.Blog.Posts
return NotFound();
}
Blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Blog = await GetBlogAsync(_blogAppService, _blogOptions, BlogShortName);
BlogShortName = Blog.ShortName;
Post = new CreatePostViewModel
{
BlogId = Blog.Id
@ -70,9 +72,17 @@ namespace Volo.Blogging.Pages.Blog.Posts
var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map<CreatePostViewModel, CreatePostDto>(Post));
//TODO: Try Url.Page(...)
var urlPrefix = _blogOptions.RoutePrefix;
return Redirect(Url.Content($"~{urlPrefix}{WebUtility.UrlEncode(blog.ShortName)}/{WebUtility.UrlEncode(postWithDetailsDto.Url)}"));
Dictionary<string, object> routeValues = new()
{
{ nameof(DetailModel.PostUrl), postWithDetailsDto.Url }
};
if (!_blogOptions.SingleBlogMode.Enabled)
{
routeValues.Add(nameof(DetailModel.BlogShortName), blog.ShortName);
}
return RedirectToPage("/Blogs/Posts/Detail", routeValues);
}
public class CreatePostViewModel

Loading…
Cancel
Save