fix(admin): fixed various issues lmao idk it was a ballache and is probably quite shit. sorry to future me
This commit is contained in:
parent
56ea7fb7f0
commit
2cbbc00489
29 changed files with 382 additions and 131 deletions
|
|
@ -1,4 +1,5 @@
|
|||
using JellyGlass.Exceptions;
|
||||
using JellyGlass.Models.ControllerBodies.Auth;
|
||||
using JellyGlass.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
|
@ -64,20 +65,20 @@ public class AuthController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateLogin([FromForm] string username, [FromForm] string password)
|
||||
public async Task<IActionResult> CreateLogin([FromBody] CreateLoginDTO login)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var newLogin = await _service.CreateLogin(username, password);
|
||||
var newLogin = await _service.CreateLogin(login.Username, login.Password);
|
||||
|
||||
return Ok(newLogin);
|
||||
}
|
||||
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> UpdateLogin([FromForm] string username, [FromForm] string password, [FromForm] string newPassword)
|
||||
public async Task<IActionResult> UpdateLogin([FromBody] UpdateLoginDTO login)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
|
|
@ -86,7 +87,7 @@ public class AuthController : ControllerBase
|
|||
|
||||
try
|
||||
{
|
||||
await _service.UpdateLoginOwnPassword(username, newPassword, password);
|
||||
await _service.UpdateLoginOwnPassword(GetSessionToken()!, login.NewPassword, login.Password); //TODO: should take in session token
|
||||
}
|
||||
catch (AuthNotFoundException)
|
||||
{
|
||||
|
|
@ -101,7 +102,7 @@ public class AuthController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteLogin([FromForm] string username)
|
||||
public async Task<IActionResult> DeleteLogin([FromBody] DeleteLoginDTO login)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
|
|
@ -110,7 +111,7 @@ public class AuthController : ControllerBase
|
|||
|
||||
try
|
||||
{
|
||||
var deletedLogin = await _service.DeleteLogin(username);
|
||||
var deletedLogin = await _service.DeleteLogin(login.Username);
|
||||
|
||||
return Ok(deletedLogin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public class SearchController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> handleSearch([FromQuery] string searchTerm, string serverId)
|
||||
public async Task<IActionResult> handleSearch([FromQuery] string searchTerm, string serverUrl)
|
||||
{
|
||||
var sessionToken = Request.Cookies["session"];
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ public class SearchController : ControllerBase
|
|||
|
||||
try
|
||||
{
|
||||
var results = await _service.Search(decodedSearchTerm, serverId);
|
||||
var results = await _service.Search(decodedSearchTerm, serverUrl);
|
||||
return Ok(results);
|
||||
}
|
||||
catch (ClientNotFoundException)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
using System.Web;
|
||||
using JellyGlass.Exceptions;
|
||||
using JellyGlass.Models.ControllerBodies.Servers;
|
||||
using JellyGlass.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
|
@ -33,11 +35,17 @@ public class ServersController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetServer([FromQuery] int id)
|
||||
public async Task<IActionResult> GetServer([FromQuery] string url)
|
||||
{
|
||||
if (!await IsAuthenticated())
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var server = await _serverService.GetServerByID(id);
|
||||
var decodedUrl = HttpUtility.UrlDecode(url);
|
||||
var server = await _serverService.GetServerByUrl(decodedUrl);
|
||||
return Ok(server);
|
||||
}
|
||||
catch (ServerNotFoundException)
|
||||
|
|
@ -47,7 +55,7 @@ public class ServersController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> UpdateServer([FromBody] int id, string owner, string url, string apiToken)
|
||||
public async Task<IActionResult> UpdateServer([FromBody] UpdateServerDTO server)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
|
|
@ -56,7 +64,7 @@ public class ServersController : ControllerBase
|
|||
|
||||
try
|
||||
{
|
||||
var updatedServer = await _serverService.UpdateServer(id, owner, url, apiToken);
|
||||
var updatedServer = await _serverService.UpdateServer(server.Owner, server.Url, server.ApiToken);
|
||||
return Ok(updatedServer);
|
||||
}
|
||||
catch (ServerNotFoundException)
|
||||
|
|
@ -66,20 +74,7 @@ public class ServersController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> AddServer([FromBody] string owner, string url, string apiToken)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var newServer = await _serverService.CreateServer(owner, url, apiToken);
|
||||
|
||||
return Ok(newServer);
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteServer([FromBody] int id)
|
||||
public async Task<IActionResult> AddServer([FromBody] AddServerDTO server)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
|
|
@ -88,7 +83,27 @@ public class ServersController : ControllerBase
|
|||
|
||||
try
|
||||
{
|
||||
var deletedServer = await _serverService.DeleteServer(id);
|
||||
var newServer = await _serverService.CreateServer(server.Owner, server.Url, server.ApiToken);
|
||||
return Ok(newServer);
|
||||
}
|
||||
catch (ServerAlreadyExistsException)
|
||||
{
|
||||
return Conflict("A server with this url already exists");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteServer([FromBody] DeleteServerDTO server)
|
||||
{
|
||||
if (!await IsAdminAuthenticated())
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var decodedUrl = HttpUtility.UrlDecode(server.Url);
|
||||
var deletedServer = await _serverService.DeleteServer(decodedUrl);
|
||||
return Ok(deletedServer);
|
||||
}
|
||||
catch (ServerNotFoundException)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ public class AuthServiceException : Exception
|
|||
public AuthServiceException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class LoginFailedException : AuthServiceException
|
||||
{
|
||||
public LoginFailedException() { }
|
||||
|
|
|
|||
|
|
@ -12,4 +12,11 @@ public class ServerNotFoundException : ServerRepositoryException
|
|||
public ServerNotFoundException() { }
|
||||
public ServerNotFoundException(string message) : base(message) { }
|
||||
public ServerNotFoundException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
|
||||
public class ServerAlreadyExistsException : ServerRepositoryException
|
||||
{
|
||||
public ServerAlreadyExistsException() { }
|
||||
public ServerAlreadyExistsException(string message) : base(message) { }
|
||||
public ServerAlreadyExistsException(string message, System.Exception inner) : base(message, inner) { }
|
||||
}
|
||||
87
backend/src/Migrations/20260305184556_changedServerId.Designer.cs
generated
Normal file
87
backend/src/Migrations/20260305184556_changedServerId.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using JellyGlass.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace JellyGlassBackend.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20260305184556_changedServerId")]
|
||||
partial class changedServerId
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.11");
|
||||
|
||||
modelBuilder.Entity("JellyGlass.Models.Server", b =>
|
||||
{
|
||||
b.Property<string>("Url")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApiToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Owner")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Url");
|
||||
|
||||
b.ToTable("Servers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("JellyGlass.Models.UserLogin", b =>
|
||||
{
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HashedPassword")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsAdmin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Username");
|
||||
|
||||
b.ToTable("Logins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("JellyGlass.Models.UserSession", b =>
|
||||
{
|
||||
b.Property<string>("SessionToken")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ExpiresOn")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LoginUsername")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("SessionToken");
|
||||
|
||||
b.HasIndex("LoginUsername");
|
||||
|
||||
b.ToTable("Sessions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("JellyGlass.Models.UserSession", b =>
|
||||
{
|
||||
b.HasOne("JellyGlass.Models.UserLogin", "Login")
|
||||
.WithMany()
|
||||
.HasForeignKey("LoginUsername");
|
||||
|
||||
b.Navigation("Login");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
48
backend/src/Migrations/20260305184556_changedServerId.cs
Normal file
48
backend/src/Migrations/20260305184556_changedServerId.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace JellyGlassBackend.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class changedServerId : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Servers",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Id",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Servers",
|
||||
table: "Servers",
|
||||
column: "Url");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropPrimaryKey(
|
||||
name: "PK_Servers",
|
||||
table: "Servers");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Id",
|
||||
table: "Servers",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0)
|
||||
.Annotation("Sqlite:Autoincrement", true);
|
||||
|
||||
migrationBuilder.AddPrimaryKey(
|
||||
name: "PK_Servers",
|
||||
table: "Servers",
|
||||
column: "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,9 +19,8 @@ namespace JellyGlassBackend.Migrations
|
|||
|
||||
modelBuilder.Entity("JellyGlass.Models.Server", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
b.Property<string>("Url")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ApiToken")
|
||||
.IsRequired()
|
||||
|
|
@ -31,11 +30,7 @@ namespace JellyGlassBackend.Migrations
|
|||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
b.HasKey("Url");
|
||||
|
||||
b.ToTable("Servers");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Auth;
|
||||
|
||||
public class CreateLoginDTO
|
||||
{
|
||||
public required string Username { get; set; }
|
||||
public required string Password { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Auth;
|
||||
|
||||
public class DeleteLoginDTO
|
||||
{
|
||||
public required string Username { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Auth;
|
||||
|
||||
public class UpdateLoginDTO
|
||||
{
|
||||
public required string Password { get; set; }
|
||||
public required string NewPassword { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Servers;
|
||||
|
||||
public class AddServerDTO
|
||||
{
|
||||
public required string Owner { get; set; }
|
||||
public required string Url { get; set; }
|
||||
public required string ApiToken { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Servers;
|
||||
|
||||
public class DeleteServerDTO
|
||||
{
|
||||
public required string Url { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
namespace JellyGlass.Models.ControllerBodies.Servers;
|
||||
|
||||
public class UpdateServerDTO
|
||||
{
|
||||
public required string Owner { get; set; }
|
||||
public required string Url { get; set; }
|
||||
public required string ApiToken { get; set; }
|
||||
}
|
||||
|
|
@ -1,14 +1,11 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace JellyGlass.Models;
|
||||
|
||||
public class Server
|
||||
{
|
||||
public string Owner { get; set; } = string.Empty;
|
||||
public string Url { get; set; } = string.Empty;
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
public string Url { get; set; } = string.Empty;
|
||||
public string ApiToken { get; set; } = string.Empty;
|
||||
}
|
||||
|
|
@ -8,12 +8,10 @@ public class ServerDTO
|
|||
{
|
||||
Owner = s.Owner;
|
||||
Url = s.Url;
|
||||
Id = s.Id;
|
||||
}
|
||||
|
||||
public string Owner { get; set; } = string.Empty;
|
||||
public string Url { get; set; } = string.Empty;
|
||||
public int Id { get; set; }
|
||||
public string JellyfinServerID { get; set; } = string.Empty;
|
||||
public bool Errored { get; set; } = false;
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ namespace JellyGlass.Repositories;
|
|||
public interface IServerRepository
|
||||
{
|
||||
public Task<Server[]> GetServers();
|
||||
public Task<Server> GetServerById(int id);
|
||||
public Task<Server> GetServerByUrl(string url);
|
||||
public Task<Server> CreateServer(string owner, string url, string apiToken);
|
||||
public Task<Server> UpdateServer(int id, string owner, string url, string apiToken);
|
||||
public Task<Server> DeleteServer(int id);
|
||||
public Task<Server> UpdateServer(string owner, string url, string apiToken);
|
||||
public Task<Server> DeleteServer(string url);
|
||||
}
|
||||
|
|
@ -20,9 +20,9 @@ public class ServerRepository : IServerRepository
|
|||
return servers;
|
||||
}
|
||||
|
||||
public async Task<Server> GetServerById(int id)
|
||||
public async Task<Server> GetServerByUrl(string url)
|
||||
{
|
||||
var server = await _context.Servers.FirstOrDefaultAsync(s => s.Id == id);
|
||||
var server = await _context.Servers.FirstOrDefaultAsync(s => s.Url == url);
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
|
|
@ -34,6 +34,10 @@ public class ServerRepository : IServerRepository
|
|||
|
||||
public async Task<Server> CreateServer(string owner, string url, string apiToken)
|
||||
{
|
||||
if (_context.Servers.Where(s => s.Url == url).Any())
|
||||
{
|
||||
throw new ServerAlreadyExistsException();
|
||||
}
|
||||
|
||||
var newServer = new Server()
|
||||
{
|
||||
|
|
@ -48,12 +52,11 @@ public class ServerRepository : IServerRepository
|
|||
return newServer;
|
||||
}
|
||||
|
||||
public async Task<Server> UpdateServer(int id, string owner, string url, string apiToken)
|
||||
public async Task<Server> UpdateServer(string owner, string url, string apiToken)
|
||||
{
|
||||
var server = await GetServerById(id);
|
||||
var server = await GetServerByUrl(url);
|
||||
|
||||
server.Owner = owner;
|
||||
server.Url = url;
|
||||
server.ApiToken = apiToken;
|
||||
|
||||
_context.Servers.Update(server);
|
||||
|
|
@ -62,9 +65,9 @@ public class ServerRepository : IServerRepository
|
|||
return server;
|
||||
}
|
||||
|
||||
public async Task<Server> DeleteServer(int id)
|
||||
public async Task<Server> DeleteServer(string url)
|
||||
{
|
||||
var server = await GetServerById(id);
|
||||
var server = await GetServerByUrl(url);
|
||||
|
||||
_context.Servers.Remove(server);
|
||||
await _context.SaveChangesAsync();
|
||||
|
|
|
|||
|
|
@ -107,16 +107,23 @@ public class AuthService : IAuthService
|
|||
return new UserLoginDTO(newLogin);
|
||||
}
|
||||
|
||||
public async Task UpdateLoginOwnPassword(string username, string newPassword, string oldPassword)
|
||||
public async Task UpdateLoginOwnPassword(string sessionToken, string newPassword, string oldPassword)
|
||||
{
|
||||
var login = await _loginRepo.GetUserLogin(username);
|
||||
var session = await _sessionRepo.GetUserSession(sessionToken);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
throw new LoginFailedException();
|
||||
}
|
||||
|
||||
var login = session.Login;
|
||||
|
||||
if (!BCrypt.Net.BCrypt.Verify(oldPassword, login.HashedPassword))
|
||||
{
|
||||
throw new LoginFailedException();
|
||||
}
|
||||
|
||||
await UpdateLoginPassword(username, newPassword);
|
||||
await UpdateLoginPassword(login.Username, newPassword);
|
||||
}
|
||||
|
||||
public async Task UpdateLoginPassword(string username, string newPassword)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using JellyGlass.Exceptions;
|
||||
using JellyGlass.Models;
|
||||
using JellyGlass.Repositories;
|
||||
|
||||
namespace JellyGlass.Services;
|
||||
|
|
@ -6,7 +7,7 @@ namespace JellyGlass.Services;
|
|||
public class ClientService : IClientService
|
||||
{
|
||||
private IServerRepository _repository;
|
||||
private static JellyfinApiClient[] _clients = [];
|
||||
private static List<JellyfinApiClient> _clients = new List<JellyfinApiClient>();
|
||||
private ILogger<ClientService> _logger;
|
||||
|
||||
public ClientService(IServerRepository repository, ILogger<ClientService> logger)
|
||||
|
|
@ -22,59 +23,70 @@ public class ClientService : IClientService
|
|||
await LoadClients();
|
||||
}
|
||||
|
||||
return _clients;
|
||||
return _clients.ToArray();
|
||||
}
|
||||
|
||||
public async Task<JellyfinApiClient> GetClientForServerId(string serverId)
|
||||
public async Task<JellyfinApiClient> GetClientFromUrl(string url)
|
||||
{
|
||||
if (!_clients.Any())
|
||||
{
|
||||
await LoadClients();
|
||||
}
|
||||
|
||||
foreach (var client in _clients)
|
||||
var client = _clients.FirstOrDefault(c => c.InstanceUrl == url);
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
if (client.ID == serverId)
|
||||
{
|
||||
return client;
|
||||
}
|
||||
throw new Exception($"Could not find client with url {url}");
|
||||
}
|
||||
|
||||
throw new Exception($"Client with ID {serverId} not found");
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task LoadNewClient(Server server)
|
||||
{
|
||||
var client = new JellyfinApiClient(server.Url, server.ApiToken);
|
||||
|
||||
try
|
||||
{
|
||||
await client.GetServerInfo();
|
||||
}
|
||||
catch (JellyfinApiClientException e)
|
||||
{
|
||||
_logger.LogError($"Error authenticating to {server.Url}. Error: {e.Message} Client will not be used");
|
||||
throw;
|
||||
}
|
||||
|
||||
_clients.Add(client);
|
||||
}
|
||||
|
||||
public void UnloadClient(JellyfinApiClient client)
|
||||
{
|
||||
if (_clients.Contains(client))
|
||||
{
|
||||
_clients.Remove(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Haven't loaded Jellyfin api client with ID of {client.ID}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadClients()
|
||||
{
|
||||
var servers = await _repository.GetServers();
|
||||
var clients = new List<JellyfinApiClient>();
|
||||
|
||||
foreach (var server in servers)
|
||||
{
|
||||
var client = new JellyfinApiClient(server.Url, server.ApiToken);
|
||||
|
||||
// try
|
||||
// {
|
||||
// await client.Authenticate();
|
||||
// }
|
||||
// catch (JellyfinApiClientException e)
|
||||
// {
|
||||
// _logger.LogError($"Error authenticating to {server.Url}. Error: {e.Message} Client will not be used");
|
||||
// continue;
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
await client.GetServerInfo(); //test the connection
|
||||
await LoadNewClient(server);
|
||||
}
|
||||
catch (JellyfinApiClientException e)
|
||||
catch (JellyfinApiClientException)
|
||||
{
|
||||
_logger.LogError($"Error authenticating to {server.Url}. Error: {e.Message} Client will not be used");
|
||||
continue;
|
||||
}
|
||||
|
||||
clients.Add(client);
|
||||
}
|
||||
|
||||
_clients = clients.ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ public interface IAuthService
|
|||
public Task<UserLoginDTO[]> GetLogins();
|
||||
public Task<UserLoginDTO> GetLogin(string username);
|
||||
public Task<UserLoginDTO> CreateLogin(string username, string password);
|
||||
public Task UpdateLoginOwnPassword(string username, string newPassword, string oldPassword);
|
||||
public Task UpdateLoginOwnPassword(string sessionToken, string newPassword, string oldPassword);
|
||||
public Task UpdateLoginPassword(string username, string newPassword);
|
||||
public Task<UserLoginDTO> DeleteLogin(string username);
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using JellyGlass.Models;
|
||||
using JellyGlass.Repositories;
|
||||
|
||||
namespace JellyGlass.Services;
|
||||
|
|
@ -5,6 +6,7 @@ namespace JellyGlass.Services;
|
|||
public interface IClientService
|
||||
{
|
||||
public Task<JellyfinApiClient[]> GetClients();
|
||||
// public JellyfinApiClient GetClientForServer(string url);
|
||||
public Task<JellyfinApiClient> GetClientForServerId(string serverId);
|
||||
public Task<JellyfinApiClient> GetClientFromUrl(string url);
|
||||
public Task LoadNewClient(Server server);
|
||||
public void UnloadClient(JellyfinApiClient client);
|
||||
}
|
||||
|
|
@ -5,9 +5,9 @@ namespace JellyGlass.Services;
|
|||
public interface ILibraryService
|
||||
{
|
||||
public Task<Library[]> GetLibraries();
|
||||
public Task<ItemDTO[]> GetItemsFromLibrary(string libraryName, string serverId);
|
||||
public Task<ItemDTO[]> GetItemsFromLibrary(string libraryName, string serverUrl);
|
||||
|
||||
public Task<Library[]> GetLibrariesFromServer(string serverId);
|
||||
public Task<Library[]> GetLibrariesFromServer(string serverUrl);
|
||||
|
||||
|
||||
// public Task<ItemDTO[]> GetChildrenFromItems(ItemDTO[] items);
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ namespace JellyGlass.Services;
|
|||
|
||||
public interface ISearchService
|
||||
{
|
||||
public Task<ItemDTO[]> Search(string searchTerm, string serverId);
|
||||
public Task<ItemDTO[]> Search(string searchTerm, string serverUrl);
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@ namespace JellyGlass.Services;
|
|||
public interface IServerService
|
||||
{
|
||||
public Task<ServerDTO[]> GetServers();
|
||||
public Task<ServerDTO> GetServerByID(int id);
|
||||
public Task<ServerDTO> GetServerByUrl(string url);
|
||||
public Task<ServerDTO> CreateServer(string owner, string url, string apiToken);
|
||||
public Task<ServerDTO> UpdateServer(int id, string owner, string url, string apiToken);
|
||||
public Task<ServerDTO> DeleteServer(int id);
|
||||
public Task<ServerDTO> UpdateServer(string owner, string url, string apiToken);
|
||||
public Task<ServerDTO> DeleteServer(string url);
|
||||
}
|
||||
|
|
@ -44,13 +44,13 @@ public class LibraryService : ILibraryService
|
|||
return libraries.Values.ToArray();
|
||||
}
|
||||
|
||||
public async Task<Item> GetLibrary(string libraryName, string serverId)
|
||||
public async Task<Item> GetLibrary(string libraryName, string serverUrl)
|
||||
{
|
||||
var client = await _clientService.GetClientForServerId(serverId);
|
||||
var client = await _clientService.GetClientFromUrl(serverUrl); ;
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
throw new Exception($"Could not find client with ID of {serverId}");
|
||||
throw new Exception($"Could not find client with url of {serverUrl}");
|
||||
}
|
||||
|
||||
var libraries = await client.GetInstanceLibraries();
|
||||
|
|
@ -66,11 +66,11 @@ public class LibraryService : ILibraryService
|
|||
throw new Exception("Couldn't find library");
|
||||
}
|
||||
|
||||
public async Task<ItemDTO[]> GetItemsFromLibrary(string libraryName, string serverId)
|
||||
public async Task<ItemDTO[]> GetItemsFromLibrary(string libraryName, string serverUrl)
|
||||
{
|
||||
var client = await _clientService.GetClientForServerId(serverId);
|
||||
var client = await _clientService.GetClientFromUrl(serverUrl);
|
||||
|
||||
var library = await GetLibrary(libraryName, serverId);
|
||||
var library = await GetLibrary(libraryName, serverUrl);
|
||||
|
||||
var items = await client.GetItemChildren(library.Id);
|
||||
|
||||
|
|
@ -84,9 +84,9 @@ public class LibraryService : ILibraryService
|
|||
return dtos.ToArray();
|
||||
}
|
||||
|
||||
public async Task<Library[]> GetLibrariesFromServer(string serverId)
|
||||
public async Task<Library[]> GetLibrariesFromServer(string serverUrl)
|
||||
{
|
||||
var client = await _clientService.GetClientForServerId(serverId);
|
||||
var client = await _clientService.GetClientFromUrl(serverUrl);
|
||||
|
||||
var libraries = new Dictionary<string, Library>();
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ public class SearchService : ISearchService
|
|||
_clientService = clientService;
|
||||
}
|
||||
|
||||
public async Task<ItemDTO[]> Search(string searchTerm, string serverId)
|
||||
public async Task<ItemDTO[]> Search(string searchTerm, string serverUrl)
|
||||
{
|
||||
var client = await _clientService.GetClientForServerId(serverId);
|
||||
var client = await _clientService.GetClientFromUrl(serverUrl);
|
||||
|
||||
var items = await client.GetItems(searchTerm: searchTerm);
|
||||
|
||||
|
|
@ -30,25 +30,25 @@ public class SearchService : ISearchService
|
|||
return dtos.ToArray();
|
||||
}
|
||||
|
||||
public async Task<ItemDTO[]> Search2(string searchTerm, string serverId)
|
||||
// public async Task<ItemDTO[]> Search2(string searchTerm, int serverId)
|
||||
// {
|
||||
// var libraries = await _libraryService.GetLibrariesFromServer(serverId);
|
||||
|
||||
// var foundItems = new List<ItemDTO>();
|
||||
|
||||
// foreach (var library in libraries)
|
||||
// {
|
||||
// var found = await SearchLibraryForTerm(searchTerm, serverId, library);
|
||||
|
||||
// foundItems.AddRange(found);
|
||||
// }
|
||||
|
||||
// return foundItems.ToArray();
|
||||
// }
|
||||
|
||||
private async Task<ItemDTO[]> SearchLibraryForTerm(string searchTerm, string serverUrl, Library library)
|
||||
{
|
||||
var libraries = await _libraryService.GetLibrariesFromServer(serverId);
|
||||
|
||||
var foundItems = new List<ItemDTO>();
|
||||
|
||||
foreach (var library in libraries)
|
||||
{
|
||||
var found = await SearchLibraryForTerm(searchTerm, serverId, library);
|
||||
|
||||
foundItems.AddRange(found);
|
||||
}
|
||||
|
||||
return foundItems.ToArray();
|
||||
}
|
||||
|
||||
private async Task<ItemDTO[]> SearchLibraryForTerm(string searchTerm, string serverId, Library library)
|
||||
{
|
||||
var items = await _libraryService.GetItemsFromLibrary(library.Name, serverId);
|
||||
var items = await _libraryService.GetItemsFromLibrary(library.Name, serverUrl);
|
||||
|
||||
var foundItems = new List<ItemDTO>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
|
||||
using JellyGlass.Exceptions;
|
||||
using JellyGlass.Models;
|
||||
using JellyGlass.Repositories;
|
||||
|
||||
|
|
@ -49,31 +50,68 @@ public class ServerService : IServerService
|
|||
return dtos.ToArray();
|
||||
}
|
||||
|
||||
public async Task<ServerDTO> GetServerByID(int id)
|
||||
public async Task<ServerDTO> GetServerByUrl(string url)
|
||||
{
|
||||
var server = await _repository.GetServerById(id);
|
||||
var server = await _repository.GetServerByUrl(url);
|
||||
|
||||
return new ServerDTO(server);
|
||||
return await GetServerDTO(server);
|
||||
}
|
||||
|
||||
public async Task<ServerDTO> CreateServer(string owner, string url, string apiToken)
|
||||
{
|
||||
var newServer = await _repository.CreateServer(owner, url, apiToken);
|
||||
var dto = new ServerDTO(newServer);
|
||||
|
||||
return new ServerDTO(newServer);
|
||||
try
|
||||
{
|
||||
await _service.LoadNewClient(newServer);
|
||||
}
|
||||
catch (JellyfinApiClientException)
|
||||
{
|
||||
dto.Errored = true;
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<ServerDTO> UpdateServer(int id, string owner, string url, string apiToken)
|
||||
public async Task<ServerDTO> UpdateServer(string owner, string url, string apiToken)
|
||||
{
|
||||
var updatedServer = await _repository.UpdateServer(id, owner, url, apiToken);
|
||||
var updatedServer = await _repository.UpdateServer(owner, url, apiToken);
|
||||
|
||||
return new ServerDTO(updatedServer);
|
||||
return await GetServerDTO(updatedServer);
|
||||
}
|
||||
|
||||
public async Task<ServerDTO> DeleteServer(int id)
|
||||
public async Task<ServerDTO> DeleteServer(string url)
|
||||
{
|
||||
var deletedServer = await _repository.DeleteServer(id);
|
||||
var deletedServer = await _repository.DeleteServer(url);
|
||||
|
||||
try
|
||||
{
|
||||
var client = await _service.GetClientFromUrl(deletedServer.Url);
|
||||
_service.UnloadClient(client);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//if it's not loaded, we don't care as we want to unload it anyway
|
||||
}
|
||||
|
||||
return new ServerDTO(deletedServer);
|
||||
}
|
||||
|
||||
private async Task<ServerDTO> GetServerDTO(Server server)
|
||||
{
|
||||
var dto = new ServerDTO(server);
|
||||
|
||||
try
|
||||
{
|
||||
var client = await _service.GetClientFromUrl(server.Url);
|
||||
dto.JellyfinServerID = client.ID;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
dto.Errored = true;
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
|
@ -33,9 +33,9 @@ const ServerSearch = ({ searchTerm, server }: ServerSearchProps) => {
|
|||
searchResults.length > 0 ?
|
||||
searchResults.map(result => {
|
||||
return (
|
||||
<tr>
|
||||
<tr key={result!.id}>
|
||||
<td>
|
||||
<ServerSearchResult key={result!.id} searchResult={result!} server={server} />
|
||||
<ServerSearchResult searchResult={result!} server={server} />
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue