Compare commits

..

17 Commits

Author SHA1 Message Date
fda184726f Merge pull request 'Merge pull request 'develop' (#14) from develop into main' (#15) from main into develop
Reviewed-on: #15
2026-03-16 16:47:16 +00:00
d26b230f91 Merge pull request 'develop' (#14) from develop into main
Reviewed-on: #14
2026-03-16 16:46:18 +00:00
710735f56d Merge pull request 'add guards admin-dashboard and user-dashboard components' (#13) from feature/guards into develop
Reviewed-on: #13
2026-03-16 16:44:14 +00:00
9452732730 add guards admin-dashboard and user-dashboard components 2026-03-16 17:43:26 +01:00
53190c2db0 Merge pull request 'fix dropdown' (#12) from feature/haeder into develop
Reviewed-on: #12
2026-03-15 19:02:16 +00:00
a9f29fff6e fix dropdown 2026-03-15 20:01:51 +01:00
ee46cf09f4 Merge pull request 'update Angular core to new version' (#11) from feature/angular into develop
Reviewed-on: #11
2026-03-15 18:11:18 +00:00
d853ac7486 update Angular core to new version 2026-03-15 19:10:57 +01:00
06675219e0 Merge pull request 'update angular cli to new Version' (#10) from feature/nuget into develop
Reviewed-on: #10
2026-03-15 18:07:15 +00:00
b75c4152fb Merge branch 'develop' into feature/nuget 2026-03-15 18:06:58 +00:00
3407f9ec51 update angular cli to new Version 2026-03-15 19:06:27 +01:00
f544bc0b2c Merge pull request 'update NuGet Package to new Version' (#9) from feature/nuget into develop
Reviewed-on: #9
2026-03-15 18:04:11 +00:00
74bae6d90c update NuGet Package to new Version 2026-03-15 19:03:25 +01:00
9d6ba08be2 Merge pull request 'fix angular login and register' (#8) from feature/angular into develop
Reviewed-on: #8
2026-03-11 17:02:20 +00:00
2598adb286 fix angular login and register 2026-03-11 18:00:48 +01:00
b10b6cca60 Merge pull request 'Bearer-Authentifcation' (#7) from feature/bearer into develop
Reviewed-on: #7
2026-03-09 11:35:44 +00:00
bbb4fec581 Bearer-Authentifcation 2026-03-09 12:35:11 +01:00
61 changed files with 2426 additions and 1000 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
<changelist name="Uncommitted_changes_before_Checkout_at_11_03_26,_18_04_[Changes]" date="1773248701579" recycled="true" deleted="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/shelf/Uncommitted_changes_before_Checkout_at_11_03_26,_18_04_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before Checkout at 11.03.26, 18:04 [Changes]" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
<changelist name="Uncommitted_changes_before_Update_at_09_03_26,_12_36_[Changes]" date="1773056200358" recycled="false" toDelete="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/shelf/Uncommitted_changes_before_Update_at_09_03_26,_12_36_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before Update at 09.03.26, 12:36 [Changes]" />
</changelist>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
<changelist name="Uncommitted_changes_before_Update_at_11_03_26,_18_06_[Changes]" date="1773248835929" recycled="true" deleted="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/shelf/Uncommitted_changes_before_Update_at_11_03_26,_18_06_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before Update at 11.03.26, 18:06 [Changes]" />
</changelist>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectTasksOptions"> <component name="ProjectTasksOptions">
<TaskOptions isEnabled="true"> <TaskOptions isEnabled="false">
<option name="arguments" value="$FileName$:$FileNameWithoutExtension$.css" /> <option name="arguments" value="$FileName$:$FileNameWithoutExtension$.css" />
<option name="checkSyntaxErrors" value="true" /> <option name="checkSyntaxErrors" value="true" />
<option name="description" /> <option name="description" />

View File

@@ -13,68 +13,41 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="1ac72a4a-52ad-4e70-9b15-c330b1ed3e7a" name="Changes" comment=""> <list default="true" id="1ac72a4a-52ad-4e70-9b15-c330b1ed3e7a" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/src/API/Controllers/AuthController.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/admin-dashboard/admin-dashboard.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/API/Controllers/UserController.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/admin-dashboard/admin-dashboard.component.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/API/Extension/ResultExtension.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/admin-dashboard/admin-dashboard.component.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Common/Results/Error.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/admin-dashboard/admin-dashboard.component.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Common/Results/ErrorTypeConstant.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/unauthorized/unauthorized.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Common/Results/Result.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/unauthorized/unauthorized.component.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Common/Results/TResult.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/unauthorized/unauthorized.component.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/DTOs/PagedResult.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/unauthorized/unauthorized.component.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/DTOs/ResetPasswordDto.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-dashboard/user-dashboard.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/DTOs/UserDto.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-dashboard/user-dashboard.component.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Errors/AuthError.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-dashboard/user-dashboard.component.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Errors/UserError.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-dashboard/user-dashboard.component.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Extensions/ServiceCollectionExtensions.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-table/user-table.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Interfaces/IAuthenticationService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-table/user-table.component.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Interfaces/IEmailService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-table/user-table.component.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Interfaces/IJwtService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/user-table/user-table.component.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Interfaces/IUserService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/admin.guard.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/AssingRoleRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/admin.guard.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/EmailRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/authentication.guard.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/LoginRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/authentication.guard.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/RefreshTokenRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/guest.guard.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/RegisterRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/guards/guest.guard.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/TokenResponse.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/interceptors/token.interceptor.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Models/UserUpdateRequest.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/interceptors/token.interceptor.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Services/AuthenticationService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/shared/popup-modal/popup-modal.component.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Services/EmailService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/shared/popup-modal/popup-modal.component.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Services/JwtService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/shared/popup-modal/popup-modal.component.spec.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Services/UserService.cs" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/shared/popup-modal/popup-modal.component.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Validators/LoginRequestValidator.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Validators/RegisterRequestValidator.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Application/Validators/UserUpdateRequestValidator.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/ClientApp/package-lock.json" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Entities/Role.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Entities/User.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Entities/UserRole.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Interface/IGenericRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Interface/IUnitOfWork.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Interface/IUserRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Domain/Interface/IUserRoleRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Configuration/RoleConfiguration.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Configuration/UserConfiguration.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Configuration/UserRoleConfiguration.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Context/ApplicationDbContext.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Context/ApplicationDbContextFactory.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Extensions/ServiceCollectionExtensions.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Migrations/20260206104345_InitialCreate.Designer.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Migrations/20260206104345_InitialCreate.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Migrations/ApplicationDbContextModelSnapshot.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Repositories/GenericRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Repositories/UnitOfWork.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Repositories/UserRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Repositories/UserRoleRepository.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Utilities/EmailBody.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Utilities/GenerateRefreshTokenHelper.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/Infrastructure/Utilities/PostgreSqlSettings.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.DotNetAngular/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/API/API.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/src/API/API.csproj" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/app.config.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/app.config.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/API/Extension/ServiceCollectionExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/API/Extension/ServiceCollectionExtensions.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/app.routes.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/app.routes.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/API/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/API/Program.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/domain/entities/user.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/domain/entities/user.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/API/appsettings.json" beforeDir="false" afterPath="$PROJECT_DIR$/src/API/appsettings.json" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/authentication/login/login.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/authentication/login/login.component.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/Application/Application.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/src/Application/Application.csproj" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/header/header.component.html" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/header/header.component.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/Infrastructure/Infrastructure.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/src/Infrastructure/Infrastructure.csproj" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/header/header.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/ClientApp/src/app/presentation/components/header/header.component.ts" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -97,6 +70,7 @@
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="HighlightingSettingsPerFile"> <component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/dotnet-tools.json" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/ClientApp/package-lock.json" root0="SKIP_HIGHLIGHTING" /> <setting file="file://$PROJECT_DIR$/src/ClientApp/package-lock.json" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/ClientApp/package.json" root0="FORCE_HIGHLIGHTING" /> <setting file="file://$PROJECT_DIR$/src/ClientApp/package.json" root0="FORCE_HIGHLIGHTING" />
</component> </component>
@@ -105,6 +79,9 @@
<urls /> <urls />
</component> </component>
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" /> <component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="ProblemsViewState">
<option name="selectedTabId" value="Toolset" />
</component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 5 &quot;associatedIndex&quot;: 5
}</component> }</component>
@@ -122,14 +99,14 @@
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;, &quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;, &quot;RunOnceActivity.typescript.service.memoryLimit.init&quot;: &quot;true&quot;,
&quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;, &quot;com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;feature/dotnet&quot;, &quot;git-widget-placeholder&quot;: &quot;feature/guards&quot;,
&quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;, &quot;junie.onboarding.icon.badge.shown&quot;: &quot;true&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;vcs.Git&quot;, &quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;to.speed.mode.migration.done&quot;: &quot;true&quot;, &quot;to.speed.mode.migration.done&quot;: &quot;true&quot;,
&quot;ts.external.directory.path&quot;: &quot;/home/natlinux/RiderProjects/DotNetAngular/src/ClientApp/node_modules/typescript/lib&quot;, &quot;ts.external.directory.path&quot;: &quot;/home/natlinux/RiderProjects/DotNetAngular/src/ClientApp/node_modules/typescript/lib&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot; &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
@@ -270,6 +247,13 @@
<workItem from="1771239672703" duration="359000" /> <workItem from="1771239672703" duration="359000" />
<workItem from="1771331713319" duration="2451000" /> <workItem from="1771331713319" duration="2451000" />
<workItem from="1771503996420" duration="1283000" /> <workItem from="1771503996420" duration="1283000" />
<workItem from="1772664092787" duration="54000" />
<workItem from="1772664174287" duration="646000" />
<workItem from="1773053172796" duration="1432000" />
<workItem from="1773597121547" duration="689000" />
<workItem from="1773599776473" duration="3799000" />
<workItem from="1773605341198" duration="3147000" />
<workItem from="1773678089390" duration="1025000" />
</task> </task>
<task id="LOCAL-00001" summary="updating template"> <task id="LOCAL-00001" summary="updating template">
<option name="closed" value="true" /> <option name="closed" value="true" />
@@ -303,7 +287,39 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1770318472632</updated> <updated>1770318472632</updated>
</task> </task>
<option name="localTasksCounter" value="5" /> <task id="LOCAL-00005" summary="update nuget packages to new versions">
<option name="closed" value="true" />
<created>1771506336945</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1771506336945</updated>
</task>
<task id="LOCAL-00006" summary="update NuGet Package to new Version">
<option name="closed" value="true" />
<created>1773597809588</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1773597809588</updated>
</task>
<task id="LOCAL-00007" summary="update Angular core to new version">
<option name="closed" value="true" />
<created>1773598259701</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1773598259701</updated>
</task>
<task id="LOCAL-00008" summary="fix dropdown">
<option name="closed" value="true" />
<created>1773601314558</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1773601314558</updated>
</task>
<option name="localTasksCounter" value="9" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -343,7 +359,11 @@
<MESSAGE value="update to angular 20" /> <MESSAGE value="update to angular 20" />
<MESSAGE value="login.component, register.component" /> <MESSAGE value="login.component, register.component" />
<MESSAGE value="update to dotnet 10" /> <MESSAGE value="update to dotnet 10" />
<option name="LAST_COMMIT_MESSAGE" value="update to dotnet 10" /> <MESSAGE value="update nuget packages to new versions" />
<MESSAGE value="update NuGet Package to new Version" />
<MESSAGE value="update Angular core to new version" />
<MESSAGE value="fix dropdown" />
<option name="LAST_COMMIT_MESSAGE" value="fix dropdown" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>

13
dotnet-tools.json Normal file
View File

@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "10.0.4",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}

View File

@@ -11,10 +11,11 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="10.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="10.1.4" /> <PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="10.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="10.1.4" /> <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="10.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.4" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="10.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,3 +1,6 @@
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi; using Microsoft.OpenApi;
namespace API.Extension; namespace API.Extension;
@@ -5,7 +8,7 @@ namespace API.Extension;
public static class ServiceCollectionExtensions public static class ServiceCollectionExtensions
{ {
public static IServiceCollection AddWebServices(this IServiceCollection services, public static IServiceCollection AddWebServices(this IServiceCollection services,
ConfigurationManager builderConfiguration) IConfiguration configuration)
{ {
services.AddSwaggerGen(options => services.AddSwaggerGen(options =>
{ {
@@ -13,7 +16,43 @@ public static class ServiceCollectionExtensions
options.SwaggerDoc("v1", new OpenApiInfo { Title = "DotNetAngular API", Version = "v1" }); options.SwaggerDoc("v1", new OpenApiInfo { Title = "DotNetAngular API", Version = "v1" });
// update names of the api // update names of the api
options.SwaggerGeneratorOptions.DocumentFilters.Add(new LowerCaseDocumentFilter()); options.SwaggerGeneratorOptions.DocumentFilters.Add(new LowerCaseDocumentFilter());
// configure JWT authentication
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description =
"JWT Authorization header using the Bearer scheme. Enter your token in the text input below."
});
options.AddSecurityRequirement(doc =>
{
var schemeRef = new OpenApiSecuritySchemeReference("Bearer", doc);
return new OpenApiSecurityRequirement
{
{ schemeRef, new List<string>() }
};
});
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["Jwt:Issuer"],
ValidAudience = configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(configuration["Jwt:Key"] ??
throw new InvalidOperationException("Jwt:Key is not configured"))),
ClockSkew = TimeSpan.Zero // remove delay of token expiration time
};
}); });
return services; return services;
} }

View File

@@ -13,12 +13,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" /> <PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.1.1" />
<PackageReference Include="MailKit" Version="4.15.0" /> <PackageReference Include="MailKit" Version="4.15.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.3.9" /> <PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.3.9" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.3.9" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.3.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.3" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
<PackageReference Include="MimeKit" Version="4.15.0" /> <PackageReference Include="MimeKit" Version="4.15.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.16.0" />
</ItemGroup> </ItemGroup>

View File

@@ -64,8 +64,8 @@
"sourceMap": true, "sourceMap": true,
"fileReplacements": [ "fileReplacements": [
{ {
"replace": "src/environments/environment.development.ts", "replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts" "with": "src/environments/environment.development.ts"
} }
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@@ -12,14 +12,14 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^21.1.2", "@angular/animations": "^21.2.4",
"@angular/common": "^21.1.2", "@angular/common": "^21.2.4",
"@angular/compiler": "^21.1.2", "@angular/compiler": "^21.2.4",
"@angular/core": "^21.1.2", "@angular/core": "^21.2.4",
"@angular/forms": "^21.1.2", "@angular/forms": "^21.2.4",
"@angular/platform-browser": "^21.1.2", "@angular/platform-browser": "^21.2.4",
"@angular/platform-browser-dynamic": "^21.1.2", "@angular/platform-browser-dynamic": "^21.2.4",
"@angular/router": "^21.1.2", "@angular/router": "^21.2.4",
"@auth0/angular-jwt": "^5.2.0", "@auth0/angular-jwt": "^5.2.0",
"@ng-bootstrap/ng-bootstrap": "^20.0.0", "@ng-bootstrap/ng-bootstrap": "^20.0.0",
"bootstrap": "^5.3.8", "bootstrap": "^5.3.8",
@@ -29,9 +29,9 @@
"zone.js": "~0.15.0" "zone.js": "~0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@angular/build": "^21.1.2", "@angular/build": "^21.2.2",
"@angular/cli": "^21.1.2", "@angular/cli": "^21.2.2",
"@angular/compiler-cli": "^21.1.2", "@angular/compiler-cli": "^21.2.4",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"jasmine-core": "~5.2.0", "jasmine-core": "~5.2.0",
"karma": "~6.4.0", "karma": "~6.4.0",

View File

@@ -2,7 +2,12 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { routes } from './app.routes'; import { routes } from './app.routes';
import {provideHttpClient, withFetch, withInterceptors} from "@angular/common/http";
import {tokenInterceptor} from "./presentation/interceptors/token.interceptor";
import {provideClientHydration, withEventReplay} from "@angular/platform-browser";
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes),
provideHttpClient(withFetch(), withInterceptors([tokenInterceptor
])), provideClientHydration(withEventReplay())]
}; };

View File

@@ -1,9 +1,22 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import {RegisterComponent} from "./presentation/authentication/register/register.component"; import {RegisterComponent} from "./presentation/authentication/register/register.component";
import {LoginComponent} from "./presentation/authentication/login/login.component"; import {LoginComponent} from "./presentation/authentication/login/login.component";
import {StartpageComponent} from "./presentation/components/startpage/startpage.component";
import {AdminDashboardComponent} from "./presentation/components/admin-dashboard/admin-dashboard.component";
import {UserDashboardComponent} from "./presentation/components/user-dashboard/user-dashboard.component";
import {UnauthorizedComponent} from "./presentation/components/unauthorized/unauthorized.component";
import {guestGuard} from "./presentation/guards/guest.guard";
import {AuthenticationGuard} from "./presentation/guards/authentication.guard";
import {adminGuard} from "./presentation/guards/admin.guard";
import {UserTableComponent} from "./presentation/components/user-table/user-table.component";
export const routes: Routes = [ export const routes: Routes = [
{path: '', redirectTo: 'login', pathMatch: 'full'}, {path: '', redirectTo: 'startpage', pathMatch: 'full'},
{path: 'register', component: RegisterComponent}, {path: 'register', component: RegisterComponent, canActivate: [guestGuard]},
{path: 'login', component: LoginComponent} {path: 'login', component: LoginComponent, canActivate: [guestGuard]},
{path: 'startpage', component: StartpageComponent, canActivate: [guestGuard]},
{path: 'user-table', component: UserTableComponent, canActivate: [adminGuard]},
{path: 'admin-dashboard', component: AdminDashboardComponent, canActivate: [adminGuard]},
{path: 'user-dashboard', component: UserDashboardComponent, canActivate: [AuthenticationGuard]},
{path: 'unauthorized', component: UnauthorizedComponent, canActivate: [AuthenticationGuard]}
]; ];

View File

@@ -1,4 +1,3 @@
import {RssFeed} from "./rss-feed";
import {UserRole} from "./user-role"; import {UserRole} from "./user-role";
export interface User { export interface User {
@@ -8,9 +7,5 @@ export interface User {
password: string; password: string;
lastLogin: Date; lastLogin: Date;
rssFeedId: number;
rssFeed: RssFeed;
UserRoles: UserRole[]; UserRoles: UserRole[];
rssFeeds: RssFeed [];
} }

View File

@@ -36,7 +36,7 @@ export class AuthService implements IAuthService {
} }
signOut() { signOut() {
if (!this.isBrowser) { if (this.isBrowser) {
localStorage.clear(); localStorage.clear();
this.router.navigate(['/login']).catch(error => { this.router.navigate(['/login']).catch(error => {
console.error('Navigation error:', error); console.error('Navigation error:', error);

View File

@@ -66,7 +66,8 @@ export class LoginComponent {
this.userStore.setEmailForStore(tokenPayload.email); this.userStore.setEmailForStore(tokenPayload.email);
this.userStore.setRoleForStore(tokenPayload.role); this.userStore.setRoleForStore(tokenPayload.role);
this.loadingService.hide() this.loadingService.hide()
this.router.navigate(['rss-feed-overview']).then(success => { // TODO redirect to...
this.router.navigate(['user-dashboard']).then(success => {
if (success) { if (success) {
this.loginForm.reset(); this.loginForm.reset();
} }

View File

@@ -0,0 +1,10 @@
<div class="container-fluid d-flex justify-content-center">
<div class="card mt-2 col-2 me-2" [routerLink]="['/user-table']" style="cursor: pointer;">
<div class="card-body text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150" fill="blue" class="bi bi-people-fill " viewBox="0 0 16 16">
<path d="M7 14s-1 0-1-1 1-4 5-4 5 3 5 4-1 1-1 1zm4-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6m-5.784 6A2.24 2.24 0 0 1 5 13c0-1.355.68-2.75 1.936-3.72A6.3 6.3 0 0 0 5 9c-4 0-5 3-5 4s1 1 1 1zM4.5 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5"/>
</svg>
<h4 class="my-3">Users</h4>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AdminDashboardComponent } from './admin-dashboard.component';
describe('AdminDashboardComponent', () => {
let component: AdminDashboardComponent;
let fixture: ComponentFixture<AdminDashboardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AdminDashboardComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AdminDashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import {RouterLink} from "@angular/router";
@Component({
selector: 'app-admin-dashboard',
imports: [
RouterLink
],
templateUrl: './admin-dashboard.component.html',
styleUrl: './admin-dashboard.component.scss',
standalone: true
})
export class AdminDashboardComponent {
}

View File

@@ -1,27 +1,10 @@
<nav class="navbar navbar-expand-lg border-bottom position-relative bg-body-tertiary"> <nav class="navbar navbar-expand-lg border-bottom position-relative bg-body-tertiary">
<div class="container-fluid"> <div class="container-fluid">
@if (showOverviewTools){
<div class="sidebar-toggle p-2 me-1 text-secondary" data-bs-target="#offcanvasExample" data-bs-toggle="offcanvas"
type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-list"
viewBox="0 0 16 16">
<path fill-rule="evenodd"
d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5"/>
</svg>
</div>
}
<a class="navbar-brand" [routerLink]="['/#']" title="Refresh" data-bs-target="#offcanvasExample" data-bs-dismiss="offcanvas"> <a class="navbar-brand" [routerLink]="['/#']" title="Refresh" data-bs-target="#offcanvasExample" data-bs-dismiss="offcanvas">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-app" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-app" viewBox="0 0 16 16">
<path d="M11 2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zM5 1a4 4 0 0 0-4 4v6a4 4 0 0 0 4 4h6a4 4 0 0 0 4-4V5a4 4 0 0 0-4-4z"/> <path d="M11 2a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H5a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3zM5 1a4 4 0 0 0-4 4v6a4 4 0 0 0 4 4h6a4 4 0 0 0 4-4V5a4 4 0 0 0-4-4z"/>
</svg> </svg>
</a> </a>
<button aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"
class="navbar-toggler"
data-bs-target="#navbarSupportedContent" data-bs-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
</div> </div>
<!-- Dropdown --> <!-- Dropdown -->
@if (!showDropdown){ @if (!showDropdown){

View File

@@ -1,7 +1,6 @@
import {Component, inject, OnInit, viewChild} from '@angular/core'; import {Component, inject, OnInit} from '@angular/core';
import {DarkModeService} from '../../../infrastructure/services/dark-mode.service'; import {DarkModeService} from '../../../infrastructure/services/dark-mode.service';
import {FormsModule, NgForm} from "@angular/forms"; import {FormsModule} from "@angular/forms";
import {ToastService} from "../../../infrastructure/services/toast.service";
import {ActivatedRoute, NavigationEnd, Router, RouterLink} from "@angular/router"; import {ActivatedRoute, NavigationEnd, Router, RouterLink} from "@angular/router";
import {AuthService} from "../../../infrastructure/services/auth-service"; import {AuthService} from "../../../infrastructure/services/auth-service";
import {UserStoreService} from "../../../infrastructure/services/user-store.service"; import {UserStoreService} from "../../../infrastructure/services/user-store.service";
@@ -19,7 +18,6 @@ import {filter} from "rxjs/operators";
}) })
export class HeaderComponent implements OnInit { export class HeaderComponent implements OnInit {
toastService = inject(ToastService);
darkModeService = inject(DarkModeService); darkModeService = inject(DarkModeService);
userStore = inject(UserStoreService); userStore = inject(UserStoreService);
@@ -50,9 +48,9 @@ export class HeaderComponent implements OnInit {
while (route.firstChild) route = route.firstChild; while (route.firstChild) route = route.firstChild;
// Header-Logic // Header-Logic
const headerRoutes = ['/login', '/register', '/legal' , '/start']; // TODO hide dropdown for login register and legal
this.showDropdown = headerRoutes.some(route => event.urlAfterRedirects.startsWith(route)); const headerRoutes = ['/login', '/register', '/legal', '/startpage'];
this.showOverviewTools = event.urlAfterRedirects.startsWith('/rss-feed-overview'); this.showDropdown = headerRoutes.some(route => event.urlAfterRedirects.startsWith(route))
}); });
} }

View File

@@ -0,0 +1 @@
<p>startpage works!</p>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StartpageComponent } from './startpage.component';
describe('StartpageComponent', () => {
let component: StartpageComponent;
let fixture: ComponentFixture<StartpageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [StartpageComponent]
})
.compileComponents();
fixture = TestBed.createComponent(StartpageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-startpage',
imports: [],
templateUrl: './startpage.component.html',
styleUrl: './startpage.component.scss',
})
export class StartpageComponent {
}

View File

@@ -0,0 +1 @@
<p>unauthorized works!</p>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UnauthorizedComponent } from './unauthorized.component';
describe('UnauthorizedComponent', () => {
let component: UnauthorizedComponent;
let fixture: ComponentFixture<UnauthorizedComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UnauthorizedComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UnauthorizedComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-unauthorized',
imports: [],
templateUrl: './unauthorized.component.html',
styleUrl: './unauthorized.component.scss',
})
export class UnauthorizedComponent {
}

View File

@@ -0,0 +1,73 @@
<div class="container-fluid">
<div class="align-items-center justify-content-center mt-3 d-flex">
<div class="container">
<div class="row justify-content-center ">
<div class="col-lg-3">
<div class="card mb-3">
<div class="card-body text-center">
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="150" height="150" class="bi bi-person-fill bg-primary rounded-circle" viewBox="0 0 16 16">
<path d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6"/>
</svg>
<h4 class="my-3">{{username}}</h4>
<!-- <button class="btn btn-primary">Update Picture</button>-->
</div>
</div>
</div>
<div class="col-lg-8">
<div class="row mb-2">
<div class="col-md-6">
<div class="card mb-3">
<div class="card-header text-center">
<h2 class="mb-4">Personal Data</h2>
</div>
<div class="card-body">
<p class="mb-1"><strong>Username:</strong> <br> {{username}}</p> <br>
<p class="mb-1"><strong>E-Mail:</strong> <br>{{email}}</p>
</div>
</div>
</div>
<!-- <div class="col-md-6">-->
<!-- <div class="card mb-3" style="height: 92%">-->
<!-- <div class="card-header text-center">-->
<!-- <h2 class="mb-4">Payment Method</h2>-->
<!-- </div>-->
<!-- <div class="card-body">-->
<!-- <p class="mb-1"></p>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
<a class="text-decoration-none">
<div class="row">
<div class="col-md-6">
<!-- <div class="card mb-3">-->
<!-- <div class="card-header text-center">-->
<!-- <h4 class="my-3">Change password</h4>-->
<!-- </div>-->
<!-- <div class="card-body d-flex flex-wrap">-->
<!-- <input type="password" class="form-control mt-2" placeholder="Enter new password">-->
<!-- <input type="password" class="form-control mt-2" placeholder="Repeat new password">-->
<!-- <button class="btn btn-primary mt-4">Change password</button>-->
<!-- </div>-->
<!-- </div>-->
</div>
<div class="col-md-6">
<!-- <div class="card mb-3">-->
<!-- <div class="card-header text-center">-->
<!-- <h4 class="my-3">Change E-Mail</h4>-->
<!-- </div>-->
<!-- <div class="card-body d-flex flex-wrap">-->
<!-- <input type="password" class="form-control mt-2" placeholder="Enter new E-Mail">-->
<!-- <input type="password" class="form-control mt-2" placeholder="Repeat new E-Mail">-->
<!-- <button class="btn btn-primary mt-4">Change E-Mail</button>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserDashboardComponent } from './user-dashboard.component';
describe('UserDashboardComponent', () => {
let component: UserDashboardComponent;
let fixture: ComponentFixture<UserDashboardComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserDashboardComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UserDashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,38 @@
import {Component, inject} from '@angular/core';
import {Title} from "@angular/platform-browser";
import {UserStoreService} from "../../../infrastructure/services/user-store.service";
import {AuthService} from "../../../infrastructure/services/auth-service";
@Component({
selector: 'app-user-dashboard',
imports: [],
templateUrl: './user-dashboard.component.html',
styleUrl: './user-dashboard.component.scss',
})
export class UserDashboardComponent {
public username!: string;
public email!: string;
public userId!: number;
userStore = inject(UserStoreService);
private authenticateService = inject(AuthService);
title = inject(Title)
constructor() {
//TODO App Name
this.title.setTitle('User Dashboard | App Name');
}
ngOnInit(): void {
this.userStore.getUsernameFromStore()
.subscribe(val => {
const usernameFromToken = this.authenticateService.getUsernameFromToken();
this.username = val || usernameFromToken
});
this.userStore.getEmailFromStore()
.subscribe(val => {
const emailFromToken = this.authenticateService.getEmailFromToken();
this.email = val || emailFromToken
});
}
}

View File

@@ -0,0 +1,98 @@
<div class="container-fluid p-4">
<div class="card">
<div class="card-header bg-primary text-center text-dark"><h4>User-List</h4></div>
<div class="card-body p-0">
<table class="table table-striped table-hover table-bordered table-sm mb-0">
<thead>
<tr class="text-center">
<th>#</th>
<th (click)="sort('username')" class="sortable">
Username
<i class="bi"
[ngClass]="{
'bi bi-arrow-up': sortColumn === 'username' && sortDirection === 'asc',
'bi bi-arrow-down': sortColumn === 'username' && sortDirection === 'desc',
'bi bi-arrow-down-up': sortColumn !== 'username'
}"></i>
</th>
<th (click)="sort('email')" class="sortable">
E-Mail
<i class="bi"
[ngClass]="{
'bi bi-arrow-up': sortColumn === 'email' && sortDirection === 'asc',
'bi bi-arrow-down': sortColumn === 'email' && sortDirection === 'desc',
'bi bi-arrow-down-up': sortColumn !== 'email'
}"></i>
</th>
<th (click)="sort('lastLogin')" class="sortable">
Last Login
<i class="bi"
[ngClass]="{
'bi bi-arrow-up': sortColumn === 'lastLogin' && sortDirection === 'asc',
'bi bi-arrow-down': sortColumn === 'lastLogin' && sortDirection === 'desc',
'bi bi-arrow-down-up': sortColumn !== 'lastLogin'
}"></i>
</th>
<th>Action</th>
</tr>
</thead>
<tbody class="table-group-divider">
@for (user of users; track user.id; let i = $index;) {
<tr>
<td class="text-center">{{ i + 1 }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td class="text-center">{{ user.lastLogin | date:'dd.MM.yyyy HH:mm:ss':'Europe/Berlin' }}</td>
<td class="d-flex justify-content-center">
<button (click)="selectUser(user)" class="btn btn-sm btn-danger"
data-bs-target="#warningModal"
data-bs-toggle="modal"
><i class="bi bi-trash3-fill"></i></button>
</td>
</tr>
}
</tbody>
</table>
</div>
<!-- Pagination Buttons Bootstrap -->
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mt-3">
<!-- Previous Button -->
<li class="page-item me-1" [class.disabled]="pageNumber === 1">
<a class="btn btn-primary" (click)="previousPage()" href="javascript:void(0)" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
<!-- Dynamic Page Buttons -->
@for (Page of [].constructor(totalPages); track Page ;let i = $index;) {
<li class="page-item me-1">
<a class="btn btn-outline-primary" href="javascript:void(0)" (click)="goToPage(i + 1)">
{{ i + 1 }}
</a>
</li>
}
<!-- Next Button -->
<li class="page-item me-1" [class.disabled]="pageNumber === totalPages">
<a class="btn btn-primary" (click)="nextPage()" href="javascript:void(0)" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</ul>
</nav>
<div class="d-flex justify-content-center align-items-center mb-3">
<span>Page {{ pageNumber }} of {{ totalPages }}</span>
</div>
</div>
</div>
<app-popup-modal
[title]="'Warning'"
[headerClass]="'bg-warning text-dark'"
(confirm)="handleConfirm()">
<p>
Do you really want to delete
<strong class="text-danger">{{ selectedUser?.username }}</strong> ?
</p></app-popup-modal>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserTableComponent } from './user-table.component';
describe('UserTableComponent', () => {
let component: UserTableComponent;
let fixture: ComponentFixture<UserTableComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserTableComponent]
})
.compileComponents();
fixture = TestBed.createComponent(UserTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,120 @@
import {Component, inject} from '@angular/core';
import {User} from "../../../domain/entities/user";
import {UserService} from "../../../infrastructure/services/user.service";
import {ToastService} from "../../../infrastructure/services/toast.service";
import {Title} from "@angular/platform-browser";
import {PopupModalComponent} from "../../shared/popup-modal/popup-modal.component";
import {DatePipe, NgClass} from "@angular/common";
@Component({
selector: 'app-user-table',
imports: [
PopupModalComponent,
DatePipe,
NgClass
],
templateUrl: './user-table.component.html',
styleUrl: './user-table.component.scss',
standalone: true
})
export class UserTableComponent {
public users: User[] = [];
selectedUser: User | null = null;
pageNumber: number = 1;
pageSize: number = 10;
totalPages: number = 0;
sortColumn: string = '';
sortDirection: 'asc' | 'desc' = 'asc';
private apiService = inject(UserService)
toastService = inject(ToastService);
title = inject(Title)
constructor() {
this.title.setTitle('User Table | RSS Feed Reader');
}
ngOnInit(): void {
this.getAllUsers()
}
getAllUsers(): void {
this.apiService.getAllUsers(this.pageNumber, this.pageSize).subscribe(result => {
this.users = result.value.items;
this.totalPages = result.value.totalPages;
this.sort(this.sortColumn);
});
}
nextPage(): void {
if (this.pageNumber < this.totalPages) {
this.pageNumber++;
this.getAllUsers();
}
}
previousPage(): void {
if (this.pageNumber > 1) {
this.pageNumber--;
this.getAllUsers();
}
}
goToPage(page: number): void {
if (page >= 1 && page <= this.totalPages) {
this.pageNumber = page;
this.getAllUsers();
}
}
// Sortiermethode
sort(column: string): void {
if (this.sortColumn === column) {
// Wenn die Spalte bereits sortiert ist, wechsle die Richtung
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
// Andernfalls aufsteigend sortieren
this.sortDirection = 'asc';
this.sortColumn = column;
}
// Sortiere die Tabelle basierend auf Spalte und Richtung
this.users.sort((a: any, b: any) => {
const valueA = a[column];
const valueB = b[column];
if (valueA < valueB) {
return this.sortDirection === 'asc' ? -1 : 1;
}
if (valueA > valueB) {
return this.sortDirection === 'asc' ? 1 : -1;
}
return 0;
});
}
deleteUser(id: number): void {
this.apiService.deleteUser(id).subscribe({
next: (result) => {
console.log('delete',result);
this.toastService.show(result.value, {
classname: 'bg-success text-light',
delay: 3000
})
this.users = this.users.filter(user => user.id !== id);
},
error: (err) => {
console.error(err.error.error.message);
this.toastService.show(err.error.error.message, {
classname: 'bg-danger text-light',
delay: 3000
});
}
});
}
selectUser(user: User): void {
this.selectedUser = user;
console.log('selectedUser', user);
}
handleConfirm() {
this.deleteUser(this.selectedUser!.id);
}
}

View File

@@ -0,0 +1,17 @@
import {TestBed} from '@angular/core/testing';
import {CanActivateFn} from '@angular/router';
import {adminGuard} from './admin.guard';
describe('adminGuard', () => {
const executeGuard: CanActivateFn = (...guardParameters) =>
TestBed.runInInjectionContext(() => adminGuard(...guardParameters));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(executeGuard).toBeTruthy();
});
});

View File

@@ -0,0 +1,43 @@
import {CanActivateFn, Router} from '@angular/router';
import {inject} from "@angular/core";
import {AuthService} from "../../infrastructure/services/auth-service";
import {ToastService} from "../../infrastructure/services/toast.service";
import {UserStoreService} from "../../infrastructure/services/user-store.service";
import {catchError, map} from 'rxjs/operators';
import {of} from 'rxjs';
export const adminGuard: CanActivateFn = (route, state) => {
const userStore = inject(UserStoreService);
const authenticateService = inject(AuthService);
const toastService = inject(ToastService);
const router = inject(Router);
return userStore.getRoleFromStore().pipe(
map(val => {
const roleFromToken = authenticateService.getRoleFromToken();
const role = val || roleFromToken;
if (role === "Admin" || role === "SuperAdmin") {
return true;
} else {
toastService.show("Access denied. Admins only.", {
classname: 'bg-warning text-dark',
delay: 3000
});
void router.navigate(['/unauthorized']);
return false;
}
}),
catchError(() => {
toastService.show("An error occurred. Please try again later.", {
classname: 'bg-danger text-light',
delay: 2000
});
void router.navigate(['/login']);
return of(false);
})
);
};

View File

@@ -0,0 +1,24 @@
import {TestBed} from '@angular/core/testing';
import {AuthenticationGuard} from './authentication.guard';
import {provideHttpClient} from "@angular/common/http";
import {ActivatedRoute} from "@angular/router";
import {of} from "rxjs";
describe('AuthenticationGuard', () => {
let guard: AuthenticationGuard;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [provideHttpClient(),
{ provide: ActivatedRoute, useValue: { data: of({}), firstChild: null } },
]
});
guard = TestBed.inject(AuthenticationGuard);
});
it('should be created', () => {
expect(guard).toBeTruthy();
});
});

