Skip to content

Commit

Permalink
Reset password feature with email star data (#93)
Browse files Browse the repository at this point in the history
* feature(User): add tokens db

* fix(user)add token repository

* fix(user) : add email service

* fix(user) : complete email service

* fix(user) : check email service and we recived an email

* fix(token) : fix token validation

* feat(User) : fix Reset Password

* fix(User) : add reset password from user service in new arthitecture

* fix(Migrations) : add new migrations
  • Loading branch information
mahdijafariii authored Sep 7, 2024
1 parent 822a8c5 commit fa7198e
Show file tree
Hide file tree
Showing 36 changed files with 1,045 additions and 114 deletions.
25 changes: 17 additions & 8 deletions AnalysisData/AnalysisData.sln.DotSettings.user
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,8 @@
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=4036527e_002D1256_002D400e_002D9592_002Dd58dfbe85769/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="All tests from &amp;lt;TestProject&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="C:\Users\amir\Desktop\New folder (4)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=57d88556_002Dabe9_002D4ba5_002Da041_002D358ccf783382/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="AddFileToDb_ShouldReturnCategoryId_WhenCategoryIdAdded" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Graph.Service.FileUploadServiceTests.UploadFileServiceTests.AddFileToDb_ShouldReturnFileId_WhenFileIsAdded&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=57d88556_002Dabe9_002D4ba5_002Da041_002D358ccf783382/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="AddFileToDb_ShouldReturnCategoryId_WhenCategoryIdAdded" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="C:\Users\Mahdi\Desktop\New folder (2)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=580d1d66_002D6a9d_002D41c5_002D9bbc_002D4f090dd2983a/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="GetAllNodesAsync_ShouldReturnsPaginatedNodes_WhenNodesExist #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
Expand All @@ -56,6 +54,16 @@
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Repository.UserRepository.UserRepositoryTests&lt;/TestId&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Repository.RoleRepository.RoleRepositoryTests.DeleteRole_ShouldReturnsFalse_WhenRoleDoesNotExist&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=68034445_002Da1d4_002D4956_002D8b75_002D9bad7fa07f74/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="ResetPasswordAsync_ShouldCallValidatePasswordAndConfirmation_WhenCalled #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.User.Services.UserService.BuisinessTests.PasswordManagerTests.ResetPasswordAsync_ShouldCallValidatePasswordAndConfirmation_WhenCalled&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=78c742c3_002D725a_002D4ffe_002D8c86_002D1f8910bcc4e8/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="ResetPasswordAsync_ShouldCallValidatePasswordAndConfirmation_WhenCalled" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.User.Services.UserService.BuisinessTests.PasswordManagerTests.ResetPasswordAsync_ShouldCallValidatePasswordAndConfirmation_WhenCalled&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=826a2c7b_002D653f_002D4c68_002D93e1_002Db3cd3a5e8b15/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="AccessFileToUserAsync_ShouldAccessFilesToInputUsers_WhenFileAndUserExist #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=7daf18b0_002D56cf_002D4c0c_002Da004_002D0da528af25ea/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="CheckExistenceOfRole_ShouldNotThrowException_WhenRoleExists" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
Expand Down Expand Up @@ -88,7 +96,7 @@
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.User.Controllers.RoleControllerTests.GetAllRoles_ReturnsOkResult_WithRolesAndCount&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=88874ef4_002De555_002D4c0a_002Db58b_002Da18db20161dc/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="GetRelationalEdgeBaseNodeAsync_ShouldReturnNodesAndEdges_WhenUserIsDataAnalyst_AndNodeIsAccessible" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=88874ef4_002De555_002D4c0a_002Db58b_002Da18db20161dc/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="GetRelationalEdgeBaseNodeAsync_ShouldReturnNodesAndEdges_WhenUserIsDataAnalyst_AndNodeIsAccessible" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Graph.Service.GraphServices.Relationship.GraphRelationServiceTests&lt;/TestId&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.Graph.Service.GraphServices.Search.GraphSearchServiceTests.SearchInEntityNodeNameAsync_ShouldReturnResults_WhenRoleIsAdminAndSearchTypeStartsWith&lt;/TestId&gt;&#xD;
Expand Down Expand Up @@ -129,9 +137,10 @@
&lt;Project Location="C:\Users\Mahdi\Desktop\New folder (2)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=ce35ecc6_002D100e_002D4f4e_002Daba0_002D7678c76dbbbe/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="DeleteRole_ShouldRemovesRoleAndReturnsTrue_WhenRoleExists" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
&lt;TestId&gt;xUnit::9AEC1F3F-B1B3-47C1-82D4-E432E2D77E0E::net8.0::TestProject.User.Repository.RoleRepository.RoleRepositoryTests&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;Project Location="C:\Users\Mahdi\Desktop\New folder (2)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=fe4fe44b_002D7953_002D4423_002Dac04_002Da7f1b464e5c0/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="ResetPasswordAsync_ShouldCallPasswordCheck_WhenCalled" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="C:\Users\Mahdi\Desktop\New folder (2)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=ff0aa496_002Df562_002D44d7_002Db40c_002D780e81cc354b/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" Name="All tests from &amp;lt;TestProject&amp;gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="C:\Users\Mahdi\Desktop\New folder (2)\Summer1403-Project-Group03-Backend\AnalysisData\TestProject" Presentation="&amp;lt;TestProject&amp;gt;" /&gt;&#xD;
Expand Down
13 changes: 13 additions & 0 deletions AnalysisData/AnalysisData/ConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@
using AnalysisData.User.CookieService.abstractions;
using AnalysisData.User.JwtService;
using AnalysisData.User.JwtService.abstractions;
using AnalysisData.User.Repository.PasswordResetTokensRepository;
using AnalysisData.User.Repository.PasswordResetTokensRepository.Abstraction;
using AnalysisData.User.Repository.RoleRepository;
using AnalysisData.User.Repository.RoleRepository.Abstraction;
using AnalysisData.User.Repository.UserRepository;
using AnalysisData.User.Repository.UserRepository.Abstraction;
using AnalysisData.User.Services.AdminService;
using AnalysisData.User.Services.AdminService.Abstraction;
using AnalysisData.User.Services.EmailService;
using AnalysisData.User.Services.PermissionService;
using AnalysisData.User.Services.PermissionService.Abstraction;
using AnalysisData.User.Services.RoleService;
Expand All @@ -45,6 +48,7 @@
using AnalysisData.User.Services.S3FileStorageService.Abstraction;
using AnalysisData.User.Services.SecurityPasswordService;
using AnalysisData.User.Services.SecurityPasswordService.Abstraction;
using AnalysisData.User.Services.TokenService.Abstraction;
using AnalysisData.User.Services.UserService;
using AnalysisData.User.Services.UserService.Abstraction;
using AnalysisData.User.Services.UserService.Business;
Expand Down Expand Up @@ -73,6 +77,8 @@ public static IServiceCollection AddRepositories(this IServiceCollection service
services.AddScoped<ICategoryRepository, CategoryRepository>();
services.AddScoped<IFileUploadedRepository, FileUploadedRepository>();
services.AddScoped<IUserFileRepository, UserFileRepository>();
services.AddScoped<IPasswordResetTokensRepository, PasswordResetTokensRepository>();

return services;
}

Expand Down Expand Up @@ -122,6 +128,13 @@ public static IServiceCollection AddServices(this IServiceCollection services)
services.AddScoped<IValueNodeProcessor, ValueNodeProcessor>();
services.AddScoped<IEntityEdgeRecordProcessor, EntityEdgeRecordProcessor>();
services.AddScoped<IValueEdgeProcessor, ValueEdgeProcessor>();
services.AddScoped<IEdgeToDbService, EdgeToDbService>();
services.AddScoped<IEmailService, EmailService>();
services.AddScoped<IResetPasswordService, ResetPasswordService>();
services.AddScoped<IValidateTokenService, ValidateTokenService>();



return services;
}
}
2 changes: 2 additions & 0 deletions AnalysisData/AnalysisData/Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
public DbSet<FileEntity> FileUploadedDb { get; set; }
public DbSet<UserFile> UserFiles { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<PasswordResetToken> Tokens { get; set; }


protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace AnalysisData.Exception.TokenException;

public class TokenExpiredException : ServiceException
{
public TokenExpiredException() : base(Resources.TokenExpiredException, StatusCodes.Status400BadRequest)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace AnalysisData.Exception.TokenException;

public class TokenIsInvalidException : ServiceException
{
public TokenIsInvalidException() : base(Resources.TokenIsInvalidException, StatusCodes.Status400BadRequest)
{
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace AnalysisData.Migrations
{
/// <inheritdoc />
public partial class initial : Migration
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
Expand Down Expand Up @@ -120,6 +120,27 @@ protected override void Up(MigrationBuilder migrationBuilder)
onDelete: ReferentialAction.Cascade);
});

migrationBuilder.CreateTable(
name: "Tokens",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Token = table.Column<string>(type: "text", nullable: false),
Expiration = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tokens", x => x.Id);
table.ForeignKey(
name: "FK_Tokens_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});

migrationBuilder.CreateTable(
name: "EntityNodes",
columns: table => new
Expand Down Expand Up @@ -258,7 +279,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
migrationBuilder.InsertData(
table: "Users",
columns: new[] { "Id", "Email", "FirstName", "ImageURL", "LastName", "Password", "PhoneNumber", "RoleId", "Username" },
values: new object[] { new Guid("31a2df40-d66d-4a7e-967c-6c3b7561da0f"), "[email protected]", "admin", null, "admin", "jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=", "09131111111", 1, "admin" });
values: new object[] { new Guid("12cb995a-4885-4ec3-9a3b-126b0ff89602"), "[email protected]", "admin", null, "admin", "jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=", "09131111111", 1, "admin" });

migrationBuilder.CreateIndex(
name: "IX_EntityEdges_EntityIDSource",
Expand All @@ -285,6 +306,11 @@ protected override void Up(MigrationBuilder migrationBuilder)
table: "FileUploadedDb",
column: "UploaderId");

migrationBuilder.CreateIndex(
name: "IX_Tokens_UserId",
table: "Tokens",
column: "UserId");

migrationBuilder.CreateIndex(
name: "IX_UserFiles_FileId",
table: "UserFiles",
Expand Down Expand Up @@ -324,6 +350,9 @@ protected override void Up(MigrationBuilder migrationBuilder)
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Tokens");

migrationBuilder.DropTable(
name: "UserFiles");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,31 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("ValueNodes");
});

modelBuilder.Entity("AnalysisData.User.Model.PasswordResetToken", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");

NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));

b.Property<DateTime>("Expiration")
.HasColumnType("timestamp with time zone");

b.Property<string>("Token")
.IsRequired()
.HasColumnType("text");

b.Property<Guid>("UserId")
.HasColumnType("uuid");

b.HasKey("Id");

b.HasIndex("UserId");

b.ToTable("Tokens");
});

modelBuilder.Entity("AnalysisData.User.Model.Role", b =>
{
b.Property<int>("Id")
Expand Down Expand Up @@ -310,7 +335,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.HasData(
new
{
Id = new Guid("31a2df40-d66d-4a7e-967c-6c3b7561da0f"),
Id = new Guid("12cb995a-4885-4ec3-9a3b-126b0ff89602"),
Email = "[email protected]",
FirstName = "admin",
LastName = "admin",
Expand Down Expand Up @@ -427,6 +452,17 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Navigation("Entity");
});

modelBuilder.Entity("AnalysisData.User.Model.PasswordResetToken", b =>
{
b.HasOne("AnalysisData.User.Model.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();

b.Navigation("User");
});

modelBuilder.Entity("AnalysisData.User.Model.User", b =>
{
b.HasOne("AnalysisData.User.Model.Role", "Role")
Expand Down
9 changes: 9 additions & 0 deletions AnalysisData/AnalysisData/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fa7198e

Please sign in to comment.