mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 12:14:46 -04:00
Fixing User database gestion
This commit is contained in:
parent
77231f4f41
commit
429af9b252
@ -70,6 +70,8 @@ namespace Kyoo.Authentication
|
|||||||
{
|
{
|
||||||
string publicUrl = _configuration.GetValue<string>("public_url").TrimEnd('/');
|
string publicUrl = _configuration.GetValue<string>("public_url").TrimEnd('/');
|
||||||
|
|
||||||
|
services.AddControllers();
|
||||||
|
|
||||||
// services.AddDbContext<IdentityDatabase>(options =>
|
// services.AddDbContext<IdentityDatabase>(options =>
|
||||||
// {
|
// {
|
||||||
// options.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
|
// options.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
|
||||||
@ -84,6 +86,8 @@ namespace Kyoo.Authentication
|
|||||||
// .AddEntityFrameworkStores<IdentityDatabase>();
|
// .AddEntityFrameworkStores<IdentityDatabase>();
|
||||||
|
|
||||||
services.Configure<PermissionOption>(_configuration.GetSection(PermissionOption.Path));
|
services.Configure<PermissionOption>(_configuration.GetSection(PermissionOption.Path));
|
||||||
|
services.Configure<CertificateOption>(_configuration.GetSection(CertificateOption.Path));
|
||||||
|
services.Configure<AuthenticationOption>(_configuration.GetSection(AuthenticationOption.Path));
|
||||||
CertificateOption certificateOptions = new();
|
CertificateOption certificateOptions = new();
|
||||||
_configuration.GetSection(CertificateOption.Path).Bind(certificateOptions);
|
_configuration.GetSection(CertificateOption.Path).Bind(certificateOptions);
|
||||||
|
|
||||||
|
@ -11,13 +11,13 @@ namespace Kyoo.Authentication.Models.DTO
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The new email address of the user
|
/// The new email address of the user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EmailAddress]
|
[EmailAddress(ErrorMessage = "The email is invalid.")]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The new username of the user.
|
/// The new username of the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MinLength(4)]
|
[MinLength(4, ErrorMessage = "The username must have at least 4 characters")]
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
|
||||||
@ -11,19 +12,19 @@ namespace Kyoo.Authentication.Models.DTO
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user email address
|
/// The user email address
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EmailAddress]
|
[EmailAddress(ErrorMessage = "The email must be a valid email address")]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user's username.
|
/// The user's username.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MinLength(4)]
|
[MinLength(4, ErrorMessage = "The username must have at least {1} characters")]
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user's password.
|
/// The user's password.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MinLength(8)]
|
[MinLength(8, ErrorMessage = "The password must have at least {1} characters")]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +39,8 @@ namespace Kyoo.Authentication.Models.DTO
|
|||||||
Slug = Utility.ToSlug(Username),
|
Slug = Utility.ToSlug(Username),
|
||||||
Username = Username,
|
Username = Username,
|
||||||
Password = Password,
|
Password = Password,
|
||||||
Email = Email
|
Email = Email,
|
||||||
|
ExtraData = new Dictionary<string, string>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ namespace Kyoo.Authentication.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main authentication options.
|
/// The main authentication options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AuthenticationOptions
|
public class AuthenticationOption
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The path to get this option from the root configuration.
|
/// The path to get this option from the root configuration.
|
@ -2,18 +2,20 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IdentityServer4.Extensions;
|
using IdentityServer4.Extensions;
|
||||||
using IdentityServer4.Models;
|
using IdentityServer4.Models;
|
||||||
using IdentityServer4.Services;
|
using IdentityServer4.Services;
|
||||||
|
using Kyoo.Authentication.Models;
|
||||||
using Kyoo.Authentication.Models.DTO;
|
using Kyoo.Authentication.Models.DTO;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using AuthenticationOptions = Kyoo.Authentication.Models.AuthenticationOptions;
|
|
||||||
|
|
||||||
namespace Kyoo.Authentication.Views
|
namespace Kyoo.Authentication.Views
|
||||||
{
|
{
|
||||||
@ -32,7 +34,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The identity server interaction service to login users.
|
/// The identity server interaction service to login users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IIdentityServerInteractionService _interaction;
|
// private readonly IIdentityServerInteractionService _interaction;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A file manager to send profile pictures
|
/// A file manager to send profile pictures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -41,7 +43,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Options about authentication. Those options are monitored and reloads are supported.
|
/// Options about authentication. Those options are monitored and reloads are supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IOptionsMonitor<AuthenticationOptions> _options;
|
private readonly IOptions<AuthenticationOption> _options;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -52,12 +54,12 @@ namespace Kyoo.Authentication.Views
|
|||||||
/// <param name="files">A file manager to send profile pictures</param>
|
/// <param name="files">A file manager to send profile pictures</param>
|
||||||
/// <param name="options">Authentication options (this may be hot reloaded)</param>
|
/// <param name="options">Authentication options (this may be hot reloaded)</param>
|
||||||
public AccountApi(IUserRepository users,
|
public AccountApi(IUserRepository users,
|
||||||
IIdentityServerInteractionService interaction,
|
// IIdentityServerInteractionService interaction,
|
||||||
IFileManager files,
|
IFileManager files,
|
||||||
IOptionsMonitor<AuthenticationOptions> options)
|
IOptions<AuthenticationOption> options)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
_interaction = interaction;
|
// _interaction = interaction;
|
||||||
_files = files;
|
_files = files;
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
@ -69,15 +71,23 @@ namespace Kyoo.Authentication.Views
|
|||||||
/// <param name="request">The DTO register request</param>
|
/// <param name="request">The DTO register request</param>
|
||||||
/// <returns>A OTAC to connect to this new account</returns>
|
/// <returns>A OTAC to connect to this new account</returns>
|
||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
public async Task<ActionResult<string>> Register([FromBody] RegisterRequest request)
|
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
|
||||||
{
|
{
|
||||||
User user = request.ToUser();
|
User user = request.ToUser();
|
||||||
user.Permissions = _options.CurrentValue.Permissions.NewUser;
|
user.Permissions = _options.Value.Permissions.NewUser;
|
||||||
user.Password = PasswordUtils.HashPassword(user.Password);
|
user.Password = PasswordUtils.HashPassword(user.Password);
|
||||||
user.ExtraData["otac"] = PasswordUtils.GenerateOTAC();
|
user.ExtraData["otac"] = PasswordUtils.GenerateOTAC();
|
||||||
user.ExtraData["otac-expire"] = DateTime.Now.AddMinutes(1).ToString("s");
|
user.ExtraData["otac-expire"] = DateTime.Now.AddMinutes(1).ToString("s");
|
||||||
await _users.Create(user);
|
try
|
||||||
return user.ExtraData["otac"];
|
{
|
||||||
|
await _users.Create(user);
|
||||||
|
}
|
||||||
|
catch (DuplicatedItemException)
|
||||||
|
{
|
||||||
|
return Conflict(new {Errors = new {Duplicate = new[] {"A user with this name already exists"}}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(new {Otac = user.ExtraData["otac"]});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -103,10 +113,10 @@ namespace Kyoo.Authentication.Views
|
|||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
public async Task<IActionResult> Login([FromBody] LoginRequest login)
|
public async Task<IActionResult> Login([FromBody] LoginRequest login)
|
||||||
{
|
{
|
||||||
AuthorizationRequest context = await _interaction.GetAuthorizationContextAsync(login.ReturnURL);
|
// AuthorizationRequest context = await _interaction.GetAuthorizationContextAsync(login.ReturnURL);
|
||||||
User user = await _users.Get(x => x.Username == login.Username);
|
User user = await _users.Get(x => x.Username == login.Username);
|
||||||
|
|
||||||
if (context == null || user == null)
|
if (user == null)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
if (!PasswordUtils.CheckPassword(login.Password, user.Password))
|
if (!PasswordUtils.CheckPassword(login.Password, user.Password))
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
@ -122,7 +132,9 @@ namespace Kyoo.Authentication.Views
|
|||||||
[HttpPost("otac-login")]
|
[HttpPost("otac-login")]
|
||||||
public async Task<IActionResult> OtacLogin([FromBody] OtacRequest otac)
|
public async Task<IActionResult> OtacLogin([FromBody] OtacRequest otac)
|
||||||
{
|
{
|
||||||
User user = await _users.Get(x => x.ExtraData["OTAC"] == otac.Otac);
|
// TODO once hstore (Dictionary<string, string> accessor) are supported, use them.
|
||||||
|
// We retrieve all users, this is inefficient.
|
||||||
|
User user = (await _users.GetAll()).FirstOrDefault(x => x.ExtraData.GetValueOrDefault("otac") == otac.Otac);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
if (DateTime.ParseExact(user.ExtraData["otac-expire"], "s", CultureInfo.InvariantCulture) <= DateTime.UtcNow)
|
if (DateTime.ParseExact(user.ExtraData["otac-expire"], "s", CultureInfo.InvariantCulture) <= DateTime.UtcNow)
|
||||||
@ -166,7 +178,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
User user = await _users.GetOrDefault(slug);
|
User user = await _users.GetOrDefault(slug);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = Path.Combine(_options.CurrentValue.ProfilePicturePath, user.ID.ToString());
|
string path = Path.Combine(_options.Value.ProfilePicturePath, user.ID.ToString());
|
||||||
return _files.FileResult(path);
|
return _files.FileResult(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +194,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
user.Username = data.Username;
|
user.Username = data.Username;
|
||||||
if (data.Picture?.Length > 0)
|
if (data.Picture?.Length > 0)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(_options.CurrentValue.ProfilePicturePath, user.ID.ToString());
|
string path = Path.Combine(_options.Value.ProfilePicturePath, user.ID.ToString());
|
||||||
await using Stream file = _files.NewFile(path);
|
await using Stream file = _files.NewFile(path);
|
||||||
await data.Picture.CopyToAsync(file);
|
await data.Picture.CopyToAsync(file);
|
||||||
}
|
}
|
||||||
@ -192,7 +204,7 @@ namespace Kyoo.Authentication.Views
|
|||||||
[HttpGet("permissions")]
|
[HttpGet("permissions")]
|
||||||
public ActionResult<IEnumerable<string>> GetDefaultPermissions()
|
public ActionResult<IEnumerable<string>> GetDefaultPermissions()
|
||||||
{
|
{
|
||||||
return _options.CurrentValue.Permissions.Default;
|
return _options.Value.Permissions.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@ using Kyoo.Models;
|
|||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,7 @@ namespace Kyoo.Postgresql
|
|||||||
services.AddDbContext<DatabaseContext, PostgresContext>(x =>
|
services.AddDbContext<DatabaseContext, PostgresContext>(x =>
|
||||||
{
|
{
|
||||||
x.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
|
x.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
|
||||||
if (_environment.IsDevelopment())
|
if (_configuration.GetValue<bool>("logging:dotnet-ef"))
|
||||||
x.EnableDetailedErrors().EnableSensitiveDataLogging();
|
x.EnableDetailedErrors().EnableSensitiveDataLogging();
|
||||||
});
|
});
|
||||||
// services.AddScoped<DatabaseContext>(_ => new PostgresContext(
|
// services.AddScoped<DatabaseContext>(_ => new PostgresContext(
|
||||||
|
@ -41,11 +41,11 @@ $("#login-btn").on("click", function (e)
|
|||||||
success: function ()
|
success: function ()
|
||||||
{
|
{
|
||||||
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
||||||
|
|
||||||
if (returnUrl == null)
|
if (returnUrl == null)
|
||||||
window.location.href = "/unauthorized";
|
window.location.href = "/unauthorized";
|
||||||
else
|
else
|
||||||
window.location.href = returnUrl;
|
window.location.href = returnUrl;
|
||||||
},
|
},
|
||||||
error: function(xhr)
|
error: function(xhr)
|
||||||
{
|
{
|
||||||
@ -56,7 +56,7 @@ $("#login-btn").on("click", function (e)
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#register-btn").on("click", function (e)
|
$("#register-btn").on("click", function (e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ $("#register-btn").on("click", function (e)
|
|||||||
error.text("Passwords don't match.");
|
error.text("Passwords don't match.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$.ajax(
|
$.ajax(
|
||||||
{
|
{
|
||||||
url: "/api/account/register",
|
url: "/api/account/register",
|
||||||
@ -81,19 +81,19 @@ $("#register-btn").on("click", function (e)
|
|||||||
contentType: 'application/json;charset=UTF-8',
|
contentType: 'application/json;charset=UTF-8',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
data: JSON.stringify(user),
|
data: JSON.stringify(user),
|
||||||
success: function(res)
|
success: function(res)
|
||||||
{
|
{
|
||||||
useOtac(res.otac);
|
useOtac(res.otac);
|
||||||
},
|
},
|
||||||
error: function(xhr)
|
error: function(xhr)
|
||||||
{
|
{
|
||||||
let error = $("#register-error");
|
let error = $("#register-error");
|
||||||
error.show();
|
error.show();
|
||||||
error.text(JSON.parse(xhr.responseText)[0].description);
|
error.html(Object.values(JSON.parse(xhr.responseText).errors).map(x => x[0]).join("<br/>"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function useOtac(otac)
|
function useOtac(otac)
|
||||||
{
|
{
|
||||||
$.ajax(
|
$.ajax(
|
||||||
@ -101,7 +101,7 @@ function useOtac(otac)
|
|||||||
url: "/api/account/otac-login",
|
url: "/api/account/otac-login",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: 'application/json;charset=UTF-8',
|
contentType: 'application/json;charset=UTF-8',
|
||||||
data: JSON.stringify({otac: otac, tayLoggedIn: $("#stay-logged-in")[0].checked}),
|
data: JSON.stringify({otac: otac, stayLoggedIn: $("#stay-logged-in")[0].checked}),
|
||||||
success: function()
|
success: function()
|
||||||
{
|
{
|
||||||
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
let returnUrl = new URLSearchParams(window.location.search).get("ReturnUrl");
|
||||||
@ -124,4 +124,4 @@ function useOtac(otac)
|
|||||||
|
|
||||||
let otac = new URLSearchParams(window.location.search).get("otac");
|
let otac = new URLSearchParams(window.location.search).get("otac");
|
||||||
if (otac != null)
|
if (otac != null)
|
||||||
useOtac(otac);
|
useOtac(otac);
|
||||||
|
@ -41,6 +41,15 @@ namespace Kyoo.Controllers
|
|||||||
.Take(20)
|
.Take(20)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override async Task<User> Create(User obj)
|
||||||
|
{
|
||||||
|
await base.Create(obj);
|
||||||
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
await _database.SaveChangesAsync($"Trying to insert a duplicated user (slug {obj.Slug} already exists).");
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task Delete(User obj)
|
public override async Task Delete(User obj)
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj">
|
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj">
|
||||||
<ExcludeAssets>all</ExcludeAssets>
|
<!-- <ExcludeAssets>all</ExcludeAssets>-->
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Kyoo.Authentication;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Postgresql;
|
using Kyoo.Postgresql;
|
||||||
@ -46,7 +47,7 @@ namespace Kyoo
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
|
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
|
||||||
|
|
||||||
_plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host)});
|
_plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host), new AuthenticationModule(configuration, loggerFactory)});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -126,19 +127,20 @@ namespace Kyoo
|
|||||||
app.UseResponseCompression();
|
app.UseResponseCompression();
|
||||||
|
|
||||||
_plugins.ConfigureAspnet(app);
|
_plugins.ConfigureAspnet(app);
|
||||||
//
|
|
||||||
// app.UseSpa(spa =>
|
|
||||||
// {
|
|
||||||
// spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
|
|
||||||
//
|
|
||||||
// if (env.IsDevelopment())
|
|
||||||
// spa.UseAngularCliServer("start");
|
|
||||||
// });
|
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapControllerRoute("Kyoo", "api/{controller=Home}/{action=Index}/{id?}");
|
endpoints.MapControllerRoute("Kyoo", "api/{controller=Home}/{action=Index}/{id?}");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
app.UseSpa(spa =>
|
||||||
|
{
|
||||||
|
spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
spa.UseAngularCliServer("start");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,12 @@
|
|||||||
"default": "Trace",
|
"default": "Trace",
|
||||||
"Microsoft": "Warning",
|
"Microsoft": "Warning",
|
||||||
"Microsoft.Hosting.Lifetime": "Information",
|
"Microsoft.Hosting.Lifetime": "Information",
|
||||||
|
"Microsoft.EntityFrameworkCore.DbUpdateException": "None",
|
||||||
|
"Microsoft.EntityFrameworkCore.Update": "None",
|
||||||
|
"Microsoft.EntityFrameworkCore.Database.Command": "None",
|
||||||
"Kyoo": "Trace"
|
"Kyoo": "Trace"
|
||||||
}
|
},
|
||||||
|
"dotnet-ef": "false"
|
||||||
},
|
},
|
||||||
|
|
||||||
"authentication": {
|
"authentication": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user