View File

@@ -0,0 +1,29 @@
import {inject, Injectable} from '@angular/core';
import {CanActivate, Router} from '@angular/router';
import {AuthService} from "../../infrastructure/services/auth-service";
import {ToastService} from "../../infrastructure/services/toast.service";
@Injectable({
providedIn: 'root'
})
export class AuthenticationGuard implements CanActivate {
toastService = inject(ToastService);
private authenticateService = inject(AuthService)
private router = inject(Router)
canActivate(): boolean {
if (this.authenticateService.isLoggedIn()) {
return true;
} else {
this.toastService.show("Please Login first", {
classname: 'bg-warning text-dark',
delay: 2000
});
this.router.navigate(['/login']).catch(error => {
console.error('Navigation error:', error);
})
return false;
}
}
}

View File

@@ -0,0 +1,17 @@
import { TestBed } from '@angular/core/testing';
import { CanActivateFn } from '@angular/router';
import { guestGuard } from './guest.guard';
describe('guestGuard', () => {
const executeGuard: CanActivateFn = (...guardParameters) =>
TestBed.runInInjectionContext(() => guestGuard(...guardParameters));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(executeGuard).toBeTruthy();
});
});

View File

@@ -0,0 +1,16 @@
import {CanActivateFn, Router} from '@angular/router';
import {inject} from "@angular/core";
import {AuthService} from "../../infrastructure/services/auth-service";
export const guestGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (!authService.isLoggedIn()){
return true;
}
// TODO rout
void router.navigate(['/user-dashboard']);
return false;
};

