Added Post url

pull/318/head
Yunus Emre Kalkan 7 years ago
parent debe97f7a7
commit 4c8cb3f431

@ -0,0 +1,443 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Volo.BloggingTestApp.EntityFrameworkCore;
namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
{
[DbContext(typeof(BloggingTestAppDbContext))]
[Migration("20180629064225_Added_Url_To_Posts")]
partial class Added_Url_To_Posts
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.IsRequired()
.HasMaxLength(256);
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("NormalizedName");
b.ToTable("AbpRoles");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("ClaimValue")
.HasMaxLength(1024);
b.Property<Guid>("RoleId");
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AbpRoleClaims");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount")
.ValueGeneratedOnAdd()
.HasColumnName("AccessFailedCount")
.HasDefaultValue(0);
b.Property<string>("ConcurrencyStamp")
.IsRequired()
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
b.Property<string>("Email")
.HasColumnName("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("EmailConfirmed")
.HasDefaultValue(false);
b.Property<string>("ExtraProperties")
.HasColumnName("ExtraProperties");
b.Property<bool>("LockoutEnabled")
.ValueGeneratedOnAdd()
.HasColumnName("LockoutEnabled")
.HasDefaultValue(false);
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasColumnName("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.IsRequired()
.HasColumnName("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash")
.HasColumnName("PasswordHash")
.HasMaxLength(256);
b.Property<string>("PhoneNumber")
.HasColumnName("PhoneNumber")
.HasMaxLength(16);
b.Property<bool>("PhoneNumberConfirmed")
.ValueGeneratedOnAdd()
.HasColumnName("PhoneNumberConfirmed")
.HasDefaultValue(false);
b.Property<string>("SecurityStamp")
.IsRequired()
.HasColumnName("SecurityStamp")
.HasMaxLength(256);
b.Property<Guid?>("TenantId")
.HasColumnName("TenantId");
b.Property<bool>("TwoFactorEnabled")
.ValueGeneratedOnAdd()
.HasColumnName("TwoFactorEnabled")
.HasDefaultValue(false);
b.Property<string>("UserName")
.IsRequired()
.HasColumnName("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("Email");
b.HasIndex("NormalizedEmail");
b.HasIndex("NormalizedUserName");
b.HasIndex("UserName");
b.ToTable("AbpUsers");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType")
.IsRequired()
.HasMaxLength(256);
b.Property<string>("ClaimValue")
.HasMaxLength(1024);
b.Property<Guid?>("TenantId");
b.Property<Guid>("UserId");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AbpUserClaims");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.Property<Guid>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(64);
b.Property<string>("ProviderDisplayName")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.IsRequired()
.HasMaxLength(196);
b.Property<Guid?>("TenantId");
b.HasKey("UserId", "LoginProvider");
b.HasIndex("LoginProvider", "ProviderKey");
b.ToTable("AbpUserLogins");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
{
b.Property<Guid>("UserId");
b.Property<Guid>("RoleId");
b.Property<Guid?>("TenantId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId", "UserId");
b.ToTable("AbpUserRoles");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
{
b.Property<Guid>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name");
b.Property<Guid?>("TenantId");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AbpUserTokens");
});
modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.IsRequired()
.HasMaxLength(64);
b.Property<string>("ProviderName")
.IsRequired()
.HasMaxLength(64);
b.Property<Guid?>("TenantId");
b.HasKey("Id");
b.HasIndex("Name", "ProviderName", "ProviderKey");
b.ToTable("AbpPermissionGrants");
});
modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(64);
b.Property<string>("ProviderName")
.HasMaxLength(64);
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(2048);
b.HasKey("Id");
b.HasIndex("Name", "ProviderName", "ProviderKey");
b.ToTable("AbpSettings");
});
modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnName("Description")
.HasMaxLength(1024);
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<string>("Name")
.IsRequired()
.HasColumnName("Name")
.HasMaxLength(256);
b.Property<string>("ShortName")
.IsRequired()
.HasColumnName("ShortName")
.HasMaxLength(32);
b.HasKey("Id");
b.ToTable("BlgBlogs");
});
modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<Guid>("BlogId")
.HasColumnName("BlogId");
b.Property<string>("Content")
.HasColumnName("Content")
.HasMaxLength(1048576);
b.Property<DateTime>("CreationTime")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnName("DeletionTime");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnName("IsDeleted")
.HasDefaultValue(false);
b.Property<DateTime?>("LastModificationTime")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnName("LastModifierId");
b.Property<string>("Title")
.IsRequired()
.HasColumnName("Title")
.HasMaxLength(512);
b.Property<string>("Url")
.IsRequired()
.HasColumnName("Url")
.HasMaxLength(64);
b.HasKey("Id");
b.HasIndex("BlogId");
b.ToTable("BlgPosts");
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityRole")
.WithMany("Claims")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Claims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Logins")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Roles")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
{
b.HasOne("Volo.Abp.Identity.IdentityUser")
.WithMany("Tokens")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
{
b.HasOne("Volo.Blogging.Blogs.Blog")
.WithMany()
.HasForeignKey("BlogId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
{
public partial class Added_Url_To_Posts : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Url",
table: "BlgPosts",
maxLength: 64,
nullable: false,
defaultValue: "");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Url",
table: "BlgPosts");
}
}
}

