diff --git a/docs/en/Getting-Started-Console-Application.md b/docs/en/Getting-Started-Console-Application.md
index 006e447f0f..00c3d1e0a2 100644
--- a/docs/en/Getting-Started-Console-Application.md
+++ b/docs/en/Getting-Started-Console-Application.md
@@ -66,7 +66,7 @@ namespace AbpConsoleDemo
### Hello World!
-The application above does nothing. Let's create a service does something:
+The application above does nothing. Let's create a service that does something:
````C#
using System;
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
index 9c8944176b..fa4e348f4b 100644
--- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json
@@ -34,6 +34,7 @@
"PagerPrevious": "Previous",
"PagerInfo": "Showing {0} to {1} of {2} entries.",
"DatatableActionDropdownDefaultText": "Actions",
- "ChangePassword": "Change password"
+ "ChangePassword": "Change password",
+ "PersonalInfo": "Personal info"
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
index f85e255058..0215dfd071 100644
--- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json
@@ -34,6 +34,7 @@
"PagerPrevious": "Önceki",
"PagerInfo": "{2} kayıttan {0} ile {1} arası gösteriliyor.",
"DatatableActionDropdownDefaultText": "İşlemler",
- "ChangePassword": "Şifre değiştir"
+ "ChangePassword": "Şifre değiştir",
+ "PersonalInfo": "Kişisel Bilgiler"
}
}
\ No newline at end of file
diff --git a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
index d021cbabe1..2741aabe82 100644
--- a/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
+++ b/modules/account/src/Volo.Abp.Account.Web/AbpAccountUserMenuContributor.cs
@@ -24,6 +24,8 @@ namespace Volo.Abp.Account.Web
context.Menu.AddItem(new ApplicationMenuItem("Account.ChangePassword", l["ChangePassword"], icon: "fa fa-key", url: "#", elementId: "abp-account-change-password"));
+ context.Menu.AddItem(new ApplicationMenuItem("Account.PersonalSettings", l["PersonalInfo"], icon: "fa fa-info", url: "#", elementId: "abp-account-personal-settings"));
+
context.Menu.AddItem(new ApplicationMenuItem("Account.Logout", l["Logout"], url: "/Account/Logout", icon: "fa fa-power-off", order: int.MaxValue - 1000));
return Task.CompletedTask;
diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.Designer.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.Designer.cs
new file mode 100644
index 0000000000..4cd1b0c993
--- /dev/null
+++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.Designer.cs
@@ -0,0 +1,694 @@
+//
+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("20181108104704_Identity_Changes")]
+ partial class Identity_Changes
+ {
+ 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.IdentityClaimType", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Description")
+ .HasMaxLength(256);
+
+ b.Property("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("Regex")
+ .HasMaxLength(512);
+
+ b.Property("RegexDescription")
+ .HasMaxLength(128);
+
+ b.Property("Required");
+
+ b.Property("ValueType");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpClaimTypes");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ConcurrencyStamp");
+
+ b.Property("IsDefault")
+ .HasColumnName("IsDefault");
+
+ b.Property("IsPublic")
+ .HasColumnName("IsPublic");
+
+ b.Property("IsStatic")
+ .HasColumnName("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("NormalizedName")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName");
+
+ b.ToTable("AbpRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AbpRoleClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AccessFailedCount")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("AccessFailedCount")
+ .HasDefaultValue(0);
+
+ b.Property("ConcurrencyStamp")
+ .IsRequired()
+ .HasColumnName("ConcurrencyStamp")
+ .HasMaxLength(256);
+
+ b.Property("CreationTime");
+
+ b.Property("CreatorId");
+
+ b.Property("DeleterId");
+
+ b.Property("DeletionTime");
+
+ b.Property("Email")
+ .HasColumnName("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("EmailConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted");
+
+ b.Property("LastModificationTime");
+
+ b.Property("LastModifierId");
+
+ b.Property("LockoutEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("LockoutEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("LockoutEnd");
+
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("NormalizedEmail")
+ .HasColumnName("NormalizedEmail")
+ .HasMaxLength(256);
+
+ b.Property("NormalizedUserName")
+ .IsRequired()
+ .HasColumnName("NormalizedUserName")
+ .HasMaxLength(256);
+
+ b.Property("PasswordHash")
+ .HasColumnName("PasswordHash")
+ .HasMaxLength(256);
+
+ b.Property("PhoneNumber")
+ .HasColumnName("PhoneNumber")
+ .HasMaxLength(16);
+
+ b.Property("PhoneNumberConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("PhoneNumberConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("SecurityStamp")
+ .IsRequired()
+ .HasColumnName("SecurityStamp")
+ .HasMaxLength(256);
+
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("TwoFactorEnabled")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("TwoFactorEnabled")
+ .HasDefaultValue(false);
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ClaimType")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("ClaimValue")
+ .HasMaxLength(1024);
+
+ b.Property("TenantId");
+
+ b.Property("UserId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AbpUserClaims");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("ProviderDisplayName")
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(196);
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "LoginProvider");
+
+ b.HasIndex("LoginProvider", "ProviderKey");
+
+ b.ToTable("AbpUserLogins");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("RoleId");
+
+ b.Property("TenantId");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId", "UserId");
+
+ b.ToTable("AbpUserRoles");
+ });
+
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId");
+
+ b.Property("LoginProvider")
+ .HasMaxLength(64);
+
+ b.Property("Name")
+ .HasMaxLength(128);
+
+ b.Property("TenantId");
+
+ b.Property("Value");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AbpUserTokens");
+ });
+
+ modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .IsRequired()
+ .HasMaxLength(64);
+
+ b.Property("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpPermissionGrants");
+ });
+
+ modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128);
+
+ b.Property("ProviderKey")
+ .HasMaxLength(64);
+
+ b.Property("ProviderName")
+ .HasMaxLength(64);
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(2048);
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name", "ProviderName", "ProviderKey");
+
+ b.ToTable("AbpSettings");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasColumnName("Description")
+ .HasMaxLength(1024);
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnName("Name")
+ .HasMaxLength(256);
+
+ b.Property("ShortName")
+ .IsRequired()
+ .HasColumnName("ShortName")
+ .HasMaxLength(32);
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgBlogs");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Comments.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("PostId")
+ .HasColumnName("PostId");
+
+ b.Property("RepliedCommentId")
+ .HasColumnName("RepliedCommentId");
+
+ b.Property("Text")
+ .IsRequired()
+ .HasColumnName("Text")
+ .HasMaxLength(1024);
+
+ b.HasKey("Id");
+
+ b.HasIndex("PostId");
+
+ b.HasIndex("RepliedCommentId");
+
+ b.ToTable("BlgComments");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BlogId")
+ .HasColumnName("BlogId");
+
+ b.Property("Content")
+ .HasColumnName("Content")
+ .HasMaxLength(1048576);
+
+ b.Property("CoverImage")
+ .IsRequired()
+ .HasColumnName("CoverImage");
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("ReadCount");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnName("Title")
+ .HasMaxLength(512);
+
+ b.Property("Url")
+ .IsRequired()
+ .HasColumnName("Url")
+ .HasMaxLength(64);
+
+ b.HasKey("Id");
+
+ b.HasIndex("BlogId");
+
+ b.ToTable("BlgPosts");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b =>
+ {
+ b.Property("PostId")
+ .HasColumnName("PostId");
+
+ b.Property("TagId")
+ .HasColumnName("TagId");
+
+ b.Property("CreationTime");
+
+ b.Property("CreatorId");
+
+ b.HasKey("PostId", "TagId");
+
+ b.HasIndex("TagId");
+
+ b.ToTable("BlgPostTags");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Tagging.Tag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("CreationTime")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnName("DeletionTime");
+
+ b.Property("Description")
+ .HasColumnName("Description")
+ .HasMaxLength(512);
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("IsDeleted")
+ .HasDefaultValue(false);
+
+ b.Property("LastModificationTime")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("UsageCount")
+ .HasColumnName("UsageCount");
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgTags");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Users.BlogUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Email")
+ .HasColumnName("Email")
+ .HasMaxLength(256);
+
+ b.Property("EmailConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("EmailConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("ExtraProperties")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
+ b.Property("PhoneNumber")
+ .HasColumnName("PhoneNumber")
+ .HasMaxLength(16);
+
+ b.Property("PhoneNumberConfirmed")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("PhoneNumberConfirmed")
+ .HasDefaultValue(false);
+
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
+ b.Property("TenantId")
+ .HasColumnName("TenantId");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnName("UserName")
+ .HasMaxLength(256);
+
+ b.HasKey("Id");
+
+ b.ToTable("BlgUsers");
+ });
+
+ 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.Comments.Comment", b =>
+ {
+ b.HasOne("Volo.Blogging.Posts.Post")
+ .WithMany()
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Volo.Blogging.Comments.Comment")
+ .WithMany()
+ .HasForeignKey("RepliedCommentId");
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Posts.Post", b =>
+ {
+ b.HasOne("Volo.Blogging.Blogs.Blog")
+ .WithMany()
+ .HasForeignKey("BlogId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b =>
+ {
+ b.HasOne("Volo.Blogging.Posts.Post")
+ .WithMany("Tags")
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("Volo.Blogging.Tagging.Tag")
+ .WithMany()
+ .HasForeignKey("TagId")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.cs
new file mode 100644
index 0000000000..8e7a402cd7
--- /dev/null
+++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20181108104704_Identity_Changes.cs
@@ -0,0 +1,170 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
+{
+ public partial class Identity_Changes : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "Name",
+ table: "BlgUsers",
+ maxLength: 64,
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Surname",
+ table: "BlgUsers",
+ maxLength: 64,
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "CreationTime",
+ table: "AbpUsers",
+ nullable: false,
+ defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
+
+ migrationBuilder.AddColumn(
+ name: "CreatorId",
+ table: "AbpUsers",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "DeleterId",
+ table: "AbpUsers",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "DeletionTime",
+ table: "AbpUsers",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "IsDeleted",
+ table: "AbpUsers",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn(
+ name: "LastModificationTime",
+ table: "AbpUsers",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "LastModifierId",
+ table: "AbpUsers",
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Name",
+ table: "AbpUsers",
+ maxLength: 64,
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "Surname",
+ table: "AbpUsers",
+ maxLength: 64,
+ nullable: true);
+
+ migrationBuilder.AddColumn(
+ name: "IsDefault",
+ table: "AbpRoles",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn(
+ name: "IsPublic",
+ table: "AbpRoles",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn(
+ name: "IsStatic",
+ table: "AbpRoles",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.CreateTable(
+ name: "AbpClaimTypes",
+ columns: table => new
+ {
+ Id = table.Column(nullable: false),
+ Name = table.Column(maxLength: 256, nullable: false),
+ Required = table.Column(nullable: false),
+ IsStatic = table.Column(nullable: false),
+ Regex = table.Column(maxLength: 512, nullable: true),
+ RegexDescription = table.Column(maxLength: 128, nullable: true),
+ Description = table.Column(maxLength: 256, nullable: true),
+ ValueType = table.Column(nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_AbpClaimTypes", x => x.Id);
+ });
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "AbpClaimTypes");
+
+ migrationBuilder.DropColumn(
+ name: "Name",
+ table: "BlgUsers");
+
+ migrationBuilder.DropColumn(
+ name: "Surname",
+ table: "BlgUsers");
+
+ migrationBuilder.DropColumn(
+ name: "CreationTime",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "CreatorId",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "DeleterId",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "DeletionTime",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "IsDeleted",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "LastModificationTime",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "LastModifierId",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "Name",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "Surname",
+ table: "AbpUsers");
+
+ migrationBuilder.DropColumn(
+ name: "IsDefault",
+ table: "AbpRoles");
+
+ migrationBuilder.DropColumn(
+ name: "IsPublic",
+ table: "AbpRoles");
+
+ migrationBuilder.DropColumn(
+ name: "IsStatic",
+ table: "AbpRoles");
+ }
+ }
+}
diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs
index b59ab48a69..7c57df160e 100644
--- a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs
+++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs
@@ -19,6 +19,35 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
+ modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Description")
+ .HasMaxLength(256);
+
+ b.Property("IsStatic");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256);
+
+ b.Property("Regex")
+ .HasMaxLength(512);
+
+ b.Property("RegexDescription")
+ .HasMaxLength(128);
+
+ b.Property("Required");
+
+ b.Property("ValueType");
+
+ b.HasKey("Id");
+
+ b.ToTable("AbpClaimTypes");
+ });
+
modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b =>
{
b.Property("Id")
@@ -26,6 +55,15 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property("ConcurrencyStamp");
+ b.Property("IsDefault")
+ .HasColumnName("IsDefault");
+
+ b.Property("IsPublic")
+ .HasColumnName("IsPublic");
+
+ b.Property("IsStatic")
+ .HasColumnName("IsStatic");
+
b.Property("Name")
.IsRequired()
.HasMaxLength(256);
@@ -81,6 +119,14 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("ConcurrencyStamp")
.HasMaxLength(256);
+ b.Property("CreationTime");
+
+ b.Property("CreatorId");
+
+ b.Property("DeleterId");
+
+ b.Property("DeletionTime");
+
b.Property("Email")
.HasColumnName("Email")
.HasMaxLength(256);
@@ -93,6 +139,12 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property("ExtraProperties")
.HasColumnName("ExtraProperties");
+ b.Property("IsDeleted");
+
+ b.Property("LastModificationTime");
+
+ b.Property("LastModifierId");
+
b.Property("LockoutEnabled")
.ValueGeneratedOnAdd()
.HasColumnName("LockoutEnabled")
@@ -100,6 +152,10 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property("LockoutEnd");
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
b.Property("NormalizedEmail")
.HasColumnName("NormalizedEmail")
.HasMaxLength(256);
@@ -127,6 +183,10 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("SecurityStamp")
.HasMaxLength(256);
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
b.Property("TenantId")
.HasColumnName("TenantId");
@@ -219,9 +279,10 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property("UserId");
b.Property("LoginProvider")
- .HasMaxLength(128);
+ .HasMaxLength(64);
- b.Property("Name");
+ b.Property("Name")
+ .HasMaxLength(128);
b.Property("TenantId");
@@ -518,6 +579,10 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
b.Property("ExtraProperties")
.HasColumnName("ExtraProperties");
+ b.Property("Name")
+ .HasColumnName("Name")
+ .HasMaxLength(64);
+
b.Property("PhoneNumber")
.HasColumnName("PhoneNumber")
.HasMaxLength(16);
@@ -527,6 +592,10 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations
.HasColumnName("PhoneNumberConfirmed")
.HasDefaultValue(false);
+ b.Property("Surname")
+ .HasColumnName("Surname")
+ .HasMaxLength(64);
+
b.Property("TenantId")
.HasColumnName("TenantId");
diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj
index f4de95d72b..0e83df5472 100644
--- a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj
+++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Volo.BloggingTestApp.EntityFrameworkCore.csproj
@@ -4,6 +4,10 @@
netstandard2.0
+
+
+
+
diff --git a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Users/BlogUser.cs b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Users/BlogUser.cs
index cde09cdb4d..56f8287b19 100644
--- a/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Users/BlogUser.cs
+++ b/modules/blogging/src/Volo.Blogging.Domain/Volo/Blogging/Users/BlogUser.cs
@@ -14,6 +14,10 @@ namespace Volo.Blogging.Users
public virtual string Email { get; protected set; }
+ public virtual string Name { get; set; }
+
+ public virtual string Surname { get; set; }
+
public virtual bool EmailConfirmed { get; protected set; }
public virtual string PhoneNumber { get; protected set; }
@@ -31,6 +35,8 @@ namespace Volo.Blogging.Users
{
Id = user.Id;
Email = user.Email;
+ Name = user.Name;
+ Surname = user.Surname;
EmailConfirmed = user.EmailConfirmed;
PhoneNumber = user.PhoneNumber;
PhoneNumberConfirmed = user.PhoneNumberConfirmed;
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IProfileAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IProfileAppService.cs
new file mode 100644
index 0000000000..9e0a5cbacf
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IProfileAppService.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Volo.Abp.Application.Services;
+
+namespace Volo.Abp.Identity
+{
+ public interface IProfileAppService : IApplicationService
+ {
+ Task GetAsync();
+
+ Task UpdateAsync(UpdateProfileDto input);
+ }
+}
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs
index a3461fcd90..0715d2512a 100644
--- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs
@@ -9,6 +9,12 @@ namespace Volo.Abp.Identity
[StringLength(IdentityUserConsts.MaxUserNameLength)]
public string UserName { get; set; }
+ [StringLength(IdentityUserConsts.MaxNameLength)]
+ public string Name { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxSurnameLength)]
+ public string Surname { get; set; }
+
[Required]
[EmailAddress]
[StringLength(IdentityUserConsts.MaxEmailLength)]
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs
index 893d2ea710..bc28a79f8e 100644
--- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs
@@ -4,12 +4,16 @@ using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Identity
{
- public class IdentityUserDto : EntityDto, IMultiTenant
+ public class IdentityUserDto : FullAuditedEntityDto, IMultiTenant
{
public Guid? TenantId { get; set; }
public string UserName { get; set; }
+ public string Name { get; set; }
+
+ public string Surname { get; set; }
+
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs
new file mode 100644
index 0000000000..ac9b09e287
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs
@@ -0,0 +1,15 @@
+namespace Volo.Abp.Identity
+{
+ public class ProfileDto
+ {
+ public string UserName { get; set; }
+
+ public string Email { get; set; }
+
+ public string Name { get; set; }
+
+ public string Surname { get; set; }
+
+ public string PhoneNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs
new file mode 100644
index 0000000000..40a576f871
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Volo.Abp.Identity
+{
+ public class UpdateProfileDto
+ {
+ [StringLength(IdentityUserConsts.MaxUserNameLength)]
+ public string UserName { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxEmailLength)]
+ public string Email { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxNameLength)]
+ public string Name { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxSurnameLength)]
+ public string Surname { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxPhoneNumberLength)]
+ public string PhoneNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
index c20c4109f3..054ce247ac 100644
--- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Security.Authentication;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
@@ -149,6 +150,9 @@ namespace Volo.Abp.Identity
(await _userManager.SetTwoFactorEnabledAsync(user, input.TwoFactorEnabled)).CheckErrors();
(await _userManager.SetLockoutEnabledAsync(user, input.LockoutEnabled)).CheckErrors();
+ user.Name = input.Name;
+ user.Surname = input.Surname;
+
if (input.RoleNames != null)
{
(await _userManager.SetRolesAsync(user, input.RoleNames)).CheckErrors();
diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs
new file mode 100644
index 0000000000..d133350921
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Volo.Abp.Users;
+
+namespace Volo.Abp.Identity
+{
+ [Authorize]
+ public class ProfileAppService : IdentityAppServiceBase, IProfileAppService
+ {
+ private readonly IdentityUserManager _userManager;
+
+ public ProfileAppService(IdentityUserManager userManager)
+ {
+ _userManager = userManager;
+ }
+
+ public async Task GetAsync()
+ {
+ return ObjectMapper.Map(
+ await _userManager.GetByIdAsync(CurrentUser.GetId())
+ );
+ }
+
+ public async Task UpdateAsync(UpdateProfileDto input)
+ {
+ var user = await _userManager.GetByIdAsync(CurrentUser.GetId());
+
+ (await _userManager.SetUserNameAsync(user, input.UserName)).CheckErrors();
+ (await _userManager.SetEmailAsync(user, input.Email)).CheckErrors();
+ (await _userManager.SetPhoneNumberAsync(user, input.PhoneNumber)).CheckErrors();
+ user.Name = input.Name;
+ user.Surname = input.Surname;
+
+ (await _userManager.UpdateAsync(user)).CheckErrors();
+ await CurrentUnitOfWork.SaveChangesAsync();
+
+ return ObjectMapper.Map(user);
+ }
+ }
+}
diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs
index c41c63280d..f56a59e967 100644
--- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/IdentityUserConsts.cs
@@ -6,6 +6,10 @@ namespace Volo.Abp.Identity
{
public const int MaxUserNameLength = AbpUserConsts.MaxUserNameLength;
+ public const int MaxNameLength = AbpUserConsts.MaxNameLength;
+
+ public const int MaxSurnameLength = AbpUserConsts.MaxSurnameLength;
+
public const int MaxNormalizedUserNameLength = MaxUserNameLength;
public const int MaxEmailLength = AbpUserConsts.MaxEmailLength;
diff --git a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs
index a381ec66ba..dc93110075 100644
--- a/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUser.cs
@@ -8,12 +8,13 @@ using Microsoft.AspNetCore.Identity;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
+using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.Guids;
using Volo.Abp.Users;
namespace Volo.Abp.Identity
{
- public class IdentityUser : AggregateRoot, IHasConcurrencyStamp, IUser, IHasExtraProperties
+ public class IdentityUser : FullAuditedAggregateRoot, IHasConcurrencyStamp, IUser, IHasExtraProperties
{
public virtual Guid? TenantId { get; protected set; }
@@ -28,6 +29,16 @@ namespace Volo.Abp.Identity
[DisableAuditing]
public virtual string NormalizedUserName { get; protected internal set; }
+ ///
+ /// Gets or sets the Name for the user.
+ ///
+ public virtual string Name { get; set; }
+
+ ///
+ /// Gets or sets the Surame for the user.
+ ///
+ public virtual string Surname { get; set; }
+
///
/// Gets or sets the email address for this user.
///
diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserExtensions.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserExtensions.cs
index 3535bb5904..bdb1e9044e 100644
--- a/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserExtensions.cs
+++ b/modules/identity/src/Volo.Abp.Identity.HttpApi.Client/Volo/Abp/Identity/IdentityUserExtensions.cs
@@ -10,6 +10,8 @@ namespace Volo.Abp.Identity
user.Id,
user.UserName,
user.Email,
+ user.Name,
+ user.Surname,
user.EmailConfirmed,
user.PhoneNumber,
user.PhoneNumberConfirmed,
diff --git a/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs
new file mode 100644
index 0000000000..449383956b
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/ProfileController.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Volo.Abp.Identity
+{
+ [RemoteService]
+ [Area("identity")]
+ [ControllerName("Profile")]
+ public class ProfileController : IProfileAppService
+ {
+ private readonly IProfileAppService _profileAppService;
+
+ public ProfileController(IProfileAppService profileAppService)
+ {
+ _profileAppService = profileAppService;
+ }
+ public Task GetAsync()
+ {
+ return _profileAppService.GetAsync();
+ }
+
+ public Task UpdateAsync(UpdateProfileDto input)
+ {
+ return _profileAppService.UpdateAsync(input);
+ }
+ }
+}
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs
index c8651d8e88..4c991466e9 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs
@@ -1,5 +1,6 @@
using AutoMapper;
using Volo.Abp.Identity.Web.Pages.Identity.Roles;
+using Volo.Abp.Identity.Web.Pages.Identity.Shared;
using CreateUserModalModel = Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel;
using EditUserModalModel = Volo.Abp.Identity.Web.Pages.Identity.Users.EditModalModel;
@@ -11,6 +12,7 @@ namespace Volo.Abp.Identity.Web
{
CreateUserMappings();
CreateRoleMappings();
+ CreateProfileMappings();
}
private void CreateUserMappings()
@@ -31,6 +33,10 @@ namespace Volo.Abp.Identity.Web
CreateMap()
.ForMember(dest => dest.IsAssigned, opt => opt.Ignore());
+
+ CreateMap();
+
+ CreateMap();
}
private void CreateRoleMappings()
@@ -44,5 +50,11 @@ namespace Volo.Abp.Identity.Web
//EditModal
CreateMap();
}
+
+ private void CreateProfileMappings()
+ {
+ CreateMap();
+ CreateMap();
+ }
}
}
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
index f898ad3ea3..934d0460b2 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs
@@ -75,7 +75,8 @@ namespace Volo.Abp.Identity.Web
options
.ScriptBundles
.Get(StandardBundles.Scripts.Global)
- .AddFiles("/Pages/Identity/Shared/change-password-modal.js");
+ .AddFiles("/Pages/Identity/Shared/change-password-modal.js")
+ .AddFiles("/Pages/Identity/Shared/personal-settings-modal.js");
});
}
}
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
index 3e97ea3700..e16e24134b 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/en.json
@@ -13,10 +13,14 @@
"DisplayName:IsPublic": "Public",
"Roles": "Roles",
"Password": "Password",
+ "PersonalInfo": "Personal Info",
+ "PersonalSettings": "Personal settings",
"UserDeletionConfirmationMessage": "User '{0}' will be deleted. Do you confirm that?",
"RoleDeletionConfirmationMessage": "Role '{0}' will be deleted. Do you confirm that?",
"DisplayName:RoleName": "Role name",
"DisplayName:UserName": "User name",
+ "DisplayName:Name": "Name",
+ "DisplayName:Surname": "Surname",
"DisplayName:Password": "Password",
"DisplayName:EmailAddress": "Email address",
"DisplayName:PhoneNumber": "Phone number",
@@ -29,6 +33,7 @@
"DisplayName:CurrentPassword": "Current password",
"DisplayName:NewPassword": "New password",
"DisplayName:NewPasswordConfirm": "Confirm new password",
- "PasswordChangedMessage": "Your password has been changed successfully."
+ "PasswordChangedMessage": "Your password has been changed successfully.",
+ "PersonalSettingsSavedMessage": "Your personal settings has been saved successfully."
}
}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json
index e0ecf1b5cb..5393b25f43 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Localization/Resources/AbpIdentity/tr.json
@@ -13,10 +13,14 @@
"UserInformations": "Kullanıcı bilgileri",
"Roles": "Roller",
"Password": "Şifre",
+ "PersonalInfo": "Kişisel bilgi",
+ "PersonalSettings": "Kişisel Ayarlar",
"UserDeletionConfirmationMessage": "{0} kullanıcısı silinecektir. Onaylıyor musunuz?",
"RoleDeletionConfirmationMessage": "'{0}' rolü silinecektir. Onaylıyor musunuz?",
"DisplayName:RoleName": "Rol adı",
"DisplayName:UserName": "Kullanıcı adı",
+ "DisplayName:Name": "Adı",
+ "DisplayName:Surname": "Soyadı",
"DisplayName:Password": "Şifre",
"DisplayName:EmailAddress": "E-posta adresi",
"DisplayName:PhoneNumber": "Telefon numarası",
@@ -30,6 +34,7 @@
"DisplayName:NewPassword": "Yeni şifre",
"DisplayName:NewPasswordConfirm": "Yeni şifre (tekrar)",
"PasswordChangedMessage": "Şifreniz başarıyla değiştirildi.",
+ "PersonalSettingsSavedMessage": "Kişisel bilgileriniz başarıyla kaydedildi.",
"Identity.StaticRoleRenamingErrorMessage": "Bir Sabit rolün ismi değiştirilemez.",
"Identity.StaticRoleDeletionErrorMessage": "Bir Sabit rol silinemez."
}
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml
new file mode 100644
index 0000000000..e6d828dd39
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml
@@ -0,0 +1,20 @@
+@page
+@using Microsoft.AspNetCore.Mvc.Localization
+@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
+@using Volo.Abp.Identity.Localization
+@using Volo.Abp.Identity.Web.Pages.Identity.Shared
+@model PersonalSettingsModal
+@inject IHtmlLocalizer L
+@{
+ Layout = null;
+}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml.cs
new file mode 100644
index 0000000000..6799b3a971
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/PersonalSettingsModal.cshtml.cs
@@ -0,0 +1,66 @@
+using System.ComponentModel.DataAnnotations;
+using System.Security.Authentication;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Localization;
+using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
+using Volo.Abp.Identity.Localization;
+
+namespace Volo.Abp.Identity.Web.Pages.Identity.Shared
+{
+ public class PersonalSettingsModal : AbpPageModel
+ {
+ [BindProperty]
+ public PersonalSettingsInfoModel PersonalSettingsInfoModel { get; set; }
+
+ private readonly IProfileAppService _profileAppService;
+
+ public PersonalSettingsModal(IProfileAppService profileAppService)
+ {
+ _profileAppService = profileAppService;
+ }
+
+ public async Task OnGetAsync()
+ {
+ var user = await _profileAppService.GetAsync();
+
+ PersonalSettingsInfoModel = ObjectMapper.Map(user);
+ }
+
+ public async Task OnPostAsync()
+ {
+ ValidateModel();
+
+ var updateDto = ObjectMapper.Map(PersonalSettingsInfoModel);
+
+ await _profileAppService.UpdateAsync(updateDto);
+
+ return NoContent();
+ }
+ }
+
+ public class PersonalSettingsInfoModel
+ {
+ [Required]
+ [StringLength(IdentityUserConsts.MaxUserNameLength)]
+ [Display(Name = "DisplayName:UserName")]
+ public string UserName { get; set; }
+
+ [Required]
+ [StringLength(IdentityUserConsts.MaxEmailLength)]
+ [Display(Name = "DisplayName:Email")]
+ public string Email { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxNameLength)]
+ [Display(Name = "DisplayName:Name")]
+ public string Name { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxSurnameLength)]
+ [Display(Name = "DisplayName:Surname")]
+ public string Surname { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxPhoneNumberLength)]
+ [Display(Name = "DisplayName:PhoneNumber")]
+ public string PhoneNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/personal-settings-modal.js b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/personal-settings-modal.js
new file mode 100644
index 0000000000..36cd526a29
--- /dev/null
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Shared/personal-settings-modal.js
@@ -0,0 +1,18 @@
+(function ($) {
+
+ var l = abp.localization.getResource('AbpIdentity');
+ var _personalSettingsModal = new abp.ModalManager(abp.appPath + 'Identity/Shared/PersonalSettingsModal');
+
+ $(function () {
+
+ $("#abp-account-personal-settings").click(function (e) {
+ e.preventDefault();
+ _personalSettingsModal.open();
+ });
+
+ _personalSettingsModal.onResult(function () {
+ //abp.message.success(l("PersonalSettingsSavedMessage"));
+ });
+ });
+
+})(jQuery);
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml
index 448d5c5633..ed45747c0c 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml
@@ -15,6 +15,8 @@
@* TODO: Can we use dynamic form? *@
+
+
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs
index 15eb60a0b6..ce7a5a0507 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/CreateModal.cshtml.cs
@@ -56,6 +56,12 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users
[StringLength(IdentityUserConsts.MaxUserNameLength)]
public string UserName { get; set; }
+ [StringLength(IdentityUserConsts.MaxNameLength)]
+ public string Name { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxSurnameLength)]
+ public string Surname { get; set; }
+
[Required]
[StringLength(IdentityUserConsts.MaxPasswordLength)]
[DataType(DataType.Password)]
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml
index 639918d8ad..afa0df85ed 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml
@@ -14,12 +14,14 @@
@* TODO: Can we use dynamic form? *@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@for (var i = 0; i < Model.Roles.Length; i++)
diff --git a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs
index c9bac5c792..25615aca94 100644
--- a/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs
+++ b/modules/identity/src/Volo.Abp.Identity.Web/Pages/Identity/Users/EditModal.cshtml.cs
@@ -63,6 +63,12 @@ namespace Volo.Abp.Identity.Web.Pages.Identity.Users
[StringLength(IdentityUserConsts.MaxUserNameLength)]
public string UserName { get; set; }
+ [StringLength(IdentityUserConsts.MaxNameLength)]
+ public string Name { get; set; }
+
+ [StringLength(IdentityUserConsts.MaxSurnameLength)]
+ public string Surname { get; set; }
+
[Required]
[EmailAddress]
[StringLength(IdentityUserConsts.MaxEmailLength)]
diff --git a/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs
new file mode 100644
index 0000000000..70f626ccbc
--- /dev/null
+++ b/modules/identity/test/Volo.Abp.Identity.Application.Tests/Volo/Abp/Identity/ProfileAppService_Tests.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.Extensions.DependencyInjection;
+using NSubstitute;
+using Shouldly;
+using Volo.Abp.Users;
+using Xunit;
+
+namespace Volo.Abp.Identity
+{
+ public class ProfileAppService_Tests : AbpIdentityApplicationTestBase
+ {
+ private readonly IProfileAppService _profileAppService;
+ private readonly IIdentityUserRepository _userRepository;
+ private readonly SignInManager _signInManager;
+ private readonly IdentityTestData _testData;
+ private ICurrentUser _currentUser;
+
+ public ProfileAppService_Tests()
+ {
+ _profileAppService = GetRequiredService();
+ _userRepository = GetRequiredService();
+ _signInManager = GetRequiredService>();
+ _testData = GetRequiredService();
+ }
+
+ protected override void AfterAddApplication(IServiceCollection services)
+ {
+ _currentUser = Substitute.For();
+ services.AddSingleton(_currentUser);
+ }
+
+ [Fact]
+ public async Task GetAsync()
+ {
+ //Arrange
+ _currentUser.Id.Returns(_testData.UserJohnId);
+ _currentUser.IsAuthenticated.Returns(true);
+
+ //Act
+ var result = await _profileAppService.GetAsync();
+
+ //Assert
+ var johnNash = GetUser("john.nash");
+
+ result.UserName.ShouldBe(johnNash.UserName);
+ result.Email.ShouldBe(johnNash.Email);
+ result.PhoneNumber.ShouldBe(johnNash.PhoneNumber);
+ }
+
+
+ [Fact]
+ public async Task UpdateAsync()
+ {
+ //Arrange
+
+ //Arrange
+ _currentUser.Id.Returns(_testData.UserJohnId);
+ _currentUser.IsAuthenticated.Returns(true);
+
+ var input = new UpdateProfileDto
+ {
+ UserName = CreateRandomString(),
+ PhoneNumber = CreateRandomPhoneNumber(),
+ Email = CreateRandomEmail(),
+ Name = CreateRandomString(),
+ Surname = CreateRandomString()
+ };
+
+ //Act
+ var result = await _profileAppService.UpdateAsync(input);
+
+ //Assert
+ result.UserName.ShouldBe(input.UserName);
+ result.Email.ShouldBe(input.Email);
+ result.PhoneNumber.ShouldBe(input.PhoneNumber);
+ result.Surname.ShouldBe(input.Surname);
+ result.Name.ShouldBe(input.Name);
+ }
+
+ private static string CreateRandomEmail()
+ {
+ return CreateRandomString() + "@abp.io";
+ }
+
+ private static string CreateRandomString()
+ {
+ return Guid.NewGuid().ToString("N").Left(16);
+ }
+
+ private static string CreateRandomPhoneNumber()
+ {
+ return RandomHelper.GetRandom(10000000, 100000000).ToString();
+ }
+ }
+}
diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IUserData.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IUserData.cs
index e7c0d8dab7..f4f2874c7f 100644
--- a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IUserData.cs
+++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/IUserData.cs
@@ -11,6 +11,10 @@ namespace Volo.Abp.Users
string UserName { get; }
+ string Name { get; }
+
+ string Surname { get; }
+
[CanBeNull]
string Email { get; }
diff --git a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserData.cs b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserData.cs
index 7ed587cb9c..be70f20047 100644
--- a/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserData.cs
+++ b/modules/users/src/Volo.Abp.Users.Abstractions/Volo/Abp/Users/UserData.cs
@@ -9,6 +9,10 @@ namespace Volo.Abp.Users
public string UserName { get; set; }
+ public string Name { get; set; }
+
+ public string Surname { get; set; }
+
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
@@ -28,6 +32,8 @@ namespace Volo.Abp.Users
Guid id,
[NotNull] string userName,
[CanBeNull] string email = null,
+ [CanBeNull] string name = null,
+ [CanBeNull] string surname = null,
bool emailConfirmed = false,
[CanBeNull] string phoneNumber = null,
bool phoneNumberConfirmed = false,
@@ -36,6 +42,8 @@ namespace Volo.Abp.Users
Id = id;
UserName = userName;
Email = email;
+ Name = name;
+ Surname = surname;
EmailConfirmed = emailConfirmed;
PhoneNumber = phoneNumber;
PhoneNumberConfirmed = phoneNumberConfirmed;
diff --git a/modules/users/src/Volo.Abp.Users.Domain.Shared/Volo/Abp/Users/AbpUserConsts.cs b/modules/users/src/Volo.Abp.Users.Domain.Shared/Volo/Abp/Users/AbpUserConsts.cs
index 96fecdd60e..acfce7f37b 100644
--- a/modules/users/src/Volo.Abp.Users.Domain.Shared/Volo/Abp/Users/AbpUserConsts.cs
+++ b/modules/users/src/Volo.Abp.Users.Domain.Shared/Volo/Abp/Users/AbpUserConsts.cs
@@ -3,6 +3,10 @@ namespace Volo.Abp.Users
public class AbpUserConsts
{
public const int MaxUserNameLength = 256;
+
+ public const int MaxNameLength = 64;
+
+ public const int MaxSurnameLength = 64;
public const int MaxEmailLength = 256;
diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/AbpUserExtensions.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/AbpUserExtensions.cs
index 19dea86bf5..41c3c30e3c 100644
--- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/AbpUserExtensions.cs
+++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/AbpUserExtensions.cs
@@ -7,6 +7,8 @@ namespace Volo.Abp.Users
return new UserData(
user.Id,
user.UserName,
+ user.Name,
+ user.Surname,
user.Email,
user.EmailConfirmed,
user.PhoneNumber,
diff --git a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUser.cs b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUser.cs
index 374c41a0b7..2b06e8de97 100644
--- a/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUser.cs
+++ b/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/IUser.cs
@@ -12,6 +12,12 @@ namespace Volo.Abp.Users
[CanBeNull]
string Email { get; }
+ [CanBeNull]
+ string Name { get; }
+
+ [CanBeNull]
+ string Surname { get; }
+
bool EmailConfirmed { get; }
[CanBeNull]
diff --git a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs
index 1367fc423e..108b3f4278 100644
--- a/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs
+++ b/modules/users/src/Volo.Abp.Users.EntityFrameworkCore/Volo/Abp/Users/EntityFrameworkCore/AbpUsersDbContextModelCreatingExtensions.cs
@@ -12,6 +12,8 @@ namespace Volo.Abp.Users.EntityFrameworkCore
b.Property(u => u.TenantId).HasColumnName(nameof(IUser.TenantId));
b.Property(u => u.UserName).IsRequired().HasMaxLength(AbpUserConsts.MaxUserNameLength).HasColumnName(nameof(IUser.UserName));
b.Property(u => u.Email).HasMaxLength(AbpUserConsts.MaxEmailLength).HasColumnName(nameof(IUser.Email));
+ b.Property(u => u.Name).HasMaxLength(AbpUserConsts.MaxNameLength).HasColumnName(nameof(IUser.Name));
+ b.Property(u => u.Surname).HasMaxLength(AbpUserConsts.MaxSurnameLength).HasColumnName(nameof(IUser.Surname));
b.Property(u => u.EmailConfirmed).HasDefaultValue(false).HasColumnName(nameof(IUser.EmailConfirmed));
b.Property(u => u.PhoneNumber).HasMaxLength(AbpUserConsts.MaxPhoneNumberLength).HasColumnName(nameof(IUser.PhoneNumber));
b.Property(u => u.PhoneNumberConfirmed).HasDefaultValue(false).HasColumnName(nameof(IUser.PhoneNumberConfirmed));