View File

@@ -0,0 +1,17 @@
import {TestBed} from '@angular/core/testing';
import {HttpInterceptorFn} from '@angular/common/http';
import {tokenInterceptor} from './token.interceptor';
describe('tokenInterceptor', () => {
const interceptor: HttpInterceptorFn = (req, next) =>
TestBed.runInInjectionContext(() => tokenInterceptor(req, next));
beforeEach(() => {
TestBed.configureTestingModule({});
});
it('should be created', () => {
expect(interceptor).toBeTruthy();
});
});

View File

@@ -0,0 +1,75 @@
import {HttpErrorResponse, HttpEvent, HttpHandlerFn, HttpInterceptorFn, HttpRequest} from '@angular/common/http';
import {inject} from "@angular/core";
import {AuthService} from "../../infrastructure/services/auth-service";
import {catchError, Observable, switchMap, throwError} from "rxjs";
import {ToastService} from "../../infrastructure/services/toast.service";
import {Router} from '@angular/router';
import {RefreshTokenRequest} from "../models/refresh-token-request";
export const tokenInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
const toastService = inject(ToastService);
const router = inject(Router);
if (token) {
req = req.clone({
setHeaders: {Authorization: `Bearer ${token}`}
});
}
return next(req).pipe(
catchError((err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
return handleUnAuthorizedError(req, next, authService, router, toastService);
}
}
console.log("interceptor error",err.error?.error?.message);
return throwError(() => err);
})
);
};
function handleUnAuthorizedError(
req: HttpRequest<any>,
next: HttpHandlerFn,
authenticateService: AuthService,
router: Router,
toastService: ToastService
): Observable<HttpEvent<any>> {
const refreshTokenRequest = new RefreshTokenRequest();
refreshTokenRequest.refreshToken = authenticateService.getRefreshToken()!;
refreshTokenRequest.userId = authenticateService.getUserIdFromToken()!;
return authenticateService.renewToken(refreshTokenRequest).pipe(
switchMap((data) => {
const tokenResponse = data.value;
authenticateService.storeRefreshToken(tokenResponse.refreshToken);
authenticateService.storeToken(tokenResponse.accessToken);
req = req.clone({
setHeaders: {Authorization: `Bearer ${tokenResponse.accessToken}`}
});
return next(req);
}),
catchError((err) => {
return throwError(() => {
authenticateService.signOut();
router.navigate(['login']).then(success => {
if (success) {
toastService.show(err.error?.error?.message ||'Token is expired, login again!', {
classname: 'bg-warning text-light',
delay: 2000
});
}
})
});
})
);
}