@ -15,7 +15,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.0-rtm-30799")
.HasAnnotation("ProductVersion", "2.1.1-rtm-30846")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
@ -371,6 +371,11 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("Title")
.HasMaxLength(512);
b.Property<string>("Url")
.IsRequired()
.HasColumnName("Url")
.HasMaxLength(64);
b.HasKey("Id");
b.HasIndex("BlogId");

@ -11,6 +11,11 @@ namespace Volo.Blogging.Posts
[StringLength(PostConsts.MaxTitleLength)]
public string Title { get; set; }
[Required]
[StringLength(PostConsts.MaxUrlLength)]
public string Url { get; set; }
[StringLength(PostConsts.MaxContentLength)]
public string Content { get; set; }
}

@ -11,6 +11,8 @@ namespace Volo.Blogging.Posts
public string Title { get; set; }
public string Url { get; set; }
public string Content { get; set; }
}
}

@ -4,7 +4,7 @@ namespace Volo.Blogging.Posts
{
public class GetPostInput
{
public string Title { get; set; }
public string Url { get; set; }
public Guid BlogId { get; set; }
}

@ -11,7 +11,7 @@ namespace Volo.Blogging.Posts
{
ListResultDto<PostWithDetailsDto> GetListByBlogIdAsync(Guid id);
Task<PostWithDetailsDto> GetByTitleAsync(GetPostInput input);
Task<PostWithDetailsDto> GetByUrlAsync(GetPostInput input);
Task<PostWithDetailsDto> GetAsync(Guid id);

@ -9,6 +9,8 @@ namespace Volo.Blogging.Posts
public string Title { get; protected set; }
public string Url { get; set; }
public string Content { get; set; }
}
}

@ -11,6 +11,8 @@ namespace Volo.Blogging.Posts
public string Title { get; set; }
public string Url { get; set; }
public string Content { get; set; }
}
}

@ -11,6 +11,8 @@ namespace Volo.Blogging.Posts
public string Title { get; set; }
public string Url { get; set; }
public string Content { get; set; }
}
}

