Add authentication and authorization #21
@@ -37,6 +37,9 @@ Store your favorite games, intelligent game add, store game files and data, mana
|
|||||||
| DB_USERNAME | Username for the database |
|
| DB_USERNAME | Username for the database |
|
||||||
| DB_PASSWORD | Plain password for the database |
|
| DB_PASSWORD | Plain password for the database |
|
||||||
| DB_DATABASE | Name of the database |
|
| DB_DATABASE | Name of the database |
|
||||||
|
| JWT_KEY | Key for your jwt tokens |
|
||||||
|
| JWT_ISSUER | Your domain name |
|
||||||
|
| JWT_AUDIENCE | Your domain name |
|
||||||
|
|
||||||
<!-- ## Installation
|
<!-- ## Installation
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
@using GameIdeas.BlazorApp.Layouts
|
@using GameIdeas.BlazorApp.Layouts
|
||||||
|
@using Microsoft.AspNetCore.Components.Authorization
|
||||||
|
|
||||||
|
<CascadingAuthenticationState>
|
||||||
|
<Router AppAssembly="@typeof(App).Assembly">
|
||||||
|
<Found Context="routeData">
|
||||||
|
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
||||||
|
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||||
|
</Found>
|
||||||
|
<NotFound>
|
||||||
|
<PageTitle>Not found</PageTitle>
|
||||||
|
<LayoutView Layout="@typeof(MainLayout)">
|
||||||
|
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||||
|
</LayoutView>
|
||||||
|
</NotFound>
|
||||||
|
</Router>
|
||||||
|
</CascadingAuthenticationState>
|
||||||
|
|
||||||
<Router AppAssembly="@typeof(App).Assembly">
|
|
||||||
<Found Context="routeData">
|
|
||||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
|
|
||||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
|
||||||
</Found>
|
|
||||||
<NotFound>
|
|
||||||
<PageTitle>Not found</PageTitle>
|
|
||||||
<LayoutView Layout="@typeof(MainLayout)">
|
|
||||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
|
||||||
</LayoutView>
|
|
||||||
</NotFound>
|
|
||||||
</Router>
|
|
||||||
|
|||||||
@@ -9,10 +9,13 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Blazored.FluentValidation" Version="2.2.0" />
|
<PackageReference Include="Blazored.FluentValidation" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||||
<PackageReference Include="FluentValidation" Version="11.11.0" />
|
<PackageReference Include="FluentValidation" Version="11.11.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.2" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.2" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.2" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Dto;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Helpers;
|
namespace GameIdeas.BlazorApp.Helpers;
|
||||||
|
|
||||||
public static class GameHelper
|
public static class GameHelper
|
||||||
{
|
{
|
||||||
public static void WriteTrackingDto(GameDetailDto game)
|
public static void WriteTrackingDto(GameDetailDto game, AuthenticationState authState)
|
||||||
{
|
{
|
||||||
game.CreationUserId = 100000;
|
if (authState == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(authState), "Authentication state missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = authState.User.FindFirstValue(ClaimTypes.Sid);
|
||||||
|
|
||||||
|
if (userId == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(authState), "user state missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
game.CreationUserId = userId;
|
||||||
game.CreationDate = DateTime.Now;
|
game.CreationDate = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
|||||||
using GameIdeas.BlazorApp.Shared.Components.Slider;
|
using GameIdeas.BlazorApp.Shared.Components.Slider;
|
||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Dto;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Pages.Games.Components;
|
namespace GameIdeas.BlazorApp.Pages.Games.Components;
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ public partial class GameCreationForm
|
|||||||
{
|
{
|
||||||
[Inject] private IJSRuntime Js { get; set; } = default!;
|
[Inject] private IJSRuntime Js { get; set; } = default!;
|
||||||
[Inject] private IGameGateway GameGateway { get; set; } = default!;
|
[Inject] private IGameGateway GameGateway { get; set; } = default!;
|
||||||
|
[Inject] private AuthenticationStateProvider AuthenticationState { get; set; } = default!;
|
||||||
[CascadingParameter] private Popup? Popup { get; set; }
|
[CascadingParameter] private Popup? Popup { get; set; }
|
||||||
[Parameter] public CategoriesDto? Categories { get; set; }
|
[Parameter] public CategoriesDto? Categories { get; set; }
|
||||||
[Parameter] public EventCallback OnSubmit { get; set; }
|
[Parameter] public EventCallback OnSubmit { get; set; }
|
||||||
@@ -33,7 +36,6 @@ public partial class GameCreationForm
|
|||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
await Js.InvokeVoidAsync("resizeGameForm");
|
await Js.InvokeVoidAsync("resizeGameForm");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleOnCancel()
|
private void HandleOnCancel()
|
||||||
@@ -52,7 +54,9 @@ public partial class GameCreationForm
|
|||||||
{
|
{
|
||||||
IsLoading = true;
|
IsLoading = true;
|
||||||
|
|
||||||
GameHelper.WriteTrackingDto(GameDto);
|
var authState = await AuthenticationState.GetAuthenticationStateAsync();
|
||||||
|
GameHelper.WriteTrackingDto(GameDto, authState);
|
||||||
|
|
||||||
var gameId = await GameGateway.CreateGame(GameDto);
|
var gameId = await GameGateway.CreateGame(GameDto);
|
||||||
|
|
||||||
if (gameId != 0)
|
if (gameId != 0)
|
||||||
@@ -68,6 +72,7 @@ public partial class GameCreationForm
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
IsLoading = false;
|
IsLoading = false;
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
@using GameIdeas.BlazorApp.Pages.Games
|
@using GameIdeas.BlazorApp.Pages.Games
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Account
|
@using GameIdeas.BlazorApp.Pages.User
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Select
|
@using GameIdeas.BlazorApp.Shared.Components.Select
|
||||||
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
|
@using GameIdeas.BlazorApp.Shared.Components.Select.Models
|
||||||
@using GameIdeas.BlazorApp.Shared.Models
|
@using GameIdeas.BlazorApp.Shared.Models
|
||||||
@using GameIdeas.Resources
|
@using GameIdeas.Resources
|
||||||
|
@using GameIdeas.Shared.Constants
|
||||||
|
@using Microsoft.AspNetCore.Components.Authorization
|
||||||
|
|
||||||
@inherits ComponentBase
|
@inherits ComponentBase
|
||||||
|
|
||||||
@@ -15,30 +17,26 @@
|
|||||||
@ChildContent
|
@ChildContent
|
||||||
|
|
||||||
<div class="account-add-container">
|
<div class="account-add-container">
|
||||||
<div class="add-container">
|
<AuthorizeView Roles="@GlobalConstants.ADMIN_MEMBER">
|
||||||
<div class="add-buttons">
|
<Authorized>
|
||||||
<div class="first-button button">
|
<div class="add-buttons">
|
||||||
<svg class="button-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<div class="first-button button">
|
||||||
<path d="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<Select @ref="SelectListAdd" TItem="KeyValuePair<AddType, string>" THeader="object"
|
|
||||||
ValuesChanged=HandleAddTypeClicked Params=SelectParams Theme="SelectTheme.Navigation">
|
|
||||||
<div class="second-button button">
|
|
||||||
<svg class="button-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg class="button-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path d="M1 3H23L12 22" />
|
<path d="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</Select>
|
<Select @ref="SelectListAdd" TItem="KeyValuePair<AddType, string>" THeader="object"
|
||||||
</div>
|
ValuesChanged=HandleAddTypeClicked Params=SelectParams Theme="SelectTheme.Navigation">
|
||||||
</div>
|
<div class="second-button button">
|
||||||
<div class="account-container">
|
<svg class="button-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<div class="icon-container" @onclick=HandleAccountClicked>
|
<path d="M1 3H23L12 22" />
|
||||||
<svg class="account-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
</svg>
|
||||||
<path d="M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z" />
|
</div>
|
||||||
</svg>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<AccountSettings @ref="AccountSettings" />
|
</Authorized>
|
||||||
</div>
|
</AuthorizeView>
|
||||||
|
|
||||||
|
<UserMenu />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GameIdeas.BlazorApp.Shared.Components.Account;
|
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Select;
|
using GameIdeas.BlazorApp.Shared.Components.Select;
|
||||||
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
using GameIdeas.BlazorApp.Shared.Components.Select.Models;
|
||||||
using GameIdeas.BlazorApp.Shared.Models;
|
using GameIdeas.BlazorApp.Shared.Models;
|
||||||
@@ -18,7 +17,6 @@ public partial class GameHeader : ComponentBase
|
|||||||
{ AddType.Auto, ResourcesKey.AutoAdd }
|
{ AddType.Auto, ResourcesKey.AutoAdd }
|
||||||
};
|
};
|
||||||
|
|
||||||
private AccountSettings? AccountSettings;
|
|
||||||
private Select<KeyValuePair<AddType, string>, object>? SelectListAdd;
|
private Select<KeyValuePair<AddType, string>, object>? SelectListAdd;
|
||||||
private SelectParams<KeyValuePair<AddType, string>, object> SelectParams = new();
|
private SelectParams<KeyValuePair<AddType, string>, object> SelectParams = new();
|
||||||
|
|
||||||
@@ -26,7 +24,7 @@ public partial class GameHeader : ComponentBase
|
|||||||
{
|
{
|
||||||
SelectParams = new()
|
SelectParams = new()
|
||||||
{
|
{
|
||||||
Items = AddTypes.ToList(),
|
Items = [.. AddTypes],
|
||||||
GetItemLabel = item => item.Value
|
GetItemLabel = item => item.Value
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,9 +41,4 @@ public partial class GameHeader : ComponentBase
|
|||||||
SelectListAdd?.Close();
|
SelectListAdd?.Close();
|
||||||
await AddTypeChanged.InvokeAsync(values.FirstOrDefault().Key);
|
await AddTypeChanged.InvokeAsync(values.FirstOrDefault().Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleAccountClicked()
|
|
||||||
{
|
|
||||||
AccountSettings?.Toggle();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-container img {
|
.icon-container img {
|
||||||
@@ -21,10 +22,6 @@
|
|||||||
max-width: 85%;
|
max-width: 85%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-container:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.account-add-container {
|
.account-add-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -32,15 +29,12 @@
|
|||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-container {
|
|
||||||
margin-right: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-buttons {
|
.add-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
background: var(--violet);
|
background: var(--violet);
|
||||||
border-radius: var(--small-radius);
|
border-radius: var(--small-radius);
|
||||||
|
margin-right: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
@@ -70,8 +64,4 @@
|
|||||||
.button-icon:hover {
|
.button-icon:hover {
|
||||||
background: var(--violet-selected);
|
background: var(--violet-selected);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.account-icon {
|
|
||||||
fill: var(--line);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
@using Blazored.FluentValidation
|
||||||
|
|
||||||
|
<EditForm EditContext="EditContext" OnSubmit="HandleLoginSubmit">
|
||||||
|
<FluentValidationValidator />
|
||||||
|
<div class="login-form">
|
||||||
|
<div class="login-field">
|
||||||
|
<div class="input-title">@ResourcesKey.EnterUsername</div>
|
||||||
|
<InputText class="input-text"
|
||||||
|
@bind-Value="UserDto.Username" />
|
||||||
|
</div>
|
||||||
|
<div class="login-field">
|
||||||
|
<div class="input-title">@ResourcesKey.EnterPassword</div>
|
||||||
|
<InputText class="input-text"
|
||||||
|
@bind-Value="UserDto.Password" />
|
||||||
|
</div>
|
||||||
|
<div class="login-field">
|
||||||
|
<button class="login-button" type="submit" disabled="@IsLoading">
|
||||||
|
@if (IsLoading)
|
||||||
|
{
|
||||||
|
<div class="loading"></div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@ResourcesKey.Login
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using GameIdeas.BlazorApp.Pages.User.Gateways;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.User.Components;
|
||||||
|
|
||||||
|
public partial class Login
|
||||||
|
{
|
||||||
|
[Parameter] public IAuthGateway AuthGateway { get; set; } = default!;
|
||||||
|
|
||||||
|
private EditContext? EditContext;
|
||||||
|
private UserDto UserDto = new();
|
||||||
|
private bool IsLoading = false;
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
EditContext = new EditContext(UserDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleLoginSubmit()
|
||||||
|
{
|
||||||
|
if (EditContext?.Validate() == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
await AuthGateway.Login(UserDto);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
UserDto.Password = string.Empty;
|
||||||
|
EditContext?.Validate();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,4 @@
|
|||||||
.account-setting-content {
|
.login-form {
|
||||||
overflow: hidden;
|
|
||||||
border-radius: var(--big-radius);
|
|
||||||
position: fixed;
|
|
||||||
animation-name: fade-in;
|
|
||||||
animation-duration: 0.4s;
|
|
||||||
border: 2px solid var(--input-selected);
|
|
||||||
background: var(--dropdown-content);
|
|
||||||
right: 10px;
|
|
||||||
margin-top: 4px;
|
|
||||||
z-index: var(--index-floating);
|
|
||||||
}
|
|
||||||
|
|
||||||
.invisible {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-form {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 20px 8px;
|
padding: 20px 8px;
|
||||||
@@ -53,7 +36,7 @@
|
|||||||
|
|
||||||
.login-button:hover {
|
.login-button:hover {
|
||||||
background: var(--violet-selected);
|
background: var(--violet-selected);
|
||||||
cursor:pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-button:disabled {
|
.login-button:disabled {
|
||||||
@@ -70,26 +53,3 @@
|
|||||||
animation: loading 1s linear infinite;
|
animation: loading 1s linear infinite;
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line {
|
|
||||||
margin: 0 6px;
|
|
||||||
border-bottom: 2px solid var(--line);
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-element {
|
|
||||||
max-width: 140px;
|
|
||||||
height: 40px;
|
|
||||||
padding: 0 26px;
|
|
||||||
align-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-element:hover {
|
|
||||||
background: var(--line)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Account;
|
namespace GameIdeas.BlazorApp.Pages.User.Components;
|
||||||
|
|
||||||
public class LoginValidator : AbstractValidator<LoginDto>
|
public class LoginValidator : AbstractValidator<UserDto>
|
||||||
{
|
{
|
||||||
public LoginValidator()
|
public LoginValidator()
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using GameIdeas.BlazorApp.Services;
|
||||||
|
using GameIdeas.BlazorApp.Shared.Constants;
|
||||||
|
using GameIdeas.BlazorApp.Shared.Exceptions;
|
||||||
|
using GameIdeas.Resources;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.User.Gateways;
|
||||||
|
|
||||||
|
public class AuthGateway(IHttpClientService httpClient,
|
||||||
|
AuthenticationStateProvider stateProvider) : IAuthGateway
|
||||||
|
{
|
||||||
|
public async Task<bool> Login(UserDto userDto)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = await httpClient.PostAsync<TokenDto>(Endpoints.Auth.Login, userDto);
|
||||||
|
await ((JwtAuthenticationStateProvider)stateProvider).NotifyUserAuthenticationAsync(token!.Token!);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
throw new AuthenticationUserException(ResourcesKey.UserLoginFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Logout()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ((JwtAuthenticationStateProvider)stateProvider).NotifyUserLogoutAsync();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
throw new AuthenticationUserException(ResourcesKey.UserLogoutFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.User.Gateways;
|
||||||
|
|
||||||
|
public interface IAuthGateway
|
||||||
|
{
|
||||||
|
Task<bool> Login(UserDto userDto);
|
||||||
|
Task Logout();
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
@using GameIdeas.BlazorApp.Pages.User.Components
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Components.BackdropFilter
|
||||||
|
@using GameIdeas.BlazorApp.Shared.Constants
|
||||||
|
@using GameIdeas.Shared.Constants
|
||||||
|
@using Microsoft.AspNetCore.Components.Authorization
|
||||||
|
|
||||||
|
<div class="menu">
|
||||||
|
<div class="icon" @onclick=HandleAccountClicked>
|
||||||
|
@Icons.Account
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
@if (ContentVisile)
|
||||||
|
{
|
||||||
|
<div class="content">
|
||||||
|
<AuthorizeView Roles="@GlobalConstants.ADMIN_MEMBER">
|
||||||
|
<Authorized>
|
||||||
|
<div class="menu-element">
|
||||||
|
@ResourcesKey.CategoriesManager
|
||||||
|
</div>
|
||||||
|
<span class="line"></span>
|
||||||
|
</Authorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
||||||
|
<AuthorizeView Roles="@GlobalConstants.ADMINISTRATOR">
|
||||||
|
<Authorized>
|
||||||
|
<div class="menu-element">
|
||||||
|
@ResourcesKey.UserManager
|
||||||
|
</div>
|
||||||
|
<span class="line"></span>
|
||||||
|
</Authorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
||||||
|
<AuthorizeView>
|
||||||
|
<Authorized>
|
||||||
|
<div class="menu-element" @onclick="HandleLogoutClicked">
|
||||||
|
@ResourcesKey.Logout
|
||||||
|
</div>
|
||||||
|
</Authorized>
|
||||||
|
<NotAuthorized>
|
||||||
|
<Login AuthGateway="AuthGateway" />
|
||||||
|
</NotAuthorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<BackdropFilter AllowBodyScroll=true CloseOnClick=true Color="BackdropFilterColor.Transparent"
|
||||||
|
IsVisible="ContentVisile" OnClick="HandleBackdropFilterClicked" />
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using GameIdeas.BlazorApp.Pages.User.Gateways;
|
||||||
|
using GameIdeas.BlazorApp.Services;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Pages.User;
|
||||||
|
|
||||||
|
public partial class UserMenu
|
||||||
|
{
|
||||||
|
[Inject] private IAuthGateway AuthGateway { get; set; } = default!;
|
||||||
|
|
||||||
|
private bool ContentVisile = false;
|
||||||
|
|
||||||
|
private async Task HandleLogoutClicked()
|
||||||
|
{
|
||||||
|
await AuthGateway.Logout();
|
||||||
|
ContentVisile = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleAccountClicked()
|
||||||
|
{
|
||||||
|
ContentVisile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleBackdropFilterClicked()
|
||||||
|
{
|
||||||
|
ContentVisile = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
.menu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon ::deep svg {
|
||||||
|
fill: var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
right: 0;
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 4px;
|
||||||
|
z-index: var(--index-dropdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: var(--big-radius);
|
||||||
|
border: 2px solid var(--input-selected);
|
||||||
|
background: var(--dropdown-content);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
margin: 0 6px;
|
||||||
|
border-bottom: 2px solid var(--input-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-element {
|
||||||
|
height: 32px;
|
||||||
|
padding: 0 20px;
|
||||||
|
align-content: center;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-element:hover {
|
||||||
|
background: var(--input-selected)
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
|
using Blazored.LocalStorage;
|
||||||
using GameIdeas.BlazorApp;
|
using GameIdeas.BlazorApp;
|
||||||
using GameIdeas.BlazorApp.Pages.Games.Gateways;
|
using GameIdeas.BlazorApp.Pages.Games.Gateways;
|
||||||
|
using GameIdeas.BlazorApp.Pages.User.Gateways;
|
||||||
using GameIdeas.BlazorApp.Services;
|
using GameIdeas.BlazorApp.Services;
|
||||||
using GameIdeas.Resources;
|
using GameIdeas.Resources;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
|
||||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
|
var services = builder.Services;
|
||||||
|
|
||||||
builder.RootComponents.Add<App>("#app");
|
builder.RootComponents.Add<App>("#app");
|
||||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||||
|
|
||||||
@@ -15,7 +20,7 @@ UriBuilder uriBuilder = new(builder.HostEnvironment.BaseAddress)
|
|||||||
Port = 8000
|
Port = 8000
|
||||||
};
|
};
|
||||||
|
|
||||||
builder.Services.AddHttpClient(
|
services.AddHttpClient(
|
||||||
"GameIdeas.WebAPI",
|
"GameIdeas.WebAPI",
|
||||||
client =>
|
client =>
|
||||||
{
|
{
|
||||||
@@ -23,11 +28,18 @@ builder.Services.AddHttpClient(
|
|||||||
client.Timeout = TimeSpan.FromMinutes(3);
|
client.Timeout = TimeSpan.FromMinutes(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped<IHttpClientService, HttpClientService>();
|
services.AddBlazoredLocalStorage();
|
||||||
builder.Services.AddScoped<IGameGateway, GameGateway>();
|
services.AddAuthorizationCore();
|
||||||
|
|
||||||
builder.Services.AddSingleton<TranslationService>();
|
services.AddScoped<AuthenticationStateProvider, JwtAuthenticationStateProvider>();
|
||||||
builder.Services.AddSingleton<Translations>();
|
|
||||||
|
services.AddScoped<IHttpClientService, HttpClientService>();
|
||||||
|
|
||||||
|
services.AddScoped<IAuthGateway, AuthGateway>();
|
||||||
|
services.AddScoped<IGameGateway, GameGateway>();
|
||||||
|
|
||||||
|
services.AddSingleton<TranslationService>();
|
||||||
|
services.AddSingleton<Translations>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,15 @@ using System.Net.Http.Headers;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Blazored.LocalStorage;
|
||||||
|
using GameIdeas.Shared.Constants;
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Services;
|
namespace GameIdeas.BlazorApp.Services;
|
||||||
|
|
||||||
public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFactory loggerFactory) : IHttpClientService
|
public class HttpClientService(
|
||||||
|
IHttpClientFactory httpClientFactory,
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
ILocalStorageService localStorage) : IHttpClientService
|
||||||
{
|
{
|
||||||
private readonly HttpClient httpClient = httpClientFactory.CreateClient("GameIdeas.WebAPI");
|
private readonly HttpClient httpClient = httpClientFactory.CreateClient("GameIdeas.WebAPI");
|
||||||
private readonly ILogger<HttpClientService> logger = loggerFactory.CreateLogger<HttpClientService>();
|
private readonly ILogger<HttpClientService> logger = loggerFactory.CreateLogger<HttpClientService>();
|
||||||
@@ -25,6 +30,8 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<T?> PostAsync<T>(string url, object data)
|
public async Task<T?> PostAsync<T>(string url, object data)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
|
|
||||||
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
|
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||||
var response = await httpClient.PostAsync(url, content);
|
var response = await httpClient.PostAsync(url, content);
|
||||||
@@ -32,8 +39,11 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenPostingData);
|
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenPostingData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<T?> PutAsync<T>(string url, object data)
|
public async Task<T?> PutAsync<T>(string url, object data)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
|
|
||||||
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
|
var jsonContent = JsonSerializer.Serialize(data, _optionsCamelCase);
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||||
var response = await httpClient.PutAsync(url, content);
|
var response = await httpClient.PutAsync(url, content);
|
||||||
@@ -43,6 +53,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<T?> DeleteAsync<T>(string? url)
|
public async Task<T?> DeleteAsync<T>(string? url)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
var response = await httpClient.DeleteAsync(url);
|
var response = await httpClient.DeleteAsync(url);
|
||||||
|
|
||||||
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenDeletingData);
|
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenDeletingData);
|
||||||
@@ -50,6 +61,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<T?> FetchDataAsync<T>(string? url)
|
public async Task<T?> FetchDataAsync<T>(string? url)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
var response = await httpClient.GetAsync(url);
|
var response = await httpClient.GetAsync(url);
|
||||||
|
|
||||||
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenFetchingData);
|
return await GetResultValue<T>(response, ResourcesKey.ErrorWhenFetchingData);
|
||||||
@@ -57,6 +69,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<byte[]?> FetchBytesAsync(string? url)
|
public async Task<byte[]?> FetchBytesAsync(string? url)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
var response = await httpClient.GetAsync(url);
|
var response = await httpClient.GetAsync(url);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
@@ -71,6 +84,7 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<Stream?> FetchStreamAsync(string? url)
|
public async Task<Stream?> FetchStreamAsync(string? url)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
var response = await httpClient.GetAsync(url);
|
var response = await httpClient.GetAsync(url);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
@@ -84,6 +98,8 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
|
|
||||||
public async Task<T?> PostFileAsync<T>(string? url, Stream fileStream, string fileName, string contentType)
|
public async Task<T?> PostFileAsync<T>(string? url, Stream fileStream, string fileName, string contentType)
|
||||||
{
|
{
|
||||||
|
await SetAuthorizationHeader();
|
||||||
|
|
||||||
using var content = new MultipartFormDataContent();
|
using var content = new MultipartFormDataContent();
|
||||||
|
|
||||||
var streamContent = new StreamContent(fileStream);
|
var streamContent = new StreamContent(fileStream);
|
||||||
@@ -122,4 +138,11 @@ public class HttpClientService(IHttpClientFactory httpClientFactory, ILoggerFact
|
|||||||
throw new HttpRequestException(
|
throw new HttpRequestException(
|
||||||
$"{errorMessage} + StatusCode: {response.StatusCode} + Reason: {response.ReasonPhrase}");
|
$"{errorMessage} + StatusCode: {response.StatusCode} + Reason: {response.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SetAuthorizationHeader()
|
||||||
|
{
|
||||||
|
var token = await localStorage.GetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization =
|
||||||
|
new AuthenticationHeaderValue("bearer", token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using Blazored.LocalStorage;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using GameIdeas.Shared.Constants;
|
||||||
|
|
||||||
|
namespace GameIdeas.BlazorApp.Services;
|
||||||
|
|
||||||
|
public class JwtAuthenticationStateProvider(ILocalStorageService localStorage) : AuthenticationStateProvider
|
||||||
|
{
|
||||||
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
|
{
|
||||||
|
var savedToken = await localStorage.GetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(savedToken))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = new JwtSecurityTokenHandler().ReadJwtToken(savedToken);
|
||||||
|
|
||||||
|
return new AuthenticationState(
|
||||||
|
new ClaimsPrincipal(new ClaimsIdentity(token.Claims, "jwt"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await localStorage.RemoveItemAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyUserAuthenticationAsync(string token)
|
||||||
|
{
|
||||||
|
await localStorage.SetItemAsStringAsync(GlobalConstants.LS_AUTH_STORAGE_KEY, token);
|
||||||
|
|
||||||
|
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyUserLogoutAsync()
|
||||||
|
{
|
||||||
|
await localStorage.RemoveItemAsync(GlobalConstants.LS_AUTH_STORAGE_KEY);
|
||||||
|
|
||||||
|
var nobody = new ClaimsPrincipal(new ClaimsIdentity());
|
||||||
|
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(nobody)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
@using GameIdeas.Resources
|
|
||||||
@using Blazored.FluentValidation;
|
|
||||||
|
|
||||||
<div class="account-setting-container" tabindex="1000">
|
|
||||||
<div class="account-setting-content @(ContentVisile ? string.Empty : "invisible")">
|
|
||||||
@if (!IsLogin)
|
|
||||||
{
|
|
||||||
<EditForm EditContext="EditContext" OnSubmit="HandleLoginSubmit">
|
|
||||||
<FluentValidationValidator />
|
|
||||||
<div class="login-form">
|
|
||||||
<div class="login-field">
|
|
||||||
<div class="input-title">@ResourcesKey.EnterUsername</div>
|
|
||||||
<InputText class="input-text"
|
|
||||||
@bind-Value="LoginDto.Username" />
|
|
||||||
</div>
|
|
||||||
<div class="login-field">
|
|
||||||
<div class="input-title">@ResourcesKey.EnterPassword</div>
|
|
||||||
<InputText class="input-text"
|
|
||||||
@bind-Value="LoginDto.Password" />
|
|
||||||
</div>
|
|
||||||
<div class="login-field">
|
|
||||||
<button class="login-button" type="submit" disabled="@IsLoading">
|
|
||||||
@if (IsLoading)
|
|
||||||
{
|
|
||||||
<div class="loading"></div>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@ResourcesKey.Login
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</EditForm>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<div class="settings-list">
|
|
||||||
<div class="settings-element">
|
|
||||||
@ResourcesKey.UserManager
|
|
||||||
</div>
|
|
||||||
<span class="line"></span>
|
|
||||||
<div class="settings-element" @onclick="HandleLogoutClicked">
|
|
||||||
@ResourcesKey.Logout
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using GameIdeas.Shared.Dto;
|
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
|
||||||
|
|
||||||
namespace GameIdeas.BlazorApp.Shared.Components.Account;
|
|
||||||
|
|
||||||
public partial class AccountSettings
|
|
||||||
{
|
|
||||||
private bool ContentVisile = false;
|
|
||||||
private EditContext? EditContext;
|
|
||||||
private LoginDto LoginDto = new();
|
|
||||||
private bool IsLoading = false;
|
|
||||||
private bool IsLogin = true;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
EditContext = new EditContext(LoginDto);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
ContentVisile = false;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Toggle()
|
|
||||||
{
|
|
||||||
ContentVisile = !ContentVisile;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleLoginSubmit()
|
|
||||||
{
|
|
||||||
if (EditContext?.Validate() == false)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsLoading = true;
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(5));
|
|
||||||
Close();
|
|
||||||
IsLoading = false;
|
|
||||||
}
|
|
||||||
private void HandleLogoutClicked()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,4 +15,9 @@ public static class Endpoints
|
|||||||
{
|
{
|
||||||
public static readonly string AllCategories = "api/Category/All";
|
public static readonly string AllCategories = "api/Category/All";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Auth
|
||||||
|
{
|
||||||
|
public static readonly string Login = "api/User/Login";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,4 +23,8 @@ public static class Icons
|
|||||||
public readonly static MarkupString Game = new(OpenBraket +
|
public readonly static MarkupString Game = new(OpenBraket +
|
||||||
"<path d=\"M6,7H18A5,5 0 0,1 23,12A5,5 0 0,1 18,17C16.36,17 14.91,16.21 14,15H10C9.09,16.21 7.64,17 6,17A5,5 0 0,1 1,12A5,5 0 0,1 6,7M19.75,9.5A1.25,1.25 0 0,0 18.5,10.75A1.25,1.25 0 0,0 19.75,12A1.25,1.25 0 0,0 21,10.75A1.25,1.25 0 0,0 19.75,9.5M17.25,12A1.25,1.25 0 0,0 16,13.25A1.25,1.25 0 0,0 17.25,14.5A1.25,1.25 0 0,0 18.5,13.25A1.25,1.25 0 0,0 17.25,12M5,9V11H3V13H5V15H7V13H9V11H7V9H5Z\">" +
|
"<path d=\"M6,7H18A5,5 0 0,1 23,12A5,5 0 0,1 18,17C16.36,17 14.91,16.21 14,15H10C9.09,16.21 7.64,17 6,17A5,5 0 0,1 1,12A5,5 0 0,1 6,7M19.75,9.5A1.25,1.25 0 0,0 18.5,10.75A1.25,1.25 0 0,0 19.75,12A1.25,1.25 0 0,0 21,10.75A1.25,1.25 0 0,0 19.75,9.5M17.25,12A1.25,1.25 0 0,0 16,13.25A1.25,1.25 0 0,0 17.25,14.5A1.25,1.25 0 0,0 18.5,13.25A1.25,1.25 0 0,0 17.25,12M5,9V11H3V13H5V15H7V13H9V11H7V9H5Z\">" +
|
||||||
CloseBraket);
|
CloseBraket);
|
||||||
|
|
||||||
|
public readonly static MarkupString Account = new(OpenBraket +
|
||||||
|
"<path d=\"M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z\" />" +
|
||||||
|
CloseBraket);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace GameIdeas.BlazorApp.Shared.Exceptions;
|
||||||
|
|
||||||
|
public class AuthenticationUserException(string message) : Exception(message);
|
||||||
@@ -11,6 +11,7 @@ public class Translations (TranslationService translationService)
|
|||||||
public string EnterUsername => translationService.Translate(nameof(EnterUsername));
|
public string EnterUsername => translationService.Translate(nameof(EnterUsername));
|
||||||
public string EnterPassword => translationService.Translate(nameof(EnterPassword));
|
public string EnterPassword => translationService.Translate(nameof(EnterPassword));
|
||||||
public string UserManager => translationService.Translate(nameof(UserManager));
|
public string UserManager => translationService.Translate(nameof(UserManager));
|
||||||
|
public string CategoriesManager => translationService.Translate(nameof(CategoriesManager));
|
||||||
public string Filters => translationService.Translate(nameof(Filters));
|
public string Filters => translationService.Translate(nameof(Filters));
|
||||||
public string LastAdd => translationService.Translate(nameof(LastAdd));
|
public string LastAdd => translationService.Translate(nameof(LastAdd));
|
||||||
public string Research => translationService.Translate(nameof(Research));
|
public string Research => translationService.Translate(nameof(Research));
|
||||||
@@ -48,6 +49,11 @@ public class Translations (TranslationService translationService)
|
|||||||
public string MinStorageSpaceFormat => translationService.Translate(nameof(MinStorageSpaceFormat));
|
public string MinStorageSpaceFormat => translationService.Translate(nameof(MinStorageSpaceFormat));
|
||||||
public string MaxStorageSpaceFormat => translationService.Translate(nameof(MaxStorageSpaceFormat));
|
public string MaxStorageSpaceFormat => translationService.Translate(nameof(MaxStorageSpaceFormat));
|
||||||
public string MinMaxStorageSpaceFormat => translationService.Translate(nameof(MinMaxStorageSpaceFormat));
|
public string MinMaxStorageSpaceFormat => translationService.Translate(nameof(MinMaxStorageSpaceFormat));
|
||||||
|
public string UserArgumentsNull => translationService.Translate(nameof(UserArgumentsNull));
|
||||||
|
public string InvalidToken => translationService.Translate(nameof(InvalidToken));
|
||||||
|
public string UserUnauthorized => translationService.Translate(nameof(UserUnauthorized));
|
||||||
|
public string UserLoginFailed => translationService.Translate(nameof(UserLoginFailed));
|
||||||
|
public string UserLogoutFailed => translationService.Translate(nameof(UserLogoutFailed));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ResourcesKey
|
public static class ResourcesKey
|
||||||
@@ -67,6 +73,7 @@ public static class ResourcesKey
|
|||||||
public static string EnterUsername => _instance?.EnterUsername ?? throw new InvalidOperationException("ResourcesKey.EnterUsername is not initialized.");
|
public static string EnterUsername => _instance?.EnterUsername ?? throw new InvalidOperationException("ResourcesKey.EnterUsername is not initialized.");
|
||||||
public static string EnterPassword => _instance?.EnterPassword ?? throw new InvalidOperationException("ResourcesKey.EnterPassword is not initialized.");
|
public static string EnterPassword => _instance?.EnterPassword ?? throw new InvalidOperationException("ResourcesKey.EnterPassword is not initialized.");
|
||||||
public static string UserManager => _instance?.UserManager ?? throw new InvalidOperationException("ResourcesKey.UserManager is not initialized.");
|
public static string UserManager => _instance?.UserManager ?? throw new InvalidOperationException("ResourcesKey.UserManager is not initialized.");
|
||||||
|
public static string CategoriesManager => _instance?.CategoriesManager ?? throw new InvalidOperationException("ResourcesKey.CategoriesManager is not initialized.");
|
||||||
public static string Filters => _instance?.Filters ?? throw new InvalidOperationException("ResourcesKey.Filters is not initialized.");
|
public static string Filters => _instance?.Filters ?? throw new InvalidOperationException("ResourcesKey.Filters is not initialized.");
|
||||||
public static string LastAdd => _instance?.LastAdd ?? throw new InvalidOperationException("ResourcesKey.LastAdd is not initialized.");
|
public static string LastAdd => _instance?.LastAdd ?? throw new InvalidOperationException("ResourcesKey.LastAdd is not initialized.");
|
||||||
public static string Research => _instance?.Research ?? throw new InvalidOperationException("ResourcesKey.Research is not initialized.");
|
public static string Research => _instance?.Research ?? throw new InvalidOperationException("ResourcesKey.Research is not initialized.");
|
||||||
@@ -104,4 +111,9 @@ public static class ResourcesKey
|
|||||||
public static string MinStorageSpaceFormat => _instance?.MinStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MinStorageSpaceFormat is not initialized.");
|
public static string MinStorageSpaceFormat => _instance?.MinStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MinStorageSpaceFormat is not initialized.");
|
||||||
public static string MaxStorageSpaceFormat => _instance?.MaxStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MaxStorageSpaceFormat is not initialized.");
|
public static string MaxStorageSpaceFormat => _instance?.MaxStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MaxStorageSpaceFormat is not initialized.");
|
||||||
public static string MinMaxStorageSpaceFormat => _instance?.MinMaxStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MinMaxStorageSpaceFormat is not initialized.");
|
public static string MinMaxStorageSpaceFormat => _instance?.MinMaxStorageSpaceFormat ?? throw new InvalidOperationException("ResourcesKey.MinMaxStorageSpaceFormat is not initialized.");
|
||||||
|
public static string UserArgumentsNull => _instance?.UserArgumentsNull ?? throw new InvalidOperationException("ResourcesKey.UserArgumentsNull is not initialized.");
|
||||||
|
public static string InvalidToken => _instance?.InvalidToken ?? throw new InvalidOperationException("ResourcesKey.InvalidToken is not initialized.");
|
||||||
|
public static string UserUnauthorized => _instance?.UserUnauthorized ?? throw new InvalidOperationException("ResourcesKey.UserUnauthorized is not initialized.");
|
||||||
|
public static string UserLoginFailed => _instance?.UserLoginFailed ?? throw new InvalidOperationException("ResourcesKey.UserLoginFailed is not initialized.");
|
||||||
|
public static string UserLogoutFailed => _instance?.UserLogoutFailed ?? throw new InvalidOperationException("ResourcesKey.UserLogoutFailed is not initialized.");
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
public class GlobalConstants
|
public class GlobalConstants
|
||||||
{
|
{
|
||||||
public static int NUMBER_PER_PAGE = 50;
|
public readonly static Guid ADMINISTRATOR_ID = Guid.Parse("{06CA5CB7-6DE5-4A73-9DDD-8E2D5CCDF104}");
|
||||||
|
public readonly static Guid ADMINISTRATOR_USER_ID = Guid.Parse("{2AB56FCB-0CDE-4DAE-AC9C-FC7635B0D18A}");
|
||||||
|
public readonly static Guid MEMBER_ID = Guid.Parse("{BCE14DEA-1748-4A76-8485-ADEE83DF5EFD}");
|
||||||
|
|
||||||
|
public const string ADMINISTRATOR = "Administrateur";
|
||||||
|
public const string MEMBER = "Membre";
|
||||||
|
public const string ADMIN_MEMBER = $"{ADMINISTRATOR}, {MEMBER}";
|
||||||
|
|
||||||
|
public const int JWT_DURATION_HOUR = 12;
|
||||||
|
|
||||||
|
public const int NUMBER_PER_PAGE = 50;
|
||||||
|
|
||||||
|
public const string LS_AUTH_STORAGE_KEY = "authToken";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6,9 +6,9 @@ public class GameDetailDto
|
|||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
public DateTime? ReleaseDate { get; set; }
|
public DateTime? ReleaseDate { get; set; }
|
||||||
public DateTime? CreationDate { get; set; }
|
public DateTime? CreationDate { get; set; }
|
||||||
public int CreationUserId { get; set; }
|
public string CreationUserId { get; set; } = string.Empty;
|
||||||
public DateTime? ModificationDate { get; set; }
|
public DateTime? ModificationDate { get; set; }
|
||||||
public int? ModificationUserId { get; set; }
|
public string? ModificationUserId { get; set; }
|
||||||
public double? StorageSpace { get; set; }
|
public double? StorageSpace { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public int Interest { get; set; } = 3;
|
public int Interest { get; set; } = 3;
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
using GameIdeas.Shared.Enum;
|
|
||||||
|
|
||||||
namespace GameIdeas.Shared.Dto;
|
|
||||||
|
|
||||||
public class LoginDto
|
|
||||||
{
|
|
||||||
public int? Id { get; set; }
|
|
||||||
public string? Username { get; set; }
|
|
||||||
public string? Password { get; set; }
|
|
||||||
public Role? Role { get; set; }
|
|
||||||
}
|
|
||||||
7
src/GameIdeas/GameIdeas.Shared/Dto/TokenDto.cs
Normal file
7
src/GameIdeas/GameIdeas.Shared/Dto/TokenDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
public class TokenDto
|
||||||
|
{
|
||||||
|
public string? Token { get; set; }
|
||||||
|
public DateTime? Expiration { get; set; }
|
||||||
|
}
|
||||||
@@ -7,5 +7,5 @@ public class UserDto
|
|||||||
public int? Id { get; set; }
|
public int? Id { get; set; }
|
||||||
public string? Username { get; set; }
|
public string? Username { get; set; }
|
||||||
public string? Password { get; set; }
|
public string? Password { get; set; }
|
||||||
public Role? Role { get; set; }
|
public string? RoleId { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace GameIdeas.Shared.Enum;
|
|
||||||
|
|
||||||
public enum Role
|
|
||||||
{
|
|
||||||
Guest = 1,
|
|
||||||
Member = 2,
|
|
||||||
Administrator = 3
|
|
||||||
}
|
|
||||||
@@ -6,4 +6,8 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ public partial class Game
|
|||||||
public string Title { get; set; } = null!;
|
public string Title { get; set; } = null!;
|
||||||
public DateTime? ReleaseDate { get; set; }
|
public DateTime? ReleaseDate { get; set; }
|
||||||
public DateTime CreationDate { get; set; }
|
public DateTime CreationDate { get; set; }
|
||||||
public int CreationUserId { get; set; }
|
public string CreationUserId { get; set; } = null!;
|
||||||
public DateTime? ModificationDate { get; set; }
|
public DateTime? ModificationDate { get; set; }
|
||||||
public int? ModificationUserId { get; set; }
|
public string? ModificationUserId { get; set; }
|
||||||
public double? StorageSpace { get; set; }
|
public double? StorageSpace { get; set; }
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
public int Interest { get; set; }
|
public int Interest { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
namespace GameIdeas.Shared.Model;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
public partial class User
|
namespace GameIdeas.Shared.Model;
|
||||||
|
|
||||||
|
public partial class User : IdentityUser
|
||||||
{
|
{
|
||||||
public User()
|
public User()
|
||||||
{
|
{
|
||||||
@@ -8,11 +10,6 @@ public partial class User
|
|||||||
ModificationGames = new HashSet<Game>();
|
ModificationGames = new HashSet<Game>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Id { get; set; }
|
|
||||||
public string Username { get; set; } = null!;
|
|
||||||
public string Password { get; set; } = null!;
|
|
||||||
public int Role { get; set; }
|
|
||||||
|
|
||||||
public virtual ICollection<Game> CreationGames { get; set; }
|
public virtual ICollection<Game> CreationGames { get; set; }
|
||||||
public virtual ICollection<Game> ModificationGames { get; set; }
|
public virtual ICollection<Game> ModificationGames { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameIdeas.Shared", "GameIde
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{9598BBAF-CC9F-4F43-82B2-40F57296C9F0}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{9598BBAF-CC9F-4F43-82B2-40F57296C9F0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameIdeas.WebAPI.Tests", "Server\GameIdeas.WebAPI.Tests\GameIdeas.WebAPI.Tests.csproj", "{D7B46EB2-590D-4A39-90C6-4D553FC4309A}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -37,6 +39,10 @@ Global
|
|||||||
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Release|Any CPU.Build.0 = Release|Any CPU
|
{9D6D5C6D-AD66-4353-88CC-638887C42477}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D7B46EB2-590D-4A39-90C6-4D553FC4309A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D7B46EB2-590D-4A39-90C6-4D553FC4309A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D7B46EB2-590D-4A39-90C6-4D553FC4309A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D7B46EB2-590D-4A39-90C6-4D553FC4309A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -44,6 +50,7 @@ Global
|
|||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{ABBADA2F-9017-49A2-AEB9-AC2DB7D70831} = {9598BBAF-CC9F-4F43-82B2-40F57296C9F0}
|
{ABBADA2F-9017-49A2-AEB9-AC2DB7D70831} = {9598BBAF-CC9F-4F43-82B2-40F57296C9F0}
|
||||||
{61C3985E-15DF-4127-9D1F-CAE39F0ADD17} = {F59BED34-9473-436A-A91A-23510A4E0E87}
|
{61C3985E-15DF-4127-9D1F-CAE39F0ADD17} = {F59BED34-9473-436A-A91A-23510A4E0E87}
|
||||||
|
{D7B46EB2-590D-4A39-90C6-4D553FC4309A} = {F59BED34-9473-436A-A91A-23510A4E0E87}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {6380DD77-53E4-4F3B-BB45-FAD2263D1511}
|
SolutionGuid = {6380DD77-53E4-4F3B-BB45-FAD2263D1511}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
|
<PackageReference Include="MSTest" Version="3.6.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\GameIdeas.Shared\GameIdeas.Shared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
17
src/GameIdeas/Server/GameIdeas.WebAPI.Tests/IdentityTest.cs
Normal file
17
src/GameIdeas/Server/GameIdeas.WebAPI.Tests/IdentityTest.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using GameIdeas.Shared.Model;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Tests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public sealed class IdentityTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void GetPasswordHash()
|
||||||
|
{
|
||||||
|
var hasher = new PasswordHasher<User>();
|
||||||
|
var hash = hasher.HashPassword(null!, "GameIdeas");
|
||||||
|
Console.WriteLine(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using GameIdeas.Shared.Model;
|
using GameIdeas.Shared.Model;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace GameIdeas.WebAPI.Context;
|
namespace GameIdeas.WebAPI.Context;
|
||||||
|
|
||||||
public class GameIdeasContext : DbContext
|
public class GameIdeasContext : IdentityDbContext<User>
|
||||||
{
|
{
|
||||||
public GameIdeasContext(DbContextOptions<GameIdeasContext> option)
|
public GameIdeasContext(DbContextOptions<GameIdeasContext> option)
|
||||||
: base(option)
|
: base(option)
|
||||||
@@ -12,7 +13,6 @@ public class GameIdeasContext : DbContext
|
|||||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual DbSet<User> Users { get; set; } = null!;
|
|
||||||
public virtual DbSet<Developer> Developers { get; set; } = null!;
|
public virtual DbSet<Developer> Developers { get; set; } = null!;
|
||||||
public virtual DbSet<Platform> Platforms { get; set; } = null!;
|
public virtual DbSet<Platform> Platforms { get; set; } = null!;
|
||||||
public virtual DbSet<Property> Properties { get; set; } = null!;
|
public virtual DbSet<Property> Properties { get; set; } = null!;
|
||||||
@@ -27,28 +27,51 @@ public class GameIdeasContext : DbContext
|
|||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.Entity<User>(entity => {
|
modelBuilder.Entity<Developer>(entity => {
|
||||||
entity.ToTable("User");
|
entity.ToTable("Developer");
|
||||||
|
|
||||||
entity.Property(e => e.Id)
|
entity.HasIndex(e => e.Name)
|
||||||
.UseIdentityByDefaultColumn()
|
.IsUnique();
|
||||||
.HasIdentityOptions(startValue: 100000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Developer>(entity => entity.ToTable("Developer"));
|
modelBuilder.Entity<Platform>(entity => {
|
||||||
|
entity.ToTable("Platform");
|
||||||
|
|
||||||
modelBuilder.Entity<Platform>(entity => entity.ToTable("Platform"));
|
entity.HasIndex(e => e.Label)
|
||||||
|
.IsUnique();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Property>(entity => entity.ToTable("Property"));
|
modelBuilder.Entity<Property>(entity =>
|
||||||
|
{
|
||||||
|
entity.ToTable("Property");
|
||||||
|
|
||||||
|
entity.HasIndex(e => e.Label)
|
||||||
|
.IsUnique();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Publisher>(entity => entity.ToTable("Publisher"));
|
modelBuilder.Entity<Publisher>(entity =>
|
||||||
|
{
|
||||||
|
entity.ToTable("Publisher");
|
||||||
|
|
||||||
modelBuilder.Entity<Tag>(entity => entity.ToTable("Tag"));
|
entity.HasIndex(e => e.Name)
|
||||||
|
.IsUnique();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<Tag>(entity =>
|
||||||
|
{
|
||||||
|
entity.ToTable("Tag");
|
||||||
|
|
||||||
|
entity.HasIndex(e => e.Label)
|
||||||
|
.IsUnique();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<Game>(entity =>
|
modelBuilder.Entity<Game>(entity =>
|
||||||
{
|
{
|
||||||
entity.ToTable("Game");
|
entity.ToTable("Game");
|
||||||
|
|
||||||
|
entity.HasIndex(e => e.Title)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
entity.HasIndex(e => e.CreationUserId);
|
entity.HasIndex(e => e.CreationUserId);
|
||||||
|
|
||||||
entity.HasIndex(e => e.ModificationUserId);
|
entity.HasIndex(e => e.ModificationUserId);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using GameIdeas.Shared.Dto;
|
using GameIdeas.Shared.Constants;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
using GameIdeas.WebAPI.Services.Games;
|
using GameIdeas.WebAPI.Services.Games;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace GameIdeas.WebAPI.Controllers;
|
namespace GameIdeas.WebAPI.Controllers;
|
||||||
@@ -42,6 +44,7 @@ public class GameController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
|
||||||
[HttpPost("Create")]
|
[HttpPost("Create")]
|
||||||
public async Task<ActionResult<int>> CreateGame([FromBody] GameDetailDto game)
|
public async Task<ActionResult<int>> CreateGame([FromBody] GameDetailDto game)
|
||||||
{
|
{
|
||||||
@@ -57,6 +60,7 @@ public class GameController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
|
||||||
[HttpPut("Update")]
|
[HttpPut("Update")]
|
||||||
public async Task<ActionResult<int>> UpdateGame([FromBody] GameDetailDto game)
|
public async Task<ActionResult<int>> UpdateGame([FromBody] GameDetailDto game)
|
||||||
{
|
{
|
||||||
@@ -72,6 +76,7 @@ public class GameController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = GlobalConstants.ADMIN_MEMBER)]
|
||||||
[HttpDelete("Delete/{id:int}")]
|
[HttpDelete("Delete/{id:int}")]
|
||||||
public async Task<ActionResult<bool>> DeleteGame(int id)
|
public async Task<ActionResult<bool>> DeleteGame(int id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using GameIdeas.WebAPI.Exceptions;
|
||||||
|
using GameIdeas.WebAPI.Services.Users;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class UserController(
|
||||||
|
IUserService userService,
|
||||||
|
ILoggerFactory loggerFactory) : Controller
|
||||||
|
{
|
||||||
|
private readonly ILogger<UserController> logger = loggerFactory.CreateLogger<UserController>();
|
||||||
|
|
||||||
|
[HttpPost("Login")]
|
||||||
|
public async Task<ActionResult<TokenDto>> Login([FromBody] UserDto model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await userService.Login(model));
|
||||||
|
}
|
||||||
|
catch (UserInvalidException e)
|
||||||
|
{
|
||||||
|
logger.LogInformation(e, "Missing informations for authentication");
|
||||||
|
return StatusCode(406, e.Message);
|
||||||
|
}
|
||||||
|
catch (UserUnauthorizedException e)
|
||||||
|
{
|
||||||
|
logger.LogWarning(e, "Authentication invalid with there informations");
|
||||||
|
return Unauthorized(e.Message);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "Internal error while search games");
|
||||||
|
return StatusCode(500, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace GameIdeas.WebAPI.Exceptions;
|
||||||
|
|
||||||
|
public class UserInvalidException (string message) : Exception(message);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace GameIdeas.WebAPI.Exceptions;
|
||||||
|
|
||||||
|
public class UserUnauthorizedException(string message) : Exception(message);
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"EnterUsername": "Nom d'utilisateur",
|
"EnterUsername": "Nom d'utilisateur",
|
||||||
"EnterPassword": "Mot de passe",
|
"EnterPassword": "Mot de passe",
|
||||||
"UserManager": "Gestion des utilisateurs",
|
"UserManager": "Gestion des utilisateurs",
|
||||||
|
"CategoriesManager": "Gestion des catégories",
|
||||||
"Filters": "Les filtres",
|
"Filters": "Les filtres",
|
||||||
"LastAdd": "Les ajouts récents",
|
"LastAdd": "Les ajouts récents",
|
||||||
"Research": "Rechercher",
|
"Research": "Rechercher",
|
||||||
@@ -43,5 +44,10 @@
|
|||||||
"ErrorStorageSpaceLabel": "Erreur lors de la génération des label de l'espace de stockage",
|
"ErrorStorageSpaceLabel": "Erreur lors de la génération des label de l'espace de stockage",
|
||||||
"MinStorageSpaceFormat": "Jusqu'à {0}",
|
"MinStorageSpaceFormat": "Jusqu'à {0}",
|
||||||
"MaxStorageSpaceFormat": "Plus de {0}",
|
"MaxStorageSpaceFormat": "Plus de {0}",
|
||||||
"MinMaxStorageSpaceFormat": "{0} à {1}"
|
"MinMaxStorageSpaceFormat": "{0} à {1}",
|
||||||
|
"UserArgumentsNull": "Nom d'utilisateur ou mot de passe invalide",
|
||||||
|
"InvalidToken": "Le token JWT est invalide",
|
||||||
|
"UserUnauthorized": "Utilisateur non authorisé",
|
||||||
|
"UserLoginFailed": "Authentification de l'utilisateur échoué",
|
||||||
|
"UserLogoutFailed": "Déconnection de l'utilisateur échoué"
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>c5ccfd3a-f458-4660-b6c4-81fcc2513737</UserSecretsId>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -12,6 +13,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace GameIdeas.WebAPI.Migrations
|
namespace GameIdeas.WebAPI.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(GameIdeasContext))]
|
[DbContext(typeof(GameIdeasContext))]
|
||||||
[Migration("20250409225125_InitialCreate")]
|
[Migration("20250420153030_InitialCreate")]
|
||||||
partial class InitialCreate
|
partial class InitialCreate
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -39,6 +39,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Developer", (string)null);
|
b.ToTable("Developer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -53,11 +56,12 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.Property<DateTime>("CreationDate")
|
b.Property<DateTime>("CreationDate")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp without time zone")
|
||||||
.HasDefaultValueSql("now()");
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
b.Property<int>("CreationUserId")
|
b.Property<string>("CreationUserId")
|
||||||
.HasColumnType("integer");
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@@ -66,13 +70,13 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<DateTime?>("ModificationDate")
|
b.Property<DateTime?>("ModificationDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
b.Property<int?>("ModificationUserId")
|
b.Property<string>("ModificationUserId")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<DateTime?>("ReleaseDate")
|
b.Property<DateTime?>("ReleaseDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
b.Property<double?>("StorageSpace")
|
b.Property<double?>("StorageSpace")
|
||||||
.HasColumnType("double precision");
|
.HasColumnType("double precision");
|
||||||
@@ -87,6 +91,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ModificationUserId");
|
b.HasIndex("ModificationUserId");
|
||||||
|
|
||||||
|
b.HasIndex("Title")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Game", (string)null);
|
b.ToTable("Game", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -182,6 +189,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Platform", (string)null);
|
b.ToTable("Platform", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -199,6 +209,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Property", (string)null);
|
b.ToTable("Property", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -216,6 +229,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Publisher", (string)null);
|
b.ToTable("Publisher", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -233,32 +249,206 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Tag", (string)null);
|
b.ToTable("Tag", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
NpgsqlPropertyBuilderExtensions.HasIdentityOptions(b.Property<int>("Id"), 100000L, null, null, null, null, null);
|
|
||||||
|
|
||||||
b.Property<string>("Password")
|
b.Property<string>("ClaimType")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<int>("Role")
|
b.Property<string>("ClaimValue")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Username")
|
b.Property<string>("RoleId")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("User", (string)null);
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
||||||
@@ -372,6 +562,57 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
b.Navigation("Tag");
|
b.Navigation("Tag");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("GameDevelopers");
|
b.Navigation("GameDevelopers");
|
||||||
@@ -12,6 +12,45 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetRoles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "text", nullable: false),
|
||||||
|
UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||||
|
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
PasswordHash = table.Column<string>(type: "text", nullable: true),
|
||||||
|
SecurityStamp = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ConcurrencyStamp = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PhoneNumber = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
AccessFailedCount = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Developer",
|
name: "Developer",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -78,19 +117,109 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "User",
|
name: "AspNetRoleClaims",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
Id = table.Column<int>(type: "integer", nullable: false)
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
.Annotation("Npgsql:IdentitySequenceOptions", "'100000', '1', '', '', 'False', '1'")
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Username = table.Column<string>(type: "text", nullable: false),
|
RoleId = table.Column<string>(type: "text", nullable: false),
|
||||||
Password = table.Column<string>(type: "text", nullable: false),
|
ClaimType = table.Column<string>(type: "text", nullable: true),
|
||||||
Role = table.Column<int>(type: "integer", nullable: false)
|
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_User", x => x.Id);
|
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||||
|
column: x => x.RoleId,
|
||||||
|
principalTable: "AspNetRoles",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserClaims",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
UserId = table.Column<string>(type: "text", nullable: false),
|
||||||
|
ClaimType = table.Column<string>(type: "text", nullable: true),
|
||||||
|
ClaimValue = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserLogins",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
||||||
|
ProviderKey = table.Column<string>(type: "text", nullable: false),
|
||||||
|
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
|
||||||
|
UserId = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserRoles",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
UserId = table.Column<string>(type: "text", nullable: false),
|
||||||
|
RoleId = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||||
|
column: x => x.RoleId,
|
||||||
|
principalTable: "AspNetRoles",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AspNetUserTokens",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
UserId = table.Column<string>(type: "text", nullable: false),
|
||||||
|
LoginProvider = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Value = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
@@ -101,11 +230,11 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
.Annotation("Npgsql:IdentitySequenceOptions", "'100000', '1', '', '', 'False', '1'")
|
.Annotation("Npgsql:IdentitySequenceOptions", "'100000', '1', '', '', 'False', '1'")
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Title = table.Column<string>(type: "text", nullable: false),
|
Title = table.Column<string>(type: "text", nullable: false),
|
||||||
ReleaseDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
ReleaseDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||||
CreationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
CreationUserId = table.Column<int>(type: "integer", nullable: false),
|
CreationUserId = table.Column<string>(type: "text", nullable: false),
|
||||||
ModificationDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
ModificationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
|
||||||
ModificationUserId = table.Column<int>(type: "integer", nullable: true),
|
ModificationUserId = table.Column<string>(type: "text", nullable: true),
|
||||||
StorageSpace = table.Column<double>(type: "double precision", nullable: true),
|
StorageSpace = table.Column<double>(type: "double precision", nullable: true),
|
||||||
Description = table.Column<string>(type: "text", nullable: true),
|
Description = table.Column<string>(type: "text", nullable: true),
|
||||||
Interest = table.Column<int>(type: "integer", nullable: false)
|
Interest = table.Column<int>(type: "integer", nullable: false)
|
||||||
@@ -114,14 +243,14 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
{
|
{
|
||||||
table.PrimaryKey("PK_Game", x => x.Id);
|
table.PrimaryKey("PK_Game", x => x.Id);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_Game_User_CreationUserId",
|
name: "FK_Game_AspNetUsers_CreationUserId",
|
||||||
column: x => x.CreationUserId,
|
column: x => x.CreationUserId,
|
||||||
principalTable: "User",
|
principalTable: "AspNetUsers",
|
||||||
principalColumn: "Id");
|
principalColumn: "Id");
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_Game_User_ModificationUserId",
|
name: "FK_Game_AspNetUsers_ModificationUserId",
|
||||||
column: x => x.ModificationUserId,
|
column: x => x.ModificationUserId,
|
||||||
principalTable: "User",
|
principalTable: "AspNetUsers",
|
||||||
principalColumn: "Id");
|
principalColumn: "Id");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -246,6 +375,49 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetRoleClaims_RoleId",
|
||||||
|
table: "AspNetRoleClaims",
|
||||||
|
column: "RoleId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "RoleNameIndex",
|
||||||
|
table: "AspNetRoles",
|
||||||
|
column: "NormalizedName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserClaims_UserId",
|
||||||
|
table: "AspNetUserClaims",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserLogins_UserId",
|
||||||
|
table: "AspNetUserLogins",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AspNetUserRoles_RoleId",
|
||||||
|
table: "AspNetUserRoles",
|
||||||
|
column: "RoleId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "EmailIndex",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
column: "NormalizedEmail");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "UserNameIndex",
|
||||||
|
table: "AspNetUsers",
|
||||||
|
column: "NormalizedUserName",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Developer_Name",
|
||||||
|
table: "Developer",
|
||||||
|
column: "Name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_Game_CreationUserId",
|
name: "IX_Game_CreationUserId",
|
||||||
table: "Game",
|
table: "Game",
|
||||||
@@ -256,6 +428,12 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
table: "Game",
|
table: "Game",
|
||||||
column: "ModificationUserId");
|
column: "ModificationUserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Game_Title",
|
||||||
|
table: "Game",
|
||||||
|
column: "Title",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_GameDeveloper_DeveloperId",
|
name: "IX_GameDeveloper_DeveloperId",
|
||||||
table: "GameDeveloper",
|
table: "GameDeveloper",
|
||||||
@@ -280,11 +458,50 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
name: "IX_GameTag_TagId",
|
name: "IX_GameTag_TagId",
|
||||||
table: "GameTag",
|
table: "GameTag",
|
||||||
column: "TagId");
|
column: "TagId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Platform_Label",
|
||||||
|
table: "Platform",
|
||||||
|
column: "Label",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Property_Label",
|
||||||
|
table: "Property",
|
||||||
|
column: "Label",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Publisher_Name",
|
||||||
|
table: "Publisher",
|
||||||
|
column: "Name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Tag_Label",
|
||||||
|
table: "Tag",
|
||||||
|
column: "Label",
|
||||||
|
unique: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetRoleClaims");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserClaims");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserLogins");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserRoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetUserTokens");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "GameDeveloper");
|
name: "GameDeveloper");
|
||||||
|
|
||||||
@@ -300,6 +517,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "GameTag");
|
name: "GameTag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AspNetRoles");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Developer");
|
name: "Developer");
|
||||||
|
|
||||||
@@ -319,7 +539,7 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
name: "Tag");
|
name: "Tag");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "User");
|
name: "AspNetUsers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
663
src/GameIdeas/Server/GameIdeas.WebAPI/Migrations/20250420160158_SeedDefaultUser.Designer.cs
generated
Normal file
663
src/GameIdeas/Server/GameIdeas.WebAPI/Migrations/20250420160158_SeedDefaultUser.Designer.cs
generated
Normal file
@@ -0,0 +1,663 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using GameIdeas.WebAPI.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 GameIdeas.WebAPI.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(GameIdeasContext))]
|
||||||
|
[Migration("20250420160158_SeedDefaultUser")]
|
||||||
|
partial class SeedDefaultUser
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Developer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
NpgsqlPropertyBuilderExtensions.HasIdentityOptions(b.Property<int>("Id"), 100000L, null, null, null, null, null);
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationDate")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp without time zone")
|
||||||
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
|
b.Property<string>("CreationUserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Interest")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ModificationDate")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<string>("ModificationUserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ReleaseDate")
|
||||||
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
|
b.Property<double?>("StorageSpace")
|
||||||
|
.HasColumnType("double precision");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CreationUserId");
|
||||||
|
|
||||||
|
b.HasIndex("ModificationUserId");
|
||||||
|
|
||||||
|
b.HasIndex("Title")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Game", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameDeveloper", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("DeveloperId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("GameId", "DeveloperId");
|
||||||
|
|
||||||
|
b.HasIndex("DeveloperId");
|
||||||
|
|
||||||
|
b.ToTable("GameDeveloper", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GamePlatform", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PlatformId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("GameId", "PlatformId");
|
||||||
|
|
||||||
|
b.HasIndex("PlatformId");
|
||||||
|
|
||||||
|
b.ToTable("GamePlatform", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameProperty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PropertyId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("GameId", "PropertyId");
|
||||||
|
|
||||||
|
b.HasIndex("PropertyId");
|
||||||
|
|
||||||
|
b.ToTable("GameProperty", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GamePublisher", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PublisherId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("GameId", "PublisherId");
|
||||||
|
|
||||||
|
b.HasIndex("PublisherId");
|
||||||
|
|
||||||
|
b.ToTable("GamePublisher", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameTag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("GameId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("TagId")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("GameId", "TagId");
|
||||||
|
|
||||||
|
b.HasIndex("TagId");
|
||||||
|
|
||||||
|
b.ToTable("GameTag", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Platform", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Label")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Platform", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Property", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Label")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Property", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Publisher", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Publisher", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("Label")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Tag", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", "CreationUser")
|
||||||
|
.WithMany("CreationGames")
|
||||||
|
.HasForeignKey("CreationUserId")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", "ModificationUser")
|
||||||
|
.WithMany("ModificationGames")
|
||||||
|
.HasForeignKey("ModificationUserId");
|
||||||
|
|
||||||
|
b.Navigation("CreationUser");
|
||||||
|
|
||||||
|
b.Navigation("ModificationUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameDeveloper", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Developer", "Developer")
|
||||||
|
.WithMany("GameDevelopers")
|
||||||
|
.HasForeignKey("DeveloperId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Game", "Game")
|
||||||
|
.WithMany("GameDevelopers")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Developer");
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GamePlatform", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Game", "Game")
|
||||||
|
.WithMany("GamePlatforms")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Platform", "Platform")
|
||||||
|
.WithMany("GamePlatforms")
|
||||||
|
.HasForeignKey("PlatformId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
|
||||||
|
b.Navigation("Platform");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameProperty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Game", "Game")
|
||||||
|
.WithMany("GameProperties")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Property", "Property")
|
||||||
|
.WithMany("GameProperties")
|
||||||
|
.HasForeignKey("PropertyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
|
||||||
|
b.Navigation("Property");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GamePublisher", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Game", "Game")
|
||||||
|
.WithMany("GamePublishers")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Publisher", "Publisher")
|
||||||
|
.WithMany("GamePublishers")
|
||||||
|
.HasForeignKey("PublisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
|
||||||
|
b.Navigation("Publisher");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.GameTag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Game", "Game")
|
||||||
|
.WithMany("GameTags")
|
||||||
|
.HasForeignKey("GameId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.Tag", "Tag")
|
||||||
|
.WithMany("GameTags")
|
||||||
|
.HasForeignKey("TagId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Game");
|
||||||
|
|
||||||
|
b.Navigation("Tag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GameDevelopers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GameDevelopers");
|
||||||
|
|
||||||
|
b.Navigation("GamePlatforms");
|
||||||
|
|
||||||
|
b.Navigation("GameProperties");
|
||||||
|
|
||||||
|
b.Navigation("GamePublishers");
|
||||||
|
|
||||||
|
b.Navigation("GameTags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Platform", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GamePlatforms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Property", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GameProperties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Publisher", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GamePublishers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.Tag", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("GameTags");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CreationGames");
|
||||||
|
|
||||||
|
b.Navigation("ModificationGames");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using GameIdeas.Shared.Constants;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class SeedDefaultUser : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
columns: ["Id", "Name", "NormalizedName", "ConcurrencyStamp"],
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{
|
||||||
|
GlobalConstants.ADMINISTRATOR_ID.ToString(),
|
||||||
|
GlobalConstants.ADMINISTRATOR,
|
||||||
|
GlobalConstants.ADMINISTRATOR.Normalize(),
|
||||||
|
Guid.NewGuid().ToString()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GlobalConstants.MEMBER_ID.ToString(),
|
||||||
|
GlobalConstants.MEMBER,
|
||||||
|
GlobalConstants.MEMBER.Normalize(),
|
||||||
|
Guid.NewGuid().ToString()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetUsers",
|
||||||
|
columns:
|
||||||
|
[
|
||||||
|
"Id", "UserName", "NormalizedUserName", "EmailConfirmed", "PhoneNumberConfirmed", "TwoFactorEnabled"
|
||||||
|
, "PasswordHash", "SecurityStamp", "ConcurrencyStamp", "AccessFailedCount", "LockoutEnabled"
|
||||||
|
],
|
||||||
|
values:
|
||||||
|
[
|
||||||
|
GlobalConstants.ADMINISTRATOR_USER_ID.ToString(), "admin", "ADMIN",
|
||||||
|
false, false, false,
|
||||||
|
"AQAAAAIAAYagAAAAEOGx7MFBLpS7awda0ww6jsfXsnhsUjYd4gDK9DaGvQv0X9UZTuHStr5v5+t4Y1S+xg==",
|
||||||
|
Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), 0, false
|
||||||
|
]);
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "AspNetUserRoles",
|
||||||
|
columns: ["UserId", "RoleId"],
|
||||||
|
values: [GlobalConstants.ADMINISTRATOR_USER_ID.ToString(), GlobalConstants.ADMINISTRATOR_ID.ToString()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(@$"DELETE FROM ""AspNetUserRoles"" WHERE ""UserId"" = '{GlobalConstants.ADMINISTRATOR_USER_ID.ToString()}' AND ""RoleId"" = '{GlobalConstants.ADMINISTRATOR_ID.ToString()}'");
|
||||||
|
migrationBuilder.DeleteData("AspNetUsers", "Id", GlobalConstants.ADMINISTRATOR_USER_ID.ToString());
|
||||||
|
migrationBuilder.DeleteData("AspNetRoles", "Id", GlobalConstants.ADMINISTRATOR_ID.ToString());
|
||||||
|
migrationBuilder.DeleteData("AspNetRoles", "Id", GlobalConstants.MEMBER_ID.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Developer", (string)null);
|
b.ToTable("Developer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,11 +53,12 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.Property<DateTime>("CreationDate")
|
b.Property<DateTime>("CreationDate")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("timestamp with time zone")
|
.HasColumnType("timestamp without time zone")
|
||||||
.HasDefaultValueSql("now()");
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
b.Property<int>("CreationUserId")
|
b.Property<string>("CreationUserId")
|
||||||
.HasColumnType("integer");
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
@@ -63,13 +67,13 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<DateTime?>("ModificationDate")
|
b.Property<DateTime?>("ModificationDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
b.Property<int?>("ModificationUserId")
|
b.Property<string>("ModificationUserId")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<DateTime?>("ReleaseDate")
|
b.Property<DateTime?>("ReleaseDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp without time zone");
|
||||||
|
|
||||||
b.Property<double?>("StorageSpace")
|
b.Property<double?>("StorageSpace")
|
||||||
.HasColumnType("double precision");
|
.HasColumnType("double precision");
|
||||||
@@ -84,6 +88,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ModificationUserId");
|
b.HasIndex("ModificationUserId");
|
||||||
|
|
||||||
|
b.HasIndex("Title")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Game", (string)null);
|
b.ToTable("Game", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -179,6 +186,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Platform", (string)null);
|
b.ToTable("Platform", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -196,6 +206,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Property", (string)null);
|
b.ToTable("Property", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -213,6 +226,9 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Publisher", (string)null);
|
b.ToTable("Publisher", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -230,32 +246,206 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Label")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Tag", (string)null);
|
b.ToTable("Tag", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
NpgsqlPropertyBuilderExtensions.HasIdentityOptions(b.Property<int>("Id"), 100000L, null, null, null, null, null);
|
|
||||||
|
|
||||||
b.Property<string>("Password")
|
b.Property<string>("ClaimType")
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<int>("Role")
|
b.Property<string>("ClaimValue")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("Username")
|
b.Property<string>("RoleId")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("User", (string)null);
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.Game", b =>
|
||||||
@@ -369,6 +559,57 @@ namespace GameIdeas.WebAPI.Migrations
|
|||||||
b.Navigation("Tag");
|
b.Navigation("Tag");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("GameIdeas.Shared.Model.User", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
modelBuilder.Entity("GameIdeas.Shared.Model.Developer", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("GameDevelopers");
|
b.Navigation("GameDevelopers");
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using GameIdeas.Shared.Dto;
|
|
||||||
using GameIdeas.Shared.Enum;
|
|
||||||
using GameIdeas.Shared.Model;
|
|
||||||
|
|
||||||
namespace GameIdeas.WebAPI.Profiles;
|
|
||||||
|
|
||||||
public class UserProfile : Profile
|
|
||||||
{
|
|
||||||
public UserProfile()
|
|
||||||
{
|
|
||||||
CreateMap<User, UserDto>()
|
|
||||||
.ForMember(d => d.Id, o => o.MapFrom(s => s.Id))
|
|
||||||
.ForMember(d => d.Username, o => o.MapFrom(s => s.Username))
|
|
||||||
.ForMember(d => d.Password, o => o.MapFrom(s => s.Password))
|
|
||||||
.ForMember(d => d.Role, o => o.MapFrom(s => s.Role))
|
|
||||||
.ReverseMap();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
using GameIdeas.Resources;
|
using GameIdeas.Resources;
|
||||||
|
using GameIdeas.Shared.Model;
|
||||||
using GameIdeas.WebAPI.Context;
|
using GameIdeas.WebAPI.Context;
|
||||||
using GameIdeas.WebAPI.Services.Categories;
|
using GameIdeas.WebAPI.Services.Categories;
|
||||||
using GameIdeas.WebAPI.Services.Games;
|
using GameIdeas.WebAPI.Services.Games;
|
||||||
|
using GameIdeas.WebAPI.Services.Users;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var services = builder.Services;
|
var services = builder.Services;
|
||||||
@@ -27,9 +33,38 @@ Action<DbContextOptionsBuilder> dbContextOptions = options =>
|
|||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
services.AddDbContext<GameIdeasContext>(dbContextOptions);
|
services.AddDbContext<GameIdeasContext>(dbContextOptions);
|
||||||
|
|
||||||
|
services.AddIdentity<User, IdentityRole>()
|
||||||
|
.AddEntityFrameworkStores<GameIdeasContext>()
|
||||||
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
|
var jwtKey = Environment.GetEnvironmentVariable("JWT_KEY")
|
||||||
|
?? throw new ArgumentNullException(message: "Invalid key for JWT token", null);
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = Environment.GetEnvironmentVariable("JWT_ISSUER"),
|
||||||
|
ValidAudience = Environment.GetEnvironmentVariable("JWT_AUDIENCE"),
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddAuthorization();
|
||||||
|
|
||||||
services.AddSingleton<TranslationService>();
|
services.AddSingleton<TranslationService>();
|
||||||
services.AddSingleton<Translations>();
|
services.AddSingleton<Translations>();
|
||||||
|
|
||||||
|
services.AddScoped<IUserService, UserService>();
|
||||||
services.AddScoped<IGameReadService, GameReadService>();
|
services.AddScoped<IGameReadService, GameReadService>();
|
||||||
services.AddScoped<IGameWriteService, GameWriteService>();
|
services.AddScoped<IGameWriteService, GameWriteService>();
|
||||||
services.AddScoped<ICategoryService, CategoryService>();
|
services.AddScoped<ICategoryService, CategoryService>();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Services.Users;
|
||||||
|
|
||||||
|
public interface IUserService
|
||||||
|
{
|
||||||
|
Task<TokenDto> Login(UserDto user);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using GameIdeas.Resources;
|
||||||
|
using GameIdeas.Shared.Constants;
|
||||||
|
using GameIdeas.Shared.Dto;
|
||||||
|
using GameIdeas.Shared.Model;
|
||||||
|
using GameIdeas.WebAPI.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace GameIdeas.WebAPI.Services.Users;
|
||||||
|
|
||||||
|
public class UserService(UserManager<User> userManager) : IUserService
|
||||||
|
{
|
||||||
|
public async Task<TokenDto> Login(UserDto userDto)
|
||||||
|
{
|
||||||
|
if (userDto.Username == null || userDto.Password == null)
|
||||||
|
throw new UserInvalidException(ResourcesKey.UserArgumentsNull);
|
||||||
|
|
||||||
|
var user = await userManager.FindByNameAsync(userDto.Username);
|
||||||
|
|
||||||
|
if (user == null || !await userManager.CheckPasswordAsync(user, userDto.Password))
|
||||||
|
{
|
||||||
|
throw new UserUnauthorizedException(ResourcesKey.UserUnauthorized);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Claim> authClaims =
|
||||||
|
[
|
||||||
|
new Claim(ClaimTypes.Name, user.UserName ?? string.Empty),
|
||||||
|
new Claim(ClaimTypes.Sid, user.Id),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||||
|
];
|
||||||
|
|
||||||
|
authClaims.AddRange((await userManager.GetRolesAsync(user))
|
||||||
|
.Select(r => new Claim(ClaimTypes.Role, r)));
|
||||||
|
|
||||||
|
var jwtKey = Environment.GetEnvironmentVariable("JWT_KEY")
|
||||||
|
?? throw new ArgumentNullException(message: ResourcesKey.InvalidToken, null);
|
||||||
|
|
||||||
|
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey));
|
||||||
|
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: Environment.GetEnvironmentVariable("JWT_ISSUER"),
|
||||||
|
audience: Environment.GetEnvironmentVariable("JWT_AUDIENCE"),
|
||||||
|
expires: DateTime.Now.AddHours(GlobalConstants.JWT_DURATION_HOUR),
|
||||||
|
claims: authClaims,
|
||||||
|
signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new TokenDto
|
||||||
|
{
|
||||||
|
Token = new JwtSecurityTokenHandler().WriteToken(token),
|
||||||
|
Expiration = token.ValidTo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user