View File

@@ -0,0 +1,19 @@
<div class="modal fade" id="warningModal" tabindex="-1" aria-labelledby="warningModalLabel" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" [ngClass]="headerClass">
<h1 class="modal-title fs-5 text-center w-100" id="warningModalLabel">{{ title }}</h1>
</div>
<div class="modal-body">
<ng-content></ng-content>
@if (body) {
<p>{{ body }}</p>
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">No</button>
<button type="button" class="btn btn-warning" (click)="onConfirm()" data-bs-dismiss="modal">Yes</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopupModalComponent } from './popup-modal.component';
describe('PopupModalComponent', () => {
let component: PopupModalComponent;
let fixture: ComponentFixture<PopupModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PopupModalComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PopupModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,26 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {NgClass} from "@angular/common";
@Component({
selector: 'app-popup-modal',
imports: [
NgClass
],
templateUrl: './popup-modal.component.html',
styleUrl: './popup-modal.component.scss',
standalone: true
})
export class PopupModalComponent {
@Input() headerClass: string = 'bg-light';
@Input() title: string = '';
@Input() body: string = '';
@Output() confirm = new EventEmitter<void>();
@Output() cancel = new EventEmitter<void>();
onConfirm() {
this.confirm.emit();
}
}

View File

@@ -1,6 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser'; import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config'; import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component'; import { AppComponent } from './app/app.component';
import 'bootstrap';
bootstrapApplication(AppComponent, appConfig) bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err)); .catch((err) => console.error(err));