@ -27,9 +27,9 @@ namespace Volo.Blogging.Posts
ObjectMapper.Map<List<Post>, List<PostWithDetailsDto>>(posts));
}
public async Task<PostWithDetailsDto> GetByTitleAsync(GetPostInput input)
public async Task<PostWithDetailsDto> GetByUrlAsync(GetPostInput input)
{
var post = await _postRepository.GetPost(input.BlogId, input.Title);
var post = await _postRepository.GetPostByUrl(input.BlogId, input.Url);
return ObjectMapper.Map<Post, PostWithDetailsDto>(post);
}
@ -50,7 +50,8 @@ namespace Volo.Blogging.Posts
Id = post.Id,
BlogId = post.BlogId,
Content = post.Content,
Title = post.Title
Title = post.Title,
Url = post.Url
};
return dto;
@ -62,6 +63,7 @@ namespace Volo.Blogging.Posts
var post = await _postRepository.GetAsync(id);
post.SetTitle(input.Title);
post.SetUrl(input.Url);
post.Content = input.Content;
post = await _postRepository.UpdateAsync(post);
@ -76,7 +78,8 @@ namespace Volo.Blogging.Posts
id: GuidGenerator.Create(),
blogId: input.BlogId,
creatorId: CurrentUser.GetId(),
title: input.Title
title: input.Title,
url: input.Url
) {Content = input.Content};
await _postRepository.InsertAsync(post);

@ -4,6 +4,8 @@
{
public const int MaxTitleLength = 512;
public const int MaxUrlLength = 64;
public const int MaxContentLength = 1024 * 1024; //1MB
}
}

@ -9,6 +9,6 @@ namespace Volo.Blogging.Posts
{
List<Post> GetPostsByBlogId(Guid id);
Task<Post> GetPost(Guid blogId, string title);
Task<Post> GetPostByUrl(Guid blogId, string url);
}
}

@ -9,6 +9,9 @@ namespace Volo.Blogging.Posts
{
public virtual Guid BlogId { get; protected set; }
[NotNull]
public virtual string Url { get; protected set; }
[NotNull]
public virtual string Title { get; protected set; }
@ -20,12 +23,13 @@ namespace Volo.Blogging.Posts
}
public Post(Guid id, Guid blogId, Guid creatorId, [NotNull] string title)
public Post(Guid id, Guid blogId, Guid creatorId, [NotNull] string title, [NotNull] string url)
{
Id = id;
CreatorId = creatorId;
BlogId = blogId;
Title = Check.NotNullOrWhiteSpace(title, nameof(title));
Url = Check.NotNullOrWhiteSpace(url, nameof(url));
}
public virtual Post SetTitle([NotNull] string title)
@ -33,5 +37,11 @@ namespace Volo.Blogging.Posts
Title = Check.NotNullOrWhiteSpace(title, nameof(title));
return this;
}
public virtual Post SetUrl([NotNull] string url)
{
Url = Check.NotNullOrWhiteSpace(url, nameof(url));
return this;
}
}
}

@ -38,6 +38,7 @@ namespace Volo.Blogging.EntityFrameworkCore
b.Property(x => x.BlogId).HasColumnName(nameof(Post.BlogId));
b.Property(x => x.Title).IsRequired().HasMaxLength(PostConsts.MaxTitleLength).HasColumnName(nameof(Post.Title));
b.Property(x => x.Url).IsRequired().HasMaxLength(PostConsts.MaxUrlLength).HasColumnName(nameof(Post.Url));
b.Property(x => x.Content).IsRequired(false).HasMaxLength(PostConsts.MaxContentLength).HasColumnName(nameof(Post.Content));
b.HasOne<Blog>().WithMany().IsRequired().HasForeignKey(p => p.BlogId);

@ -24,9 +24,9 @@ namespace Volo.Blogging.Posts
return DbSet.Where(p => p.BlogId == id).ToList();
}
public async Task<Post> GetPost(Guid blogId, string title)
public async Task<Post> GetPostByUrl(Guid blogId, string url)
{
return await DbSet.FirstOrDefaultAsync(p => p.BlogId == blogId && p.Title == title);
return await DbSet.FirstOrDefaultAsync(p => p.BlogId == blogId && p.Url == url);
}
}
}

@ -53,7 +53,7 @@ namespace Volo.Blogging
{
//TODO: Make configurable!
options.Conventions.AddPageRoute("/Blog/Posts/Index", "blog/{blogShortName}");
options.Conventions.AddPageRoute("/Blog/Posts/Detail", "blog/{blogShortName}/{postTitle}");
options.Conventions.AddPageRoute("/Blog/Posts/Detail", "blog/{blogShortName}/{postUrl}");
options.Conventions.AddPageRoute("/Blog/Posts/Edit", "blog/{blogShortName}/posts/edit/{postId}");
options.Conventions.AddPageRoute("/Blog/Posts/New", "blog/{blogShortName}/posts/new");
});

@ -18,7 +18,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
public string BlogShortName { get; set; }
[BindProperty(SupportsGet = true)]
public string PostTitle { get; set; }
public string PostUrl { get; set; }
public PostWithDetailsDto Post { get; set; }
@ -34,7 +34,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
var blog = await _blogAppService.GetByShortNameAsync(BlogShortName);
Post = await _postAppService.GetByTitleAsync(new GetPostInput {BlogId = blog.Id , Title = PostTitle});
Post = await _postAppService.GetByUrlAsync(new GetPostInput {BlogId = blog.Id , Url = PostUrl});
Blog = blog;
}
}

@ -1,15 +1,12 @@
@page
@using Volo.Blogging.Pages.Blog.Posts
@model EditModel
@{
}
<form method="post" id="edit-post-form">
<abp-input asp-for="@Model.Post.Title" autofocus />
<abp-input asp-for="@Model.Post.Title" auto-focus="true" />
<abp-input asp-for="@Model.Post.Url" />
<div class="form-group">
<label>Content</label>

@ -37,13 +37,14 @@ namespace Volo.Blogging.Pages.Blog.Posts
{
BlogId = Post.BlogId,
Title = Post.Title,
Url = Post.Url,
Content = Post.Content
};
var editedPost = await _postAppService.UpdateAsync(Post.Id, post);
var blog = await _blogAppService.GetAsync(editedPost.BlogId);
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{editedPost.Title}"));
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{editedPost.Url}"));
}
}
@ -60,6 +61,11 @@ namespace Volo.Blogging.Pages.Blog.Posts
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[StringLength(PostConsts.MaxUrlLength)]
[Display(Name = "Url")]
public string Url { get; set; }
[StringLength(PostConsts.MaxContentLength)]
[Display(Name = "Content")]
public string Content { get; set; }

@ -12,6 +12,6 @@
<ul>
@foreach (var post in Model.Posts)
{
<li><a asp-page="./Detail" asp-route-postTitle="@post.Title" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a></li>
<li><a asp-page="./Detail" asp-route-postUrl="@post.Url" asp-route-blogShortName="@Model.BlogShortName">@post.Title</a></li>
}
</ul>

@ -5,6 +5,8 @@
<form method="post">
<abp-input asp-for="Post.Title" auto-focus="true" />
<abp-input asp-for="Post.Url" />
<div class="form-group">
<label>@L["Content"]</label>
<textarea rows="4" class="form-control" name="Post.Content">@Model.Post.Content</textarea>

@ -42,7 +42,7 @@ namespace Volo.Blogging.Pages.Blog.Posts
var postWithDetailsDto = await _postAppService.CreateAsync(ObjectMapper.Map<CreatePostViewModel,CreatePostDto>(Post));
//TODO: Try Url.Page(...)
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{postWithDetailsDto.Title}"));
return Redirect(Url.Content($"~/blog/{blog.ShortName}/{postWithDetailsDto.Url}"));
}
public class CreatePostViewModel
@ -55,6 +55,11 @@ namespace Volo.Blogging.Pages.Blog.Posts
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[StringLength(PostConsts.MaxUrlLength)]
[Display(Name = "Url")]
public string Url { get; set; }
[StringLength(PostConsts.MaxContentLength)]
[Display(Name = "Content")]
public string Content { get; set; }

Loading…
Cancel
Save