View File

@@ -14,18 +14,18 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="2.3.9" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.3.9" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.3.9" /> <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.3.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.3"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.3" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -0,0 +1,185 @@
// <auto-generated />
using System;
using Infrastructure.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Infrastructure.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20260311163032_NewMigration")]
partial class NewMigration
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Domain.Entities.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.ToTable("Roles", "auth");
b.HasData(
new
{
Id = 1,
Name = "SuperAdmin"
},
new
{
Id = 2,
Name = "Admin"
},
new
{
Id = 3,
Name = "User"
});
});
modelBuilder.Entity("Domain.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)")
.HasAnnotation("RegularExpression", "^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
b.Property<DateTime>("LastLogin")
.HasColumnType("timestamp with time zone");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(250)
.HasColumnType("varchar(250)");
b.Property<string>("RefreshToken")
.HasColumnType("text");
b.Property<DateTime?>("RefreshTokenExpiryTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("ResetPasswordToken")
.HasColumnType("text");
b.Property<DateTime>("ResetPasswordTokenExpiryTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Username")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("varchar(50)");
b.HasKey("Id");
b.ToTable("Users", "auth");
b.HasData(
new
{
Id = 1,
Email = "superadmin@wenske-services-development.de",
LastLogin = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
Password = "AQAAAAIAAYagAAAAEADJEu1s5qUJyP4gDUrBGyqSNtKU2IKBpZm0JqfyvOkJnqVeOHZBUrEhNr7IdQRDBQ==",
ResetPasswordTokenExpiryTime = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
Username = "Superadmin"
},
new
{
Id = 2,
Email = "admin@wenske-services-development.de",
LastLogin = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
Password = "AQAAAAIAAYagAAAAEIOUiJUfMrM1Lpt4Ae3FLQOB/Bk6WHtndRAWUp132afVunMvRqkT6Hhh+27kkNW8YQ==",
ResetPasswordTokenExpiryTime = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
Username = "Admin"
});
});
modelBuilder.Entity("Domain.Entities.UserRole", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRoles", "auth");
b.HasData(
new
{
UserId = 1,
RoleId = 1
},
new
{
UserId = 2,
RoleId = 2
});
});
modelBuilder.Entity("Domain.Entities.UserRole", b =>
{
b.HasOne("Domain.Entities.Role", "Role")
.WithMany("UserRoles")
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Domain.Entities.User", "User")
.WithMany("UserRoles")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Role");
b.Navigation("User");
});
modelBuilder.Entity("Domain.Entities.Role", b =>
{
b.Navigation("UserRoles");
});
modelBuilder.Entity("Domain.Entities.User", b =>
{
b.Navigation("UserRoles");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,50 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Infrastructure.Migrations
{
/// <inheritdoc />
public partial class NewMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
schema: "auth",
table: "Users",
keyColumn: "Id",
keyValue: 1,
columns: new[] { "Email", "Password" },
values: new object[] { "superadmin@wenske-services-development.de", "AQAAAAIAAYagAAAAEADJEu1s5qUJyP4gDUrBGyqSNtKU2IKBpZm0JqfyvOkJnqVeOHZBUrEhNr7IdQRDBQ==" });
migrationBuilder.UpdateData(
schema: "auth",
table: "Users",
keyColumn: "Id",
keyValue: 2,
columns: new[] { "Email", "Password" },
values: new object[] { "admin@wenske-services-development.de", "AQAAAAIAAYagAAAAEIOUiJUfMrM1Lpt4Ae3FLQOB/Bk6WHtndRAWUp132afVunMvRqkT6Hhh+27kkNW8YQ==" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
schema: "auth",
table: "Users",
keyColumn: "Id",
keyValue: 1,
columns: new[] { "Email", "Password" },
values: new object[] { "admin@rss.wenske-services-development.de", "AQAAAAIAAYagAAAAELBxAsYVTssn5taCQ7CMo+Mzn0i87Jt8ZXJTe7cgG5hfN3wDJzIkQaotyFhM/mQGaQ==" });
migrationBuilder.UpdateData(
schema: "auth",
table: "Users",
keyColumn: "Id",
keyValue: 2,
columns: new[] { "Email", "Password" },
values: new object[] { "info@rss.wenske-services-development.de", "AQAAAAIAAYagAAAAEP0NWiTTz20doMf/KL0WkBR+5roc5KTouMrfiHk2MMXOQn+E+C5Q4dqWD7PnNoxUmQ==" });
}
}
}

View File

@@ -12,7 +12,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5"> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -12,7 +12,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5"> <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>