Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 00dcb93257 | |||
| 8abb196e1d | |||
| 12c4f56a22 | |||
| 6d650b7962 | |||
| 73bb417bde | |||
| b0277077f4 | |||
| 3edf6424d0 | |||
| dcb51448aa | |||
| 9d90247bf8 | |||
| 86e54e086a | |||
| fd3ce9f96a | |||
| a89580ac70 | |||
| 8900afdfd2 | |||
| 4b3fa78336 | |||
| 71656aa940 | |||
| 562bc87822 | |||
| ebb15b7cdb | |||
| 270b7d059c | |||
| 23c50de468 | |||
| ececcb5ba3 | |||
| 8658dd34ab | |||
| c17c9cd329 | |||
| 37cfda84b5 | |||
| 3ee17a77a8 | |||
| 522be59973 | |||
| 712a0a9a4a | |||
| 74569d85b6 | |||
| b660f8361f | |||
| d460b5d5d6 | |||
| 4a1c1f1f78 | |||
| 66b5944f92 | |||
| 80628292e2 | |||
| 57f4ec1261 | |||
| c191d7ee7a | |||
| 73bfff3940 | |||
| 38c056cc99 | |||
| 1643f78720 | |||
| 06bb52dfa5 | |||
| ab89d1602f | |||
| 640971dea8 | |||
| 664b0d520b | |||
| 11fe1f29e1 | |||
| 05b5de0939 | |||
| d5944c470b | |||
| 00ef8d0242 | |||
| 77c6ee00ea | |||
| 1bfd0a4931 | |||
| 6c3ce69873 | |||
| a423e6e220 | |||
| f8ec65fd29 | |||
| 665407aac5 | |||
| e5bea187f4 | |||
| fd0f487615 | |||
| d48716a54f | |||
| 2cc13ac9bb | |||
| 467a9d7e0f | |||
| f0551a4801 | |||
| 2cd8c83e28 | |||
| 9797897b76 | |||
| 27cc80d114 | |||
| 27ee3d6ba5 | |||
| 1b6e70ce12 | |||
| 5669cdbdd0 | |||
| 3a6e0f64bc | |||
| aa0a1ab5fe | |||
| b529731c95 | |||
| 64e6f33d7c | |||
| 023298c6f8 | |||
| f8d9c8e4a7 | |||
| 471fa71789 | |||
| edaea68296 | |||
| 8600d9b6bc | |||
| 922e527819 | |||
| 46f0da4a5f | |||
| 16839b9bf8 | |||
| 552d5dcd25 | |||
| cadcf33ed6 | |||
| 4f46f2ed94 | |||
| 560773bfff | |||
| 43623d07c3 | |||
| b93d436c29 |
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"dotnet-ef": {
|
||||||
|
"version": "8.0.7",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-ef"
|
||||||
|
],
|
||||||
|
"rollForward": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: .NET
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v2
|
||||||
|
with:
|
||||||
|
dotnet-version: 8.0.x
|
||||||
|
- name: Restore dependencies
|
||||||
|
run: dotnet restore
|
||||||
|
- name: Build
|
||||||
|
run: dotnet build --no-restore
|
||||||
|
- name: Test
|
||||||
|
run: dotnet test --no-build --verbosity normal
|
||||||
@@ -3,6 +3,24 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
/.vs/Icarus
|
/.vs/Icarus
|
||||||
|
.vscode/*
|
||||||
|
/bin/*
|
||||||
/bin/Debug/netcoreapp2.2
|
/bin/Debug/netcoreapp2.2
|
||||||
/Migrations
|
/Migrations
|
||||||
/obj
|
/obj
|
||||||
|
/obj/*
|
||||||
|
/Icarus.txt
|
||||||
|
/appsettings.json
|
||||||
|
/appsettings.Development.json
|
||||||
|
appsettings.Development.json
|
||||||
|
appsettings.json
|
||||||
|
Icarus/appsettings.Development.json
|
||||||
|
Icarus/appsettings.json
|
||||||
|
Icarus/bin
|
||||||
|
Icarus/obj
|
||||||
|
Models/bin
|
||||||
|
Models/obj
|
||||||
|
Migrations
|
||||||
|
Icarus.txt
|
||||||
|
Storage
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
using Icarus.Authorization;
|
|
||||||
|
|
||||||
namespace Icarus.Authorization.Handlers
|
|
||||||
{
|
|
||||||
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
|
|
||||||
{
|
|
||||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
|
|
||||||
{
|
|
||||||
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scopes = context.User.FindFirst(c =>
|
|
||||||
c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');
|
|
||||||
|
|
||||||
if (scopes.Any(s => s == requirement.Scope))
|
|
||||||
{
|
|
||||||
context.Succeed(requirement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
|
|
||||||
namespace Icarus.Authorization
|
|
||||||
{
|
|
||||||
public class HasScopeRequirement : IAuthorizationRequirement
|
|
||||||
{
|
|
||||||
public string Issuer { get; }
|
|
||||||
public string Scope { get; }
|
|
||||||
|
|
||||||
|
|
||||||
public HasScopeRequirement(string scope, string issuer)
|
|
||||||
{
|
|
||||||
Scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
|
||||||
Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Icarus.Constants
|
|
||||||
{
|
|
||||||
public class DirectoryPaths
|
|
||||||
{
|
|
||||||
public static string CoverArtPath =>
|
|
||||||
Directory.GetCurrentDirectory() + "/Images/Stock/CoverArt.png";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class AlbumManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class ArtistManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
protected static Logger _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
using Icarus.Constants;
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Types;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class CoverArtManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private string _rootCoverArtPath;
|
|
||||||
private byte[] _stockCoverArt = null;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public CoverArtManager(string rootPath)
|
|
||||||
{
|
|
||||||
_rootCoverArtPath = rootPath;
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public void SaveCoverArtToDatabase(ref Song song, ref CoverArt coverArt,
|
|
||||||
CoverArtRepository coverArtRepository)
|
|
||||||
{
|
|
||||||
_logger.Info("Saving cover art record to the database");
|
|
||||||
coverArtRepository.SaveCoverArt(coverArt);
|
|
||||||
|
|
||||||
coverArt = coverArtRepository.GetCoverArt(CoverArtField.SongTitle,
|
|
||||||
coverArt);
|
|
||||||
|
|
||||||
song.CoverArtId = coverArt.CoverArtId;
|
|
||||||
}
|
|
||||||
public void DeleteCoverArtFromDatabase(CoverArt coverArt,
|
|
||||||
CoverArtRepository coverArtRepository)
|
|
||||||
{
|
|
||||||
_logger.Info("Attempting to delete cover art from the database");
|
|
||||||
coverArtRepository.DeleteCoverArt(coverArt);
|
|
||||||
}
|
|
||||||
public void DeleteCoverArt(CoverArt coverArt)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var stockCoverArtPath = _rootCoverArtPath + "CoverArt.png";
|
|
||||||
if (!string.Equals(stockCoverArtPath, coverArt.ImagePath,
|
|
||||||
StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
_logger.Info("Song does not contain the stock cover art");
|
|
||||||
File.Delete(coverArt.ImagePath);
|
|
||||||
_logger.Info("Cover art deleted from the filesystem");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Info("Song contains the stock cover art");
|
|
||||||
_logger.Info("Will not delete from from the filesystem");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CoverArt SaveCoverArt(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dirMgr = new DirectoryManager(_rootCoverArtPath);
|
|
||||||
dirMgr.CreateDirectory(song);
|
|
||||||
var imagePath = dirMgr.SongDirectory + song.Title + ".png";
|
|
||||||
var coverArt = new CoverArt
|
|
||||||
{
|
|
||||||
SongTitle = song.Title,
|
|
||||||
ImagePath = imagePath
|
|
||||||
};
|
|
||||||
|
|
||||||
var metaData = new MetadataRetriever();
|
|
||||||
var imgBytes = metaData.RetrieveCoverArtBytes(song);
|
|
||||||
|
|
||||||
if (imgBytes != null)
|
|
||||||
{
|
|
||||||
_logger.Info("Saving cover art to the filesystem");
|
|
||||||
File.WriteAllBytes(coverArt.ImagePath, imgBytes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Info("Song has no cover art, applying stock cover art");
|
|
||||||
coverArt.ImagePath = _rootCoverArtPath + "CoverArt.png";
|
|
||||||
metaData.UpdateCoverArt(song, coverArt);
|
|
||||||
File.WriteAllBytes(coverArt.ImagePath, _stockCoverArt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return coverArt;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize()
|
|
||||||
{
|
|
||||||
if (System.IO.File.Exists(DirectoryPaths.CoverArtPath))
|
|
||||||
_stockCoverArt = File.ReadAllBytes(DirectoryPaths.CoverArtPath);
|
|
||||||
|
|
||||||
if (!File.Exists(_rootCoverArtPath + "CoverArt.png"))
|
|
||||||
{
|
|
||||||
File.WriteAllBytes(_rootCoverArtPath + "CoverArt.png",
|
|
||||||
_stockCoverArt);
|
|
||||||
Console.WriteLine("Copied Stock Cover Art");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Types;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class DirectoryManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private IConfiguration _config;
|
|
||||||
private Song _song;
|
|
||||||
private string _rootSongDirectory;
|
|
||||||
private string _songDirectory;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public string SongDirectory
|
|
||||||
{
|
|
||||||
get => _songDirectory;
|
|
||||||
set => _songDirectory = value;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public DirectoryManager(IConfiguration config, Song song)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_song = song;
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
public DirectoryManager(IConfiguration config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
public DirectoryManager(string rootDirectory)
|
|
||||||
{
|
|
||||||
_rootSongDirectory = rootDirectory;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public void CreateDirectory()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_songDirectory = AlbumDirectory();
|
|
||||||
|
|
||||||
if (!Directory.Exists(_songDirectory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(_songDirectory);
|
|
||||||
Console.WriteLine("The directory has been created");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine($"The song will be saved in the following" +
|
|
||||||
$" directory: {_songDirectory}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"An error occurred {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void CreateDirectory(Song song)
|
|
||||||
{
|
|
||||||
_song = song;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_songDirectory = AlbumDirectory();
|
|
||||||
|
|
||||||
if (!Directory.Exists(_songDirectory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(_songDirectory);
|
|
||||||
Console.WriteLine($"The directory has been created");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine($"The song will be saved in the following" +
|
|
||||||
$" directory: {_songDirectory}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteEmptyDirectories()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var albumDirectory = AlbumDirectory();
|
|
||||||
var artistDirectory = ArtistDirectory();
|
|
||||||
if (IsDirectoryEmpty(albumDirectory))
|
|
||||||
{
|
|
||||||
Directory.Delete(albumDirectory);
|
|
||||||
Console.WriteLine($"directory {albumDirectory} deleted");
|
|
||||||
}
|
|
||||||
if (IsDirectoryEmpty(artistDirectory))
|
|
||||||
{
|
|
||||||
Directory.Delete(artistDirectory);
|
|
||||||
Console.WriteLine($"directory {artistDirectory} deleted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred {exMsg}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteEmptyDirectories(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var albumDirectory = AlbumDirectory(song);
|
|
||||||
var artistDirectory = ArtistDirectory(song);
|
|
||||||
|
|
||||||
if (IsDirectoryEmpty(albumDirectory))
|
|
||||||
{
|
|
||||||
Directory.Delete(albumDirectory);
|
|
||||||
_logger.Info("Album directory deleted");
|
|
||||||
}
|
|
||||||
if (IsDirectoryEmpty(artistDirectory))
|
|
||||||
{
|
|
||||||
Directory.Delete(artistDirectory);
|
|
||||||
_logger.Info("Artist directory deleted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RetrieveAlbumPath(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving album song path");
|
|
||||||
|
|
||||||
var albumPath = string.Empty;
|
|
||||||
albumPath = AlbumDirectory(song);
|
|
||||||
|
|
||||||
return albumPath;
|
|
||||||
}
|
|
||||||
public string RetrieveArtistPath(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving artist path");
|
|
||||||
|
|
||||||
var artistPath = string.Empty;
|
|
||||||
artistPath = ArtistDirectory(song);
|
|
||||||
|
|
||||||
return artistPath;
|
|
||||||
}
|
|
||||||
public string GenerateSongPath(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Generating song path");
|
|
||||||
|
|
||||||
var songPath = string.Empty;
|
|
||||||
var artistPath = ArtistDirectory(song);
|
|
||||||
var albumPath = AlbumDirectory(song);
|
|
||||||
|
|
||||||
if (!Directory.Exists(artistPath))
|
|
||||||
{
|
|
||||||
_logger.Info("Artist path does not exist");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(artistPath);
|
|
||||||
|
|
||||||
_logger.Info("Creating artist path");
|
|
||||||
}
|
|
||||||
if (!Directory.Exists(albumPath))
|
|
||||||
{
|
|
||||||
_logger.Info("Album path does not exist");
|
|
||||||
|
|
||||||
Directory.CreateDirectory(albumPath);
|
|
||||||
|
|
||||||
_logger.Info("Created album path");
|
|
||||||
}
|
|
||||||
|
|
||||||
songPath = albumPath;
|
|
||||||
|
|
||||||
return songPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Initialize(DirectoryType dirTypes = DirectoryType.Music)
|
|
||||||
{
|
|
||||||
switch (dirTypes)
|
|
||||||
{
|
|
||||||
case DirectoryType.Music:
|
|
||||||
_rootSongDirectory = _config.GetValue<string>("RootMusicPath");
|
|
||||||
break;
|
|
||||||
case DirectoryType.CoverArt:
|
|
||||||
_rootSongDirectory = _config.GetValue<string>("CoverArtPath");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsDirectoryEmpty(string path)
|
|
||||||
{
|
|
||||||
return !Directory.EnumerateFileSystemEntries(path).Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string AlbumDirectory()
|
|
||||||
{
|
|
||||||
string directory = _rootSongDirectory;
|
|
||||||
directory += $@"{_song.Artist}/{_song.AlbumTitle}/";
|
|
||||||
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
private string AlbumDirectory(Song song)
|
|
||||||
{
|
|
||||||
var directory = _rootSongDirectory;
|
|
||||||
directory += $@"{song.Artist}/{song.AlbumTitle}/";
|
|
||||||
Console.WriteLine($"Album directory {directory}");
|
|
||||||
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
private string ArtistDirectory()
|
|
||||||
{
|
|
||||||
var directory = _rootSongDirectory;
|
|
||||||
directory += $@"{_song.Artist}/";
|
|
||||||
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
private string ArtistDirectory(Song song)
|
|
||||||
{
|
|
||||||
var directory = _rootSongDirectory;
|
|
||||||
directory += $@"{song.Artist}/";
|
|
||||||
Console.WriteLine($"Artist directory {directory}");
|
|
||||||
|
|
||||||
return directory;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class GenreManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using RestSharp;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class TokenManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private IConfiguration _config;
|
|
||||||
private string _clientId;
|
|
||||||
private string _clientSecret;
|
|
||||||
private string _audience;
|
|
||||||
private string _grantType;
|
|
||||||
private string _url;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public TokenManager(IConfiguration config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
InitializeValues();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public LoginResult RetrieveLoginResult(User user)
|
|
||||||
{
|
|
||||||
_logger.Info("Preparing Auth0 API request");
|
|
||||||
|
|
||||||
var client = new RestClient(_url);
|
|
||||||
var request = new RestRequest("oauth/token", Method.POST);
|
|
||||||
var tokenRequest = RetrieveTokenRequest();
|
|
||||||
|
|
||||||
_logger.Info("Serializing token object into JSON");
|
|
||||||
var tokenObject = JsonConvert.SerializeObject(tokenRequest);
|
|
||||||
|
|
||||||
request.AddParameter("application/json; charset=utf-8",
|
|
||||||
tokenObject, ParameterType.RequestBody);
|
|
||||||
|
|
||||||
request.RequestFormat = DataFormat.Json;
|
|
||||||
|
|
||||||
_logger.Info("Sending request");
|
|
||||||
IRestResponse response = client.Execute(request);
|
|
||||||
_logger.Info("Response received");
|
|
||||||
|
|
||||||
|
|
||||||
_logger.Info("Deserializing response");
|
|
||||||
var tokenResult = JsonConvert
|
|
||||||
.DeserializeObject<Token>(response.Content);
|
|
||||||
_logger.Info("Response deserialized");
|
|
||||||
|
|
||||||
return new LoginResult
|
|
||||||
{
|
|
||||||
UserId = user.Id, Username = user.Username, Token = tokenResult.AccessToken,
|
|
||||||
TokenType = tokenResult.TokenType, Expiration = tokenResult.Expiration,
|
|
||||||
Message = "Successfully retrieved token"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private TokenRequest RetrieveTokenRequest()
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving token object");
|
|
||||||
|
|
||||||
return new TokenRequest
|
|
||||||
{
|
|
||||||
ClientId = _clientId, ClientSecret = _clientSecret,
|
|
||||||
Audience = _audience, GrantType = _grantType
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeValues()
|
|
||||||
{
|
|
||||||
_logger.Info("Analyzing Auth0 information");
|
|
||||||
|
|
||||||
_clientId = _config["Auth0:ClientId"];
|
|
||||||
_clientSecret = _config["Auth0:ClientSecret"];
|
|
||||||
_audience = _config["Auth0:ApiIdentifier"];
|
|
||||||
_grantType = "client_credentials";
|
|
||||||
_url = $"https://{_config["Auth0:Domain"]}";
|
|
||||||
|
|
||||||
PrintCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Testing Methods
|
|
||||||
// For testing purposes
|
|
||||||
private void PrintCredentials()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Auth0 credentials:");
|
|
||||||
Console.WriteLine($"Client Id: {_clientId}");
|
|
||||||
Console.WriteLine($"Client Secret: {_clientSecret}");
|
|
||||||
Console.WriteLine($"Audience: {_audience}");
|
|
||||||
Console.WriteLine($"Url: {_url}");
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Classes
|
|
||||||
private class TokenRequest
|
|
||||||
{
|
|
||||||
[JsonProperty("client_id")]
|
|
||||||
public string ClientId { get; set; }
|
|
||||||
[JsonProperty("client_secret")]
|
|
||||||
public string ClientSecret { get; set; }
|
|
||||||
[JsonProperty("audience")]
|
|
||||||
public string Audience { get; set; }
|
|
||||||
[JsonProperty("grant_type")]
|
|
||||||
public string GrantType { get; set; }
|
|
||||||
}
|
|
||||||
private class Token
|
|
||||||
{
|
|
||||||
[JsonProperty("access_token")]
|
|
||||||
public string AccessToken { get; set; }
|
|
||||||
[JsonProperty("expires_in")]
|
|
||||||
public int Expiration { get; set; }
|
|
||||||
[JsonProperty("token_type")]
|
|
||||||
public string TokenType { get; set; }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Managers
|
|
||||||
{
|
|
||||||
public class YearManager : BaseManager
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using NLog;
|
|
||||||
using TagLib;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Utilities
|
|
||||||
{
|
|
||||||
public class MetadataRetriever
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private static NLog.Logger _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
|
||||||
private Song _updatedSong;
|
|
||||||
private string _message;
|
|
||||||
private string _title;
|
|
||||||
private string _artist;
|
|
||||||
private string _album;
|
|
||||||
private string _genre;
|
|
||||||
private int _year;
|
|
||||||
private int _duration;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public Song UpdatedSongRecord
|
|
||||||
{
|
|
||||||
get => _updatedSong;
|
|
||||||
set => _updatedSong = value;
|
|
||||||
}
|
|
||||||
public string Message
|
|
||||||
{
|
|
||||||
get => _message;
|
|
||||||
set => _message = value;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public static void PrintMetadata(Song song)
|
|
||||||
{
|
|
||||||
Console.WriteLine("\n\nMetadata of the song:");
|
|
||||||
Console.WriteLine($"Id: {song.Id}");
|
|
||||||
Console.WriteLine($"Title: {song.Title}");
|
|
||||||
Console.WriteLine($"Artist: {song.Artist}");
|
|
||||||
Console.WriteLine($"Album: {song.AlbumTitle}");
|
|
||||||
Console.WriteLine($"Genre: {song.Genre}");
|
|
||||||
Console.WriteLine($"Year: {song.Year}");
|
|
||||||
Console.WriteLine($"Duration: {song.Duration}");
|
|
||||||
Console.WriteLine($"AlbumId: {song.AlbumId}");
|
|
||||||
Console.WriteLine($"ArtistId: {song.ArtistId}");
|
|
||||||
Console.WriteLine($"GenreId: {song.GenreId}");
|
|
||||||
Console.WriteLine($"YearId: {song.YearId}");
|
|
||||||
Console.WriteLine($"Song Path: {song.SongPath}");
|
|
||||||
Console.WriteLine($"Filename: {song.Filename}");
|
|
||||||
Console.WriteLine("\n");
|
|
||||||
|
|
||||||
_logger.Info("Metadata of the song");
|
|
||||||
_logger.Info($"Title: {song.Title}");
|
|
||||||
_logger.Info($"Artist: {song.Artist}");
|
|
||||||
_logger.Info($"Album: {song.AlbumTitle}");
|
|
||||||
_logger.Info($"Genre: {song.Genre}");
|
|
||||||
_logger.Info($"Year: {song.Year}");
|
|
||||||
_logger.Info($"Duration: {song.Duration}");
|
|
||||||
}
|
|
||||||
public Song RetrieveMetaData(string filePath)
|
|
||||||
{
|
|
||||||
Song song = new Song();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
TagLib.File fileTag = TagLib.File.Create(filePath);
|
|
||||||
_title = fileTag.Tag.Title;
|
|
||||||
_artist = string.Join("", fileTag.Tag.Performers);
|
|
||||||
_album = fileTag.Tag.Album;
|
|
||||||
_genre = string.Join("", fileTag.Tag.Genres);
|
|
||||||
_year = (int)fileTag.Tag.Year;
|
|
||||||
_duration = (int)fileTag.Properties.Duration.TotalSeconds;
|
|
||||||
|
|
||||||
song.Title = _title;
|
|
||||||
song.Artist = _artist;
|
|
||||||
song.AlbumTitle = _album;
|
|
||||||
song.Genre = _genre;
|
|
||||||
song.Year = _year;
|
|
||||||
song.Duration = _duration;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine("An error occurred in MetadataRetriever");
|
|
||||||
Console.WriteLine(msg);
|
|
||||||
_logger.Error(msg, "An error occurred in MetadataRetriever");
|
|
||||||
}
|
|
||||||
|
|
||||||
return song;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] RetrieveCoverArtBytes(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine("Fetching image");
|
|
||||||
var tag = TagLib.File.Create(song.SongPath);
|
|
||||||
byte[] imgBytes = tag.Tag.Pictures[0].Data.Data;
|
|
||||||
|
|
||||||
return imgBytes;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred in MetadataRetriever");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateMetadata(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine("Updating song metadata");
|
|
||||||
_logger.Info("Updating song metadata");
|
|
||||||
var filePath = song.SongPath;
|
|
||||||
TagLib.File fileTag = TagLib.File.Create(filePath);
|
|
||||||
fileTag.Tag.Title = song.Title;
|
|
||||||
fileTag.Tag.Genres = new []{song.Genre};
|
|
||||||
fileTag.Save();
|
|
||||||
Console.WriteLine("Song metadata updated");
|
|
||||||
_logger.Info("Song metadata updated");
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred: \n{msg}");
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateMetadata(Song updatedSong, Song oldSong)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
InitializeUpdatedSong(oldSong);
|
|
||||||
var songValues = CheckSongValues(updatedSong);
|
|
||||||
PerformUpdate(updatedSong, songValues);
|
|
||||||
Message = "Successfully updated metadata";
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred: {msg}");
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
Message = "Failed to update metadata";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateCoverArt(Song song, CoverArt coverArt)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Updating song's cover art");
|
|
||||||
|
|
||||||
var tag = TagLib.File.Create(song.SongPath);
|
|
||||||
var pics = tag.Tag.Pictures;
|
|
||||||
Array.Resize(ref pics, 1);
|
|
||||||
|
|
||||||
pics[0] = new Picture(coverArt.ImagePath)
|
|
||||||
{
|
|
||||||
Description = "Cover Art"
|
|
||||||
};
|
|
||||||
|
|
||||||
tag.Tag.Pictures = pics;
|
|
||||||
tag.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PerformUpdate(Song updatedSong, SortedDictionary<string, bool> checkedValues)
|
|
||||||
{
|
|
||||||
var filePath = updatedSong.SongPath;
|
|
||||||
var title = updatedSong.Title;
|
|
||||||
var artist = updatedSong.Artist;
|
|
||||||
var album = updatedSong.AlbumTitle;
|
|
||||||
var genre = updatedSong.Genre;
|
|
||||||
var year = updatedSong.Year;
|
|
||||||
TagLib.File fileTag = TagLib.File.Create(filePath);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Updating metadata of {title}");
|
|
||||||
_logger.Info($"Updating metadata of {title}");
|
|
||||||
|
|
||||||
foreach (var key in checkedValues.Keys)
|
|
||||||
{
|
|
||||||
bool result = checkedValues[key];
|
|
||||||
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
switch (key.ToLower())
|
|
||||||
{
|
|
||||||
case "title":
|
|
||||||
_updatedSong.Title = title;
|
|
||||||
fileTag.Tag.Title = title;
|
|
||||||
break;
|
|
||||||
case "artists":
|
|
||||||
_updatedSong.Artist = artist;
|
|
||||||
fileTag.Tag.Performers = new []{artist};
|
|
||||||
break;
|
|
||||||
case "album":
|
|
||||||
_updatedSong.AlbumTitle = album;
|
|
||||||
fileTag.Tag.Album = album;
|
|
||||||
break;
|
|
||||||
case "genre":
|
|
||||||
_updatedSong.Genre = genre;
|
|
||||||
fileTag.Tag.Genres = new []{genre};
|
|
||||||
break;
|
|
||||||
case "year":
|
|
||||||
_updatedSong.Year = year;
|
|
||||||
fileTag.Tag.Year = (uint)year;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileTag.Save();
|
|
||||||
|
|
||||||
Console.WriteLine("Successfully updated metadata");
|
|
||||||
_logger.Info("Successfully updated metadata");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred:\n{msg}");
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void InitializeUpdatedSong(Song song)
|
|
||||||
{
|
|
||||||
_updatedSong = new Song
|
|
||||||
{
|
|
||||||
Id = song.Id,
|
|
||||||
Title = song.Title,
|
|
||||||
AlbumTitle = song.AlbumTitle,
|
|
||||||
Artist = song.Artist,
|
|
||||||
Genre = song.Genre,
|
|
||||||
Year = song.Year,
|
|
||||||
Duration = song.Duration,
|
|
||||||
Filename = song.Filename,
|
|
||||||
SongPath = song.SongPath
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private void PrintMetadata()
|
|
||||||
{
|
|
||||||
Console.WriteLine("\n\nMetadata of the song:");
|
|
||||||
Console.WriteLine($"Title: {_title}");
|
|
||||||
Console.WriteLine($"Artist: {_artist}");
|
|
||||||
Console.WriteLine($"Album: {_album}");
|
|
||||||
Console.WriteLine($"Genre: {_genre}");
|
|
||||||
Console.WriteLine($"Year: {_year}");
|
|
||||||
Console.WriteLine($"Duration: {_duration}\n\n");
|
|
||||||
|
|
||||||
_logger.Info("Metadata of the song");
|
|
||||||
_logger.Info($"Title: {_title}");
|
|
||||||
_logger.Info($"Artist: {_artist}");
|
|
||||||
_logger.Info($"Album: {_album}");
|
|
||||||
_logger.Info($"Genre: {_genre}");
|
|
||||||
_logger.Info($"Year: {_year}");
|
|
||||||
_logger.Info($"Duration: {_duration}");
|
|
||||||
}
|
|
||||||
private void PrintMetadata(Song song, string message)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"\n\n{message}");
|
|
||||||
Console.WriteLine($"Title: {song.Title}");
|
|
||||||
Console.WriteLine($"Artist: {song.Artist}");
|
|
||||||
Console.WriteLine($"Album: {song.Album}");
|
|
||||||
Console.WriteLine($"Genre: {song.Genre}");
|
|
||||||
Console.WriteLine($"Year: {song.Year}");
|
|
||||||
Console.WriteLine($"Duration: {song.Duration}\n\n");
|
|
||||||
|
|
||||||
_logger.Info(message);
|
|
||||||
_logger.Info($"Title: {_title}");
|
|
||||||
_logger.Info($"Artist: {_artist}");
|
|
||||||
_logger.Info($"Album: {_album}");
|
|
||||||
_logger.Info($"Genre: {_genre}");
|
|
||||||
_logger.Info($"Year: {_year}");
|
|
||||||
_logger.Info($"Duration: {_duration}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private SortedDictionary<string, bool> CheckSongValues(Song song)
|
|
||||||
{
|
|
||||||
var songValues = new SortedDictionary<string, bool>();
|
|
||||||
Console.WriteLine("Checking for null data");
|
|
||||||
_logger.Info("Checking for null data");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
songValues["Title"] = String.IsNullOrEmpty(song.Title);
|
|
||||||
songValues["Artists"] = String.IsNullOrEmpty(song.Artist);
|
|
||||||
songValues["Album"] = String.IsNullOrEmpty(song.AlbumTitle);
|
|
||||||
songValues["Genre"] = String.IsNullOrEmpty(song.Genre);
|
|
||||||
|
|
||||||
if (song.Year == null)
|
|
||||||
songValues["Year"] = true;
|
|
||||||
else if (song.Year==0)
|
|
||||||
songValues["Year"] = true;
|
|
||||||
else
|
|
||||||
songValues["Year"] = false;
|
|
||||||
|
|
||||||
Console.WriteLine("Checking for null data completed");
|
|
||||||
_logger.Info("Checking for null data completed");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred: \n{msg}");
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return songValues;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
using BCrypt.Net;
|
|
||||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Utilities
|
|
||||||
{
|
|
||||||
public class PasswordEncryption
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private static Logger _logger = NLog.LogManager.GetCurrentClassLogger();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public bool VerifyPassword(User user, string password)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = BCrypt.Net.BCrypt.Verify(password, user.Password);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string HashPassword(User user)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string hashedPassword = string.Empty;
|
|
||||||
hashedPassword = BCrypt.Net.BCrypt.HashPassword(user.Password);
|
|
||||||
|
|
||||||
_logger.Info("Successfully hashed password");
|
|
||||||
|
|
||||||
return hashedPassword;
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string GenerateHash(string password, byte[] salt)
|
|
||||||
{
|
|
||||||
|
|
||||||
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
|
||||||
password: password, salt: salt,
|
|
||||||
prf: KeyDerivationPrf.HMACSHA1,
|
|
||||||
iterationCount: 10000,
|
|
||||||
numBytesRequested: 256/8));
|
|
||||||
|
|
||||||
return hashed;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] GenerateSalt()
|
|
||||||
{
|
|
||||||
byte[] salt = new byte[128/8];
|
|
||||||
|
|
||||||
using (var rng = RandomNumberGenerator.Create())
|
|
||||||
rng.GetBytes(salt);
|
|
||||||
|
|
||||||
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
using Ionic.Zip;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.Utilities
|
|
||||||
{
|
|
||||||
public class SongCompression
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
string _compressedSongFilename;
|
|
||||||
string _tempDirectory;
|
|
||||||
byte[] _uncompressedSong;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Propterties
|
|
||||||
public string CompressedSongFilename
|
|
||||||
{
|
|
||||||
get => _compressedSongFilename;
|
|
||||||
set => _compressedSongFilename = value;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public SongCompression()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public SongCompression(string tempDirectory)
|
|
||||||
{
|
|
||||||
_tempDirectory = tempDirectory;
|
|
||||||
}
|
|
||||||
public SongCompression(byte[] uncompressedSong)
|
|
||||||
{
|
|
||||||
_uncompressedSong = uncompressedSong;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public async Task<SongData> RetrieveCompressedSong(Song song)
|
|
||||||
{
|
|
||||||
SongData songData = new SongData();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var archivePath = RetrieveCompressesSongPath(song);
|
|
||||||
Console.WriteLine($"Compressed song saved to: {archivePath}");
|
|
||||||
|
|
||||||
songData.Data = System.IO.File.ReadAllBytes(archivePath);
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error ocurred: \n{exMsg}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return songData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RetrieveCompressesSongPath(Song songDetails)
|
|
||||||
{
|
|
||||||
string tmpZipFilePath = _tempDirectory + songDetails.Filename;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (ZipFile zip = new ZipFile())
|
|
||||||
{
|
|
||||||
zip.AddFile(songDetails.SongPath);
|
|
||||||
zip.Save(tmpZipFilePath);
|
|
||||||
}
|
|
||||||
Console.WriteLine("Successfully compressed");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine("An error ocurred");
|
|
||||||
Console.WriteLine(exMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (songDetails.Filename.Contains(".mp3"))
|
|
||||||
{
|
|
||||||
_compressedSongFilename = StripMP3Extension(songDetails.Filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmpZipFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method not being used
|
|
||||||
public byte[] CompressedSong(byte[] uncompressedSong)
|
|
||||||
{
|
|
||||||
byte[] compressedSong = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Console.WriteLine("Song has been successfully compressed");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine("An error ocurred:");
|
|
||||||
Console.WriteLine(exMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compressedSong;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string StripMP3Extension(string filename)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Before: {filename}");
|
|
||||||
int filenameLength = filename.Length;
|
|
||||||
Console.WriteLine($"Filename length {filenameLength}");
|
|
||||||
var endIndex = filenameLength - 1;
|
|
||||||
var startIndex = endIndex - 3;
|
|
||||||
Console.WriteLine($"Starting index {startIndex} and ending index {endIndex}");
|
|
||||||
var stripped = filename.Remove(startIndex, 4);
|
|
||||||
stripped += ".zip";
|
|
||||||
Console.WriteLine($"After {stripped}");
|
|
||||||
|
|
||||||
return stripped;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/album")]
|
|
||||||
[ApiController]
|
|
||||||
public class AlbumController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<AlbumController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public AlbumController(ILogger<AlbumController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP Routes
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize("read:albums")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
List<Album> albums = new List<Album>();
|
|
||||||
|
|
||||||
AlbumRepository albumStoreContext = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(AlbumRepository)) as AlbumRepository;
|
|
||||||
|
|
||||||
albums = albumStoreContext.GetAlbums();
|
|
||||||
|
|
||||||
if (albums.Count > 0)
|
|
||||||
return Ok(albums);
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("read:albums")]
|
|
||||||
public IActionResult Get(int id)
|
|
||||||
{
|
|
||||||
Album album = new Album
|
|
||||||
{
|
|
||||||
AlbumId = id
|
|
||||||
};
|
|
||||||
|
|
||||||
AlbumRepository albumStoreContext = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(AlbumRepository)) as AlbumRepository;
|
|
||||||
|
|
||||||
if (albumStoreContext.DoesAlbumExist(album))
|
|
||||||
{
|
|
||||||
album = albumStoreContext.GetAlbum(album);
|
|
||||||
|
|
||||||
return Ok(album);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/artist")]
|
|
||||||
[ApiController]
|
|
||||||
public class ArtistController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<ArtistController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public ArtistController(ILogger<ArtistController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP Routes
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize("read:artists")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
ArtistRepository artistStoreContext = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(ArtistRepository)) as ArtistRepository;
|
|
||||||
|
|
||||||
var artists = artistStoreContext.GetArtists();
|
|
||||||
|
|
||||||
if (artists.Count > 0)
|
|
||||||
return Ok(artists);
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("read:artists")]
|
|
||||||
public IActionResult Get(int id)
|
|
||||||
{
|
|
||||||
Artist artist = new Artist
|
|
||||||
{
|
|
||||||
ArtistId = id
|
|
||||||
};
|
|
||||||
|
|
||||||
ArtistRepository artistStoreContext = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(ArtistRepository)) as ArtistRepository;
|
|
||||||
|
|
||||||
if (artistStoreContext.DoesArtistExist(artist))
|
|
||||||
{
|
|
||||||
artist = artistStoreContext.GetArtist(artist);
|
|
||||||
|
|
||||||
return Ok(artist);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/coverart")]
|
|
||||||
[ApiController]
|
|
||||||
public class CoverArtController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<CoverArtController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public CoverArtController(ILogger<CoverArtController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP Routes
|
|
||||||
public async Task<IActionResult> Get()
|
|
||||||
{
|
|
||||||
var coverArtRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(
|
|
||||||
typeof(CoverArtRepository)) as CoverArtRepository;
|
|
||||||
|
|
||||||
var coverArtRecords = coverArtRepository.GetCoverArtRecords();
|
|
||||||
|
|
||||||
if (coverArtRecords == null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No cover art records");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Found cover art records");
|
|
||||||
return Ok(coverArtRecords);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("download:cover_art")]
|
|
||||||
public async Task<IActionResult> Get(int id)
|
|
||||||
{
|
|
||||||
var coverArt = new CoverArt { CoverArtId = id };
|
|
||||||
|
|
||||||
var coverArtRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(
|
|
||||||
typeof(CoverArtRepository)) as CoverArtRepository;
|
|
||||||
|
|
||||||
coverArt = coverArtRepository.GetCoverArt(coverArt);
|
|
||||||
|
|
||||||
if (coverArt != null)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Found cover art record");
|
|
||||||
var coverArtBytes = System.IO.File.ReadAllBytes(
|
|
||||||
coverArt.ImagePath);
|
|
||||||
|
|
||||||
return File(coverArtBytes, "application/x-msdownload",
|
|
||||||
coverArt.SongTitle);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Cover art not found");
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/genre")]
|
|
||||||
[ApiController]
|
|
||||||
public class GenreController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<GenreController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public GenreController(ILogger<GenreController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP Routes
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize("read:genre")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
var genres = new List<Genre>();
|
|
||||||
|
|
||||||
var genreStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(GenreRepository)) as GenreRepository;
|
|
||||||
|
|
||||||
genres = genreStore.GetGenres();
|
|
||||||
|
|
||||||
if (genres.Count > 0)
|
|
||||||
return Ok(genres);
|
|
||||||
else
|
|
||||||
return NotFound(new List<Genre>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("read:genre")]
|
|
||||||
public IActionResult Get(int id)
|
|
||||||
{
|
|
||||||
var genre = new Genre
|
|
||||||
{
|
|
||||||
GenreId = id
|
|
||||||
};
|
|
||||||
|
|
||||||
var genreStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(GenreRepository)) as GenreRepository;
|
|
||||||
|
|
||||||
if (genreStore.DoesGenreExist(genre))
|
|
||||||
{
|
|
||||||
genre = genreStore.GetGenre(genre);
|
|
||||||
|
|
||||||
return Ok(genre);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NotFound(new Genre());
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/login")]
|
|
||||||
[ApiController]
|
|
||||||
public class LoginController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private IConfiguration _config;
|
|
||||||
private ILogger<LoginController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Contructors
|
|
||||||
public LoginController(IConfiguration config, ILogger<LoginController> logger)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP endpoints
|
|
||||||
public IActionResult Post([FromBody] User user)
|
|
||||||
{
|
|
||||||
UserRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(UserRepository)) as UserRepository;
|
|
||||||
|
|
||||||
_logger.LogInformation("Starting process of validating credentials");
|
|
||||||
|
|
||||||
var message = "Invalid credentials";
|
|
||||||
var password = user.Password;
|
|
||||||
|
|
||||||
var loginRes = new LoginResult
|
|
||||||
{
|
|
||||||
Username = user.Username
|
|
||||||
};
|
|
||||||
|
|
||||||
if (context.DoesUserExist(user))
|
|
||||||
{
|
|
||||||
user = context.RetrieveUser(user);
|
|
||||||
|
|
||||||
var validatePass = new PasswordEncryption();
|
|
||||||
var validated = validatePass.VerifyPassword(user, password);
|
|
||||||
if (!validated)
|
|
||||||
{
|
|
||||||
loginRes.Message = message;
|
|
||||||
_logger.LogInformation(message);
|
|
||||||
|
|
||||||
return Ok(loginRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Successfully validated user credentials");
|
|
||||||
|
|
||||||
TokenManager tk = new TokenManager(_config);
|
|
||||||
|
|
||||||
loginRes = tk.RetrieveLoginResult(user);
|
|
||||||
|
|
||||||
return Ok(loginRes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
loginRes.Message = message;
|
|
||||||
|
|
||||||
return NotFound(loginRes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/register")]
|
|
||||||
[ApiController]
|
|
||||||
public class RegisterController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private IConfiguration _config;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public RegisterController(IConfiguration config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public IActionResult Post([FromBody] User user)
|
|
||||||
{
|
|
||||||
PasswordEncryption pe = new PasswordEncryption();
|
|
||||||
user.Password = pe.HashPassword(user);
|
|
||||||
user.EmailVerified = false;
|
|
||||||
|
|
||||||
UserRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(UserRepository)) as UserRepository;
|
|
||||||
|
|
||||||
context.SaveUser(user);
|
|
||||||
|
|
||||||
var registerResult = new RegisterResult
|
|
||||||
{
|
|
||||||
Username = user.Username
|
|
||||||
};
|
|
||||||
|
|
||||||
if (context.DoesUserExist(user))
|
|
||||||
{
|
|
||||||
registerResult.Message = "Successful registration";
|
|
||||||
registerResult.SuccessfullyRegistered = true;
|
|
||||||
|
|
||||||
return Ok(registerResult);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
registerResult.Message = "Registration failed";
|
|
||||||
registerResult.SuccessfullyRegistered = false;
|
|
||||||
|
|
||||||
return Ok(registerResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/song/compressed/data")]
|
|
||||||
[ApiController]
|
|
||||||
public class SongCompressedDataController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private IConfiguration _config;
|
|
||||||
private string _songTempDir;
|
|
||||||
private string _archiveDir;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public SongCompressedDataController(IConfiguration config)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
|
||||||
_archiveDir = _config.GetValue<string>("ArchivePath");
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region API Routes
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("download:songs")]
|
|
||||||
public async Task<IActionResult> Get(int id)
|
|
||||||
{
|
|
||||||
SongRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
SongCompression cmp = new SongCompression(_archiveDir);
|
|
||||||
|
|
||||||
Console.WriteLine($"Archive directory root: {_archiveDir}");
|
|
||||||
|
|
||||||
Console.WriteLine("Starting process of retrieving comrpessed song");
|
|
||||||
SongData song = await cmp.RetrieveCompressedSong(context.GetSong(id));
|
|
||||||
|
|
||||||
return File(song.Data, "application/x-msdownload", cmp.CompressedSongFilename);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Controllers.Utilities;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/song")]
|
|
||||||
[ApiController]
|
|
||||||
public class SongController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<SongController> _logger;
|
|
||||||
private IConfiguration _config;
|
|
||||||
private SongManager _songMgr;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public SongController(IConfiguration config, ILogger<SongController> logger)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_logger = logger;
|
|
||||||
_songMgr = new SongManager(config);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize("read:song_details")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
List<Song> songs = new List<Song>();
|
|
||||||
Console.WriteLine("Attemtping to retrieve songs");
|
|
||||||
_logger.LogInformation("Attempting to retrieve songs");
|
|
||||||
|
|
||||||
SongRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
songs = context.GetAllSongs();
|
|
||||||
|
|
||||||
if (songs.Count > 0)
|
|
||||||
return Ok(songs);
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("read:song_details")]
|
|
||||||
public IActionResult Get(int id)
|
|
||||||
{
|
|
||||||
SongRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
Song song = new Song { Id = id };
|
|
||||||
song = context.GetSong(song);
|
|
||||||
|
|
||||||
Console.WriteLine("Here");
|
|
||||||
|
|
||||||
if (song.Id != 0)
|
|
||||||
return Ok(song);
|
|
||||||
else
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize("update:songs")]
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
public IActionResult Put(int id, [FromBody] Song song)
|
|
||||||
{
|
|
||||||
SongRepository context = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
ArtistRepository artistStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(ArtistRepository)) as ArtistRepository;
|
|
||||||
|
|
||||||
AlbumRepository albumStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(AlbumRepository)) as AlbumRepository;
|
|
||||||
|
|
||||||
GenreRepository genreStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(GenreRepository)) as GenreRepository;
|
|
||||||
|
|
||||||
YearRepository yearStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(YearRepository)) as YearRepository;
|
|
||||||
|
|
||||||
song.Id = id;
|
|
||||||
Console.WriteLine("Retrieving filepath of song");
|
|
||||||
_logger.LogInformation("Retrieving filepath of song");
|
|
||||||
|
|
||||||
if (!context.DoesSongExist(song))
|
|
||||||
return NotFound(new SongResult
|
|
||||||
{
|
|
||||||
Message = "Song does not exist"
|
|
||||||
});
|
|
||||||
|
|
||||||
var songRes = _songMgr.UpdateSong(song, context, albumStore, artistStore, genreStore,
|
|
||||||
yearStore);
|
|
||||||
|
|
||||||
return Ok(songRes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Controllers.Managers;
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Contexts;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/song/data")]
|
|
||||||
[ApiController]
|
|
||||||
public class SongDataController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private SongRepository _songRepository;
|
|
||||||
private AlbumRepository _albumRepository;
|
|
||||||
private ArtistRepository _artistRepository;
|
|
||||||
private GenreRepository _genreRepository;
|
|
||||||
private YearRepository _yearRepository;
|
|
||||||
private CoverArtRepository _coverArtRepository;
|
|
||||||
private IConfiguration _config;
|
|
||||||
private ILogger<SongDataController> _logger;
|
|
||||||
private SongManager _songMgr;
|
|
||||||
private string _songTempDir;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public SongDataController(IConfiguration config, ILogger<SongDataController> logger)
|
|
||||||
{
|
|
||||||
_config = config;
|
|
||||||
_logger = logger;
|
|
||||||
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
|
||||||
_songMgr = new SongManager(config, _songTempDir);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private void Initialize()
|
|
||||||
{
|
|
||||||
_songRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService
|
|
||||||
(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
_albumRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(typeof(AlbumRepository)) as AlbumRepository;
|
|
||||||
|
|
||||||
_artistRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(typeof(ArtistRepository)) as ArtistRepository;
|
|
||||||
|
|
||||||
_genreRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(typeof(GenreRepository)) as GenreRepository;
|
|
||||||
|
|
||||||
_yearRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(typeof(YearRepository)) as YearRepository;
|
|
||||||
|
|
||||||
_coverArtRepository = HttpContext
|
|
||||||
.RequestServices
|
|
||||||
.GetService(typeof(CoverArtRepository)) as CoverArtRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Route("private-scoped")]
|
|
||||||
[Authorize("download:songs")]
|
|
||||||
public async Task<IActionResult> Get(int id)
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
var songMetaData = _songRepository.GetSong(id);
|
|
||||||
|
|
||||||
SongData song = await _songMgr.RetrieveSong(songMetaData);
|
|
||||||
|
|
||||||
return File(song.Data, "application/x-msdownload", songMetaData.Filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
[Authorize("upload:songs")]
|
|
||||||
public async Task Post([FromForm(Name = "file")] List<IFormFile> songData)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
|
|
||||||
Console.WriteLine("Uploading song...");
|
|
||||||
_logger.LogInformation("Uploading song...");
|
|
||||||
|
|
||||||
var uploads = _songTempDir;
|
|
||||||
Console.WriteLine($"Song Root Path {uploads}");
|
|
||||||
_logger.LogInformation($"Song root path {uploads}");
|
|
||||||
foreach (var sng in songData)
|
|
||||||
if (sng.Length > 0) {
|
|
||||||
Console.WriteLine($"Song filename {sng.FileName}");
|
|
||||||
_logger.LogInformation($"Song filename {sng.FileName}");
|
|
||||||
|
|
||||||
await _songMgr.SaveSongToFileSystem(sng, _songRepository,
|
|
||||||
_albumRepository, _artistRepository,
|
|
||||||
_genreRepository, _yearRepository, _coverArtRepository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.LogError(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
[Authorize("delete:songs")]
|
|
||||||
public IActionResult Delete(int id)
|
|
||||||
{
|
|
||||||
Initialize();
|
|
||||||
|
|
||||||
var songMetaData = new Song{ Id = id };
|
|
||||||
Console.WriteLine($"Id {songMetaData.Id}");
|
|
||||||
songMetaData = _songRepository.GetSong(songMetaData);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(songMetaData.Title))
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Song does not exist");
|
|
||||||
return NotFound("Song does not exist");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Starting process of deleting song from the filesystem and database");
|
|
||||||
|
|
||||||
_songMgr.DeleteSong(songMetaData, _songRepository,
|
|
||||||
_albumRepository, _artistRepository,
|
|
||||||
_genreRepository, _yearRepository,
|
|
||||||
_coverArtRepository);
|
|
||||||
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Web;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controllers.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/song/stream")]
|
|
||||||
[ApiController]
|
|
||||||
public class SongStreamController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private ILogger<SongStreamController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public SongStreamController(ILogger<SongStreamController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP endpoints
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("stream:songs")]
|
|
||||||
public async Task<IActionResult> Get(int id)
|
|
||||||
{
|
|
||||||
var songStore= HttpContext.RequestServices
|
|
||||||
.GetService(typeof(SongRepository)) as SongRepository;
|
|
||||||
|
|
||||||
var song = songStore.GetSong(new Song { Id = id });
|
|
||||||
|
|
||||||
var stream = new FileStream(song.SongPath, FileMode.Open, FileAccess.Read);
|
|
||||||
stream.Position = 0;
|
|
||||||
var filename = $"{song.Title}.mp3";
|
|
||||||
|
|
||||||
_logger.LogInformation("Starting to stream song...>");
|
|
||||||
Console.WriteLine("Starting to streamsong...");
|
|
||||||
|
|
||||||
return File(stream, "application/octet-stream", filename);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Database.Repositories;
|
|
||||||
|
|
||||||
namespace Icarus.Controller.V1
|
|
||||||
{
|
|
||||||
[Route("api/v1/year")]
|
|
||||||
[ApiController]
|
|
||||||
public class YearController : ControllerBase
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
private readonly ILogger<YearController> _logger;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public YearController(ILogger<YearController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region HTTP Routes
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize("read:year")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
var yearValues = new List<Year>();
|
|
||||||
|
|
||||||
var yearStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(YearRepository)) as YearRepository;
|
|
||||||
|
|
||||||
yearValues = yearStore.GetSongYears();
|
|
||||||
|
|
||||||
if (yearValues.Count > 0)
|
|
||||||
return Ok(yearValues);
|
|
||||||
else
|
|
||||||
return NotFound(new List<Year>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize("read:year")]
|
|
||||||
public IActionResult Get(int id)
|
|
||||||
{
|
|
||||||
var year = new Year
|
|
||||||
{
|
|
||||||
YearId = id
|
|
||||||
};
|
|
||||||
|
|
||||||
var yearStore = HttpContext.RequestServices
|
|
||||||
.GetService(typeof(YearRepository)) as YearRepository;
|
|
||||||
|
|
||||||
if (yearStore.DoesYearExist(year))
|
|
||||||
{
|
|
||||||
year = yearStore.GetSongYear(year);
|
|
||||||
|
|
||||||
return Ok(year);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NotFound(new Year());
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class AlbumContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<Album> Albums { get; set; }
|
|
||||||
|
|
||||||
public AlbumContext(DbContextOptions<AlbumContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<Album>()
|
|
||||||
.ToTable("Album");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class ArtistContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<Artist> Artists { get; set; }
|
|
||||||
|
|
||||||
public ArtistContext(DbContextOptions<ArtistContext> options) : base (options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<Artist>()
|
|
||||||
.ToTable("Artist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class CoverArtContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<CoverArt> CoverArtImages { get; set; }
|
|
||||||
|
|
||||||
public CoverArtContext(DbContextOptions<CoverArtContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<CoverArt>()
|
|
||||||
.ToTable("CoverArt");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class GenreContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<Genre> Genres { get; set; }
|
|
||||||
public GenreContext(DbContextOptions<GenreContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<Genre>()
|
|
||||||
.ToTable("Genre");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class SongContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<Song> Songs { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public SongContext(DbContextOptions<SongContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.ToTable("Song");
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.Album)
|
|
||||||
.WithMany(al => al.Songs)
|
|
||||||
.HasForeignKey(s => s.AlbumId)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(sa => sa.SongArtist)
|
|
||||||
.WithMany(ar => ar.Songs)
|
|
||||||
.HasForeignKey(s => s.ArtistId)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongGenre)
|
|
||||||
.WithMany(gnr => gnr.Songs)
|
|
||||||
.HasForeignKey(s => s.GenreId)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongYear)
|
|
||||||
.WithMany(yr => yr.Songs)
|
|
||||||
.HasForeignKey(s => s.YearId)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.HasOne(s => s.SongCoverArt)
|
|
||||||
.WithMany(ca => ca.Songs)
|
|
||||||
.HasForeignKey(s => s.CoverArtId)
|
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
|
||||||
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.Year)
|
|
||||||
.IsRequired(false);
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.YearId)
|
|
||||||
.IsRequired(false);
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.GenreId)
|
|
||||||
.IsRequired(false);
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.ArtistId)
|
|
||||||
.IsRequired(false);
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.AlbumId)
|
|
||||||
.IsRequired(false);
|
|
||||||
modelBuilder.Entity<Song>()
|
|
||||||
.Property(s => s.CoverArtId)
|
|
||||||
.IsRequired(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class UserContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<User> Users { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public UserContext(DbContextOptions<UserContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<User>()
|
|
||||||
.ToTable("User");
|
|
||||||
modelBuilder.Entity<User>()
|
|
||||||
.Property(u => u.LastLogin).IsRequired(false);
|
|
||||||
modelBuilder.Entity<User>()
|
|
||||||
.Property(u => u.DateCreated).HasDefaultValue(DateTime.Now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MySql.Data;
|
|
||||||
using MySql.Data.EntityFrameworkCore.Extensions;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Contexts
|
|
||||||
{
|
|
||||||
public class YearContext : DbContext
|
|
||||||
{
|
|
||||||
public DbSet<Year> YearValues { get; set; }
|
|
||||||
|
|
||||||
public YearContext(DbContextOptions<YearContext> options) : base(options) { }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
modelBuilder.Entity<Year>()
|
|
||||||
.ToTable("Year");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,385 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class AlbumRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public AlbumRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public List<Album> GetAlbumWithoutCount()
|
|
||||||
{
|
|
||||||
var albums = new List<Album>();
|
|
||||||
|
|
||||||
if (AnyAlbums())
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM Album";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
albums = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return albums;
|
|
||||||
}
|
|
||||||
public List<Album> GetAlbums()
|
|
||||||
{
|
|
||||||
List<Album> albums = new List<Album>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT alb.*,COUNT(*) AS SongCount FROM Album alb " +
|
|
||||||
"LEFT JOIN Song sng ON alb.AlbumId=sng.AlbumId WHERE " +
|
|
||||||
"alb.AlbumId=sng.AlbumId GROUP BY alb.AlbumId";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
albums = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return albums;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Album GetAlbum(Album album)
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb " +
|
|
||||||
"LEFT JOIN Song sng ON alb.AlbumId=sng.AlbumId WHERE "+
|
|
||||||
"alb.AlbumId=@AlbumId LIMIT 1";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", album.AlbumId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
album = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return album;
|
|
||||||
}
|
|
||||||
public Album GetAlbum(Song song)
|
|
||||||
{
|
|
||||||
var album = new Album();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT alb.*, 0 AS SongCount FROM Album alb " +
|
|
||||||
"WHERE alb.Title=@Title LIMIT 1";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Album title {song.AlbumTitle}");
|
|
||||||
cmd.Parameters.AddWithValue("@Title", song.AlbumTitle);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
album = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return album;
|
|
||||||
}
|
|
||||||
public Album GetAlbum(Song song, bool retrieveCount)
|
|
||||||
{
|
|
||||||
var album = new Album();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = string.Empty;
|
|
||||||
if (retrieveCount)
|
|
||||||
query = "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb " +
|
|
||||||
"LEFT JOIN Song sng ON alb.AlbumId=sng.AlbumId WHERE " +
|
|
||||||
"alb.Title=@Title GROUP BY alb.AlbumId LIMIT 1";
|
|
||||||
else
|
|
||||||
query = "SELECT alb.*, 0 AS SongCount FROM Album alb WHERE " +
|
|
||||||
"alb.Title=@Title LIMIT 1";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", song.AlbumTitle);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
album = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return album;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesAlbumExist(Album album)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT alb.*, 0 AS SongCount FROM Album alb WHERE alb.AlbumId=@AlbumId";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", album.AlbumId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
album = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (album.Title != null)
|
|
||||||
{
|
|
||||||
_logger.Info($"Album {album.Title} exists");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public bool DoesAlbumExist(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT alb.*, 0 AS SongCount FROM Album alb WHERE alb.Title=@Title";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", song.AlbumTitle);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
var album = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(album.Title))
|
|
||||||
{
|
|
||||||
_logger.Info($"Album {album.Title} exists");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveAlbum(Album album)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "INSERT INTO Album(Title, AlbumArtist)" +
|
|
||||||
" VALUES (@Title, @AlbumArtist)";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", album.Title);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumArtist", album.AlbumArtist);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateAlbum(Album album)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "UPDATE Album SET Title=@Title, AlbumArtist=" +
|
|
||||||
"@AlbumArtist WHERE AlbumId=@AlbumId";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", album.Title);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumArtist", album.AlbumArtist);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", album.AlbumId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteAlbum(Album album)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "DELETE FROM Album WHERE AlbumId=@AlbumId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", album.AlbumId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Album> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
List<Album> albums = new List<Album>();
|
|
||||||
_logger.Info("Retrieving album records");
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["AlbumId"]);
|
|
||||||
var title = reader["Title"].ToString();
|
|
||||||
var albumArtist = reader["AlbumArtist"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"]);
|
|
||||||
albums.Add(new Album
|
|
||||||
{
|
|
||||||
AlbumId = id,
|
|
||||||
Title = title,
|
|
||||||
AlbumArtist = albumArtist,
|
|
||||||
SongCount = songCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Album records retrieved");
|
|
||||||
|
|
||||||
return albums;
|
|
||||||
}
|
|
||||||
private Album ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
Album album = new Album();
|
|
||||||
_logger.Info("Retrieving single album record");
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["AlbumId"]);
|
|
||||||
var title = reader["Title"].ToString();
|
|
||||||
var albumArtist = reader["AlbumArtist"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"]);
|
|
||||||
album = new Album
|
|
||||||
{
|
|
||||||
AlbumId = id,
|
|
||||||
Title = title,
|
|
||||||
AlbumArtist = albumArtist,
|
|
||||||
SongCount = songCount
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_logger.Info("Single ablum retreived");
|
|
||||||
|
|
||||||
return album;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AnyAlbums()
|
|
||||||
{
|
|
||||||
var albums = new List<Album>();
|
|
||||||
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT * FROM Album";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
albums = ParseData(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (albums.Count > 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,355 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
//using NLog;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class ArtistRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public ArtistRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public List<Artist> GetArtists()
|
|
||||||
{
|
|
||||||
List<Artist> artists = new List<Artist>();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT art.*, COUNT(*) AS SongCount FROM Artist " +
|
|
||||||
"art LEFT JOIN Song sng ON art.ArtistId=sng.ArtistId " +
|
|
||||||
"GROUP BY art.ArtistId";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
artists = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return artists;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Artist GetArtist(Artist artist)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving artist record from the database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT art.*, COUNT(*) AS SongCount FROM Artist " +
|
|
||||||
"art LEFT JOIN Song sng ON art.ArtistId=sng.ArtistId " +
|
|
||||||
"WHERE art.ArtistId=@ArtistId";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", artist.ArtistId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
artist = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return artist;
|
|
||||||
}
|
|
||||||
public Artist GetArtist(Song song)
|
|
||||||
{
|
|
||||||
Artist artist = new Artist();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving artist record from the database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT art.*, 0 AS SongCount FROM Artist " +
|
|
||||||
"art WHERE art.Name=@Name";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Name", song.Artist);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
artist = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return artist;
|
|
||||||
}
|
|
||||||
public Artist GetArtist(Song song, bool retrieveCount)
|
|
||||||
{
|
|
||||||
var artist = new Artist();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving artist record from the database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = string.Empty;
|
|
||||||
|
|
||||||
if (retrieveCount)
|
|
||||||
query = "SELECT art.*, COUNT(*) AS SongCount FROM Artist " +
|
|
||||||
"art LEFT JOIN Song sng ON art.ArtistId=sng.ArtistId " +
|
|
||||||
"WHERE art.Name=@Name GROUP BY art.ArtistId LIMIT 1";
|
|
||||||
else
|
|
||||||
query = "SELECT art.*, 0 AS SongCount FROM Artist art " +
|
|
||||||
"WHERE art.Name=@Name LIMIT 1";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Name", song.Artist);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
artist = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return artist;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesArtistExist(Artist artist)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Artist exists");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT art.*, 0 AS SongCount FROM Artist art WHERE art.ArtistId=@ArtistId";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", artist.ArtistId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
artist = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (artist.Name != null)
|
|
||||||
{
|
|
||||||
_logger.Info($"Artist {artist.Name} exists");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Could not successfully retrieve Artist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public bool DoesArtistExist(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Artist exists");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT art.*, 0 AS SongCount FROM Artist art WHERE art.Name=@Name";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Name", song.Artist);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
var artist = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(artist.Name))
|
|
||||||
{
|
|
||||||
_logger.Info($"Artist {artist.Name} exists");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Could not successfully retrieve Artist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void SaveArtist(Artist artist)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Saving artist record");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "INSERT INTO Artist(Name) VALUES(@Name)";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Name", artist.Name);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Artist record has successfully been saved");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateArtist(Artist artist)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Updating artist record");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "UPDATE Artist SET Name=@Name WHERE ArtistId=@ArtistId";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Name", artist.Name);
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", artist.ArtistId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Artist record has successfully been saved");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteArtist(Artist artist)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting artist record");
|
|
||||||
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "DELETE FROM Artist WHERE ArtistId=@ArtistId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", artist.ArtistId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Artist> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
List<Artist> artists = new List<Artist>();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["ArtistId"]);
|
|
||||||
var name = reader["Name"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
artists.Add(new Artist
|
|
||||||
{
|
|
||||||
ArtistId = id,
|
|
||||||
Name = name,
|
|
||||||
SongCount = songCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Artist records retrieved");
|
|
||||||
|
|
||||||
return artists;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Artist ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
Artist artist = new Artist();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["ArtistId"]);
|
|
||||||
var name = reader["Name"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
artist.ArtistId = id;
|
|
||||||
artist.Name = name;
|
|
||||||
artist.SongCount = songCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Single artist record retrieved");
|
|
||||||
|
|
||||||
return artist;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
protected string _connectionString;
|
|
||||||
protected static Logger _logger = NLog.LogManager.GetCurrentClassLogger();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
protected MySqlConnection GetConnection()
|
|
||||||
{
|
|
||||||
return new MySqlConnection(_connectionString);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
using Icarus.Types;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class CoverArtRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
public CoverArtRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public List<CoverArt> GetCoverArtRecords()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Querying cover art records");
|
|
||||||
|
|
||||||
var query = "SELECT cv.*, sng.Id AS SongId FROM CoverArt " +
|
|
||||||
"cv LEFT JOIN Song sng ON cv.CoverArtId=sng.CoverArtId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public CoverArt GetCoverArt(CoverArt cover)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Querying cover art record");
|
|
||||||
|
|
||||||
var query = "SELECT * FROM CoverArt WHERE " +
|
|
||||||
"CoverArtId=@CoverArtId";
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters
|
|
||||||
.AddWithValue("@CoverArtId", cover.CoverArtId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public CoverArt GetCoverArt(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Querying cover art record");
|
|
||||||
|
|
||||||
var query = "SELECT cov.* FROM CoverArt cov LEFT JOIN " +
|
|
||||||
"Song sng ON cov.CoverArtId=sng.CoverArtId WHERE " +
|
|
||||||
"sng.Id=@SongId";
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@SongId", song.Id);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public CoverArt GetCoverArt(CoverArtField field, CoverArt cover)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Querying cover art record");
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(BuildQuery(field), conn))
|
|
||||||
{
|
|
||||||
switch (field)
|
|
||||||
{
|
|
||||||
case CoverArtField.SongTitle:
|
|
||||||
cmd.Parameters.AddWithValue("@SongTitle",
|
|
||||||
cover.SongTitle);
|
|
||||||
break;
|
|
||||||
case CoverArtField.ImagePath:
|
|
||||||
cmd.Parameters.AddWithValue("@ImagePath",
|
|
||||||
cover.ImagePath);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesCoverArtExist(CoverArt cover)
|
|
||||||
{
|
|
||||||
return GetCoverArt(cover) != null ? true : false;
|
|
||||||
}
|
|
||||||
public bool DoesCoverArtExist(Song song)
|
|
||||||
{
|
|
||||||
return GetCoverArt(song) != null ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveCoverArt(CoverArt coverArt)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Saving cover art record");
|
|
||||||
|
|
||||||
var query = "INSERT INTO CoverArt(SongTitle, ImagePath) " +
|
|
||||||
"VALUES(@SongTitle, @ImagePath)";
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters
|
|
||||||
.AddWithValue("@SongTitle", coverArt.SongTitle);
|
|
||||||
cmd.Parameters
|
|
||||||
.AddWithValue("@ImagePath", coverArt.ImagePath);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteCoverArt(CoverArt cover)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Deleting cover art record");
|
|
||||||
|
|
||||||
var query = "DELETE FROM CoverArt WHERE " +
|
|
||||||
"CoverArtId=@CoverArtId";
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters
|
|
||||||
.AddWithValue("@CoverArtId", cover.CoverArtId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CoverArt> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
if (reader.HasRows)
|
|
||||||
{
|
|
||||||
var coverArtList = new List<CoverArt>();
|
|
||||||
_logger.Info("Parsing cover art records");
|
|
||||||
while (reader.Read())
|
|
||||||
coverArtList.Add(new CoverArt
|
|
||||||
{
|
|
||||||
CoverArtId = Convert.ToInt32(reader["CoverArtId"]),
|
|
||||||
SongTitle = reader["SongTitle"].ToString(),
|
|
||||||
ImagePath = reader["ImagePath"].ToString(),
|
|
||||||
SongId = Convert.ToInt32(reader["SongId"].ToString())
|
|
||||||
});
|
|
||||||
|
|
||||||
return coverArtList;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CoverArt ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
if (reader.HasRows)
|
|
||||||
{
|
|
||||||
_logger.Info("Parsing single cover art record");
|
|
||||||
reader.Read();
|
|
||||||
|
|
||||||
return new CoverArt
|
|
||||||
{
|
|
||||||
CoverArtId = Convert.ToInt32(reader["CoverArtId"]),
|
|
||||||
SongTitle = reader["SongTitle"].ToString(),
|
|
||||||
ImagePath = reader["ImagePath"].ToString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string BuildQuery(CoverArtField field)
|
|
||||||
{
|
|
||||||
switch (field)
|
|
||||||
{
|
|
||||||
case CoverArtField.SongTitle:
|
|
||||||
return "SELECT * FROM CoverArt WHERE SongTitle=@SongTitle";
|
|
||||||
case CoverArtField.ImagePath:
|
|
||||||
return "SELECT * FROM CoverArt WHERE ImagePath=" +
|
|
||||||
"@ImagePath";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool? AnyCoverArt()
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
_logger.Info("Checking to see if there are any cover art " +
|
|
||||||
"records");
|
|
||||||
|
|
||||||
var query = "SELECT * FROM CoverArt";
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return reader.HasRows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,447 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class GenreRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public GenreRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public List<Genre> GetGenresWithoutCount()
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving all genre records without song counts");
|
|
||||||
|
|
||||||
var genres = new List<Genre>();
|
|
||||||
|
|
||||||
if (AnyGenre())
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT * FROM Genre";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
genres = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return genres;
|
|
||||||
}
|
|
||||||
public List<Genre> GetGenres()
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Genre records");
|
|
||||||
|
|
||||||
var genres = new List<Genre>();
|
|
||||||
|
|
||||||
if (AnyGenre())
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT gnr.*, COUNT(*) AS SongCount FROM Genre " +
|
|
||||||
"gnr LEFT JOIN Song sng ON gnr.GenreId=sng.GenreId " +
|
|
||||||
"GROUP BY gnr.GenreId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
genres = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return genres;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Genre GetGenre(Genre genre)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Genre record");
|
|
||||||
|
|
||||||
if (DoesGenreExist(genre))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT gnr.*, COUNT(*) AS SongCount FROM Genre " +
|
|
||||||
"gnr LEFT JOIN Song sng ON gnr.GenreId=sng.GenreId " +
|
|
||||||
"WHERE gnr.GenreId=@GenreId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", genre.GenreId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
genre = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return genre;
|
|
||||||
}
|
|
||||||
public Genre GetGenre(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Genre record");
|
|
||||||
|
|
||||||
var genre = new Genre();
|
|
||||||
|
|
||||||
if (DoesGenreExist(song))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT gnr.*, 0 AS SongCount FROM Genre " +
|
|
||||||
"gnr WHERE gnr.GenreName=@GenreName";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreName", song.Genre);
|
|
||||||
_logger.Info($"Song genre:\n\n\n {song.Genre}");
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
genre = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return genre;
|
|
||||||
}
|
|
||||||
public Genre GetGenre(Song song, bool retrieveCount)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Genre record");
|
|
||||||
|
|
||||||
var genre = new Genre();
|
|
||||||
|
|
||||||
if (DoesGenreExist(song))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = string.Empty;
|
|
||||||
|
|
||||||
if (retrieveCount)
|
|
||||||
query = "SELECT gnr.*, COUNT(*) AS SongCount FROM Genre gnr " +
|
|
||||||
"LEFT JOIN Song sng ON gnr.GenreId=sng.GenreId " +
|
|
||||||
"WHERE gnr.GenreName=@GenreName GROUP BY gnr.GenreId " +
|
|
||||||
"LIMIT 1";
|
|
||||||
else
|
|
||||||
query = "SELECT gnr.*, 0 AS SongCount FROM Genre gnr " +
|
|
||||||
"WHERE gnr.GenreName=@GenreName LIMIT 1";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreName", song.Genre);
|
|
||||||
_logger.Info($"Song genre:\n\n\n {song.Genre}");
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
genre = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return genre;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesGenreExist(Genre genre)
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Genre record exists");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT gnr.*, 0 AS SongCount FROM Genre gnr WHERE " +
|
|
||||||
"gnr.GenreId=@GenreId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", genre.GenreId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
genre = ParseSingleData(reader);
|
|
||||||
var genreName = genre.GenreName;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(genreName))
|
|
||||||
{
|
|
||||||
_logger.Info("Genre exists");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Genre does not exist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public bool DoesGenreExist(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Genre record exists");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT gnr.*, 0 AS SongCount FROM Genre gnr WHERE " +
|
|
||||||
"gnr.GenreName=@GenreName";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreName", song.Genre);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
var genre = ParseSingleData(reader);
|
|
||||||
var genreName = genre.GenreName;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(genreName))
|
|
||||||
{
|
|
||||||
_logger.Info("Genre exists");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Genre does not exist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveGenre(Genre genre)
|
|
||||||
{
|
|
||||||
_logger.Info("Saving Genre record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "INSERT INTO Genre(GenreName) VALUES(@GenreName)";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreName", genre.GenreName);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateGenre(Genre genre)
|
|
||||||
{
|
|
||||||
_logger.Info("Updating Genre record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "UPDATE Genre SET GenreName=@GenreName " +
|
|
||||||
"WHERE GenreId=@GenreId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreName", genre.GenreName);
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", genre.GenreId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteGenre(Genre genre)
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting Genre record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "DELETE FROM Genre WHERE GenreId=@GenreId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", genre.GenreId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Genre> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
var genres = new List<Genre>();
|
|
||||||
_logger.Info("Retrieving genre records");
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["GenreId"].ToString());
|
|
||||||
var genreName = reader["GenreName"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
|
|
||||||
genres.Add(new Genre
|
|
||||||
{
|
|
||||||
GenreId = id,
|
|
||||||
GenreName = genreName,
|
|
||||||
SongCount = songCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Genre records retrieved");
|
|
||||||
|
|
||||||
return genres;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Genre ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
var genre = new Genre();
|
|
||||||
_logger.Info("Retrieving single genre record");
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["GenreId"].ToString());
|
|
||||||
var genreName = reader["GenreName"].ToString();
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
genre.GenreId = id;
|
|
||||||
genre.GenreName = genreName;
|
|
||||||
genre.SongCount = songCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Single genre record retrieved");
|
|
||||||
|
|
||||||
return genre;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AnyGenre()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT * FROM Genre";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
return reader.HasRows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("No genre records found");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,324 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class SongRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public SongRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public void SaveSong(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Saving song to the database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
string query = "INSERT INTO Song(Title, AlbumTitle, Artist," +
|
|
||||||
" Year, Genre, Duration, Filename, SongPath, AlbumId, " +
|
|
||||||
"ArtistId, GenreId, YearId, CoverArtId) VALUES(@Title," +
|
|
||||||
" @AlbumTitle, @Artist, @Year, @Genre, @Duration, " +
|
|
||||||
"@Filename, @SongPath, @AlbumId, @ArtistId, @GenreId," +
|
|
||||||
" @YearId, @CoverArtId)";
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", song.Title);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumTitle", song.AlbumTitle);
|
|
||||||
cmd.Parameters.AddWithValue("@Artist", song.Artist);
|
|
||||||
cmd.Parameters.AddWithValue("@Year", song.Year);
|
|
||||||
cmd.Parameters.AddWithValue("@Genre", song.Genre);
|
|
||||||
cmd.Parameters.AddWithValue("@Duration", song.Duration);
|
|
||||||
cmd.Parameters.AddWithValue("@Filename", song.Filename);
|
|
||||||
cmd.Parameters.AddWithValue("@SongPath", song.SongPath);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", song.AlbumId);
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", song.ArtistId);
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", song.GenreId);
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", song.YearId);
|
|
||||||
cmd.Parameters.AddWithValue("@CoverArtId", song.CoverArtId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_logger.Info("Successfully saved song to the database");
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateSong(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
string query = "UPDATE Song SET Title=@Title, AlbumTitle=@AlbumTitle, " +
|
|
||||||
"Artist=@Artist, Year=@Year, Genre=@Genre, Duration=@Duration, " +
|
|
||||||
"Filename=@Filename, SongPath=@SongPath, AlbumId=@AlbumId, " +
|
|
||||||
"ArtistId=@ArtistId, GenreId=@GenreId, YearId=@YearId WHERE Id=@Id";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Title", song.Title);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumTitle", song.AlbumTitle);
|
|
||||||
cmd.Parameters.AddWithValue("@Artist", song.Artist);
|
|
||||||
cmd.Parameters.AddWithValue("@Year", song.Year);
|
|
||||||
cmd.Parameters.AddWithValue("@Genre", song.Genre);
|
|
||||||
cmd.Parameters.AddWithValue("@Duration", song.Duration);
|
|
||||||
cmd.Parameters.AddWithValue("@Filename", song.Filename);
|
|
||||||
cmd.Parameters.AddWithValue("@SongPath", song.SongPath);
|
|
||||||
cmd.Parameters.AddWithValue("@Id", song.Id);
|
|
||||||
cmd.Parameters.AddWithValue("@AlbumId", song.AlbumId);
|
|
||||||
cmd.Parameters.AddWithValue("@ArtistId", song.ArtistId);
|
|
||||||
cmd.Parameters.AddWithValue("@GenreId", song.GenreId);
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", song.YearId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_logger.Info("Updated song");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
Console.WriteLine("An error occurred in SongRepository:");
|
|
||||||
Console.WriteLine(msg);
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteSong(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting song record");
|
|
||||||
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "Delete FROM Song WHERE Id=@Id";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Id", song.Id);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteSong(int id)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting song record");
|
|
||||||
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
string query = "DELETE FROM Song WHERE Id=@Id";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Id", id);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Song> GetAllSongs()
|
|
||||||
{
|
|
||||||
List<Song> songs = new List<Song>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving songs from the database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM Song";
|
|
||||||
Console.WriteLine("ffff");
|
|
||||||
MySqlCommand cmd = new MySqlCommand(query, conn);
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
songs = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error ocurred:\n{exMsg}");
|
|
||||||
songs.Clear();
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Song GetSong(Song song)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving song from database");
|
|
||||||
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM Song WHERE Id=@Id";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Id", song.Id);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
song = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return song;
|
|
||||||
}
|
|
||||||
public Song GetSong(int id)
|
|
||||||
{
|
|
||||||
Song song = new Song();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving song from database");
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM Song WHERE Id=@Id";
|
|
||||||
|
|
||||||
MySqlCommand cmd = new MySqlCommand(query, conn);
|
|
||||||
cmd.Parameters.AddWithValue("@Id", id);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
song = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
_logger.Info("Song found");
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error ocurred: {exMsg}");
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return song;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesSongExist(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if the song exists");
|
|
||||||
var songInDatabase = GetSong(song);
|
|
||||||
var title = songInDatabase.Title;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(title))
|
|
||||||
{
|
|
||||||
_logger.Info("Song exists");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Song does not exists");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Song> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
|
|
||||||
List<Song> songs = new List<Song>();
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
songs.Add(new Song
|
|
||||||
{
|
|
||||||
Id = Convert.ToInt32(reader["Id"]),
|
|
||||||
Title = reader["Title"].ToString(),
|
|
||||||
AlbumTitle = reader["AlbumTitle"].ToString(),
|
|
||||||
Artist = reader["Artist"].ToString(),
|
|
||||||
Year = Convert.ToInt32(reader["Year"]),
|
|
||||||
Genre = reader["Genre"].ToString(),
|
|
||||||
Duration = Convert.ToInt32(reader["Duration"]),
|
|
||||||
Filename = reader["Filename"].ToString(),
|
|
||||||
SongPath = reader["SongPath"].ToString(),
|
|
||||||
AlbumId = Convert.ToInt32(reader["AlbumId"].ToString()),
|
|
||||||
ArtistId = Convert.ToInt32(reader["ArtistId"].ToString()),
|
|
||||||
GenreId = Convert.ToInt32(reader["GenreId"].ToString()),
|
|
||||||
YearId = Convert.ToInt32(reader["YearId"].ToString()),
|
|
||||||
CoverArtId = Convert.ToInt32(reader["CoverArtId"].ToString())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return songs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Song ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
Song song = new Song();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
song.Id = Convert.ToInt32(reader["Id"]);
|
|
||||||
song.Title = reader["Title"].ToString();
|
|
||||||
song.AlbumTitle = reader["AlbumTitle"].ToString();
|
|
||||||
song.Artist = reader["Artist"].ToString();
|
|
||||||
song.Year = Convert.ToInt32(reader["Year"].ToString());
|
|
||||||
song.Genre = reader["Genre"].ToString();
|
|
||||||
song.Duration = Convert.ToInt32(reader["Duration"]);
|
|
||||||
song.Filename = reader["Filename"].ToString();
|
|
||||||
song.SongPath = reader["SongPath"].ToString();
|
|
||||||
song.AlbumId = Convert.ToInt32(reader["AlbumId"].ToString());
|
|
||||||
song.ArtistId = Convert.ToInt32(reader["ArtistId"].ToString());
|
|
||||||
song.GenreId = Convert.ToInt32(reader["GenreId"].ToString());
|
|
||||||
song.YearId = Convert.ToInt32(reader["YearId"].ToString());
|
|
||||||
song.CoverArtId = Convert.ToInt32(reader["CoverArtId"].ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return song;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class UserRepository: BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
public UserRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public void SaveUser(User user)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Saving user");
|
|
||||||
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
string query = "INSERT INTO User(Username, Password, Nickname, Email" +
|
|
||||||
", PhoneNumber, Firstname, Lastname, EmailVerified) " +
|
|
||||||
"VALUES(@Username, @Password, @Nickname, @Email, @PhoneNumber," +
|
|
||||||
" @Firstname, @Lastname, @EmailVerified)";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Username", user.Username);
|
|
||||||
cmd.Parameters.AddWithValue("@Password", user.Password);
|
|
||||||
cmd.Parameters.AddWithValue("@Nickname", user.Nickname);
|
|
||||||
cmd.Parameters.AddWithValue("@Email", user.Email);
|
|
||||||
cmd.Parameters.AddWithValue("@PhoneNumber", user.PhoneNumber);
|
|
||||||
cmd.Parameters.AddWithValue("@Firstname", user.Firstname);
|
|
||||||
cmd.Parameters.AddWithValue("@Lastname", user.Lastname);
|
|
||||||
cmd.Parameters.AddWithValue("@EmailVerified", user.EmailVerified);
|
|
||||||
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Successfully saved user");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public User RetrieveUser(User user)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving user");
|
|
||||||
|
|
||||||
using (MySqlConnection conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM User WHERE Username=@Username";
|
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Username", user.Username);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
user = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Successfully retrieved user");
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var exMsg = ex.Message;
|
|
||||||
Console.WriteLine($"An error occurred:\n{exMsg}");
|
|
||||||
_logger.Error(exMsg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesUserExist(User user)
|
|
||||||
{
|
|
||||||
var username = user.Username;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.Info($"Checking to see if {user.Username} exists");
|
|
||||||
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
var query = "SELECT * FROM User WHERE Username=@Username";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@Username", user.Username);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
user = ParseSingleData(reader, true);
|
|
||||||
username = user.Username;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(username))
|
|
||||||
{
|
|
||||||
_logger.Info($"The user {username} exists");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info($"The user {username} does not exists");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private User ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
var user = new User();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["Id"].ToString());
|
|
||||||
var username = reader["Username"].ToString();
|
|
||||||
var password = reader["Password"].ToString();
|
|
||||||
var nickname = reader["Nickname"].ToString();
|
|
||||||
var email = reader["Email"].ToString();
|
|
||||||
var phoneNumber = reader["PhoneNumber"].ToString();
|
|
||||||
var emailVerified = reader["EmailVerified"].ToString() == "1";
|
|
||||||
var firstname = reader["Firstname"].ToString();
|
|
||||||
var lastname = reader["Lastname"].ToString();
|
|
||||||
var rawLastLogin = reader["LastLogin"].ToString();
|
|
||||||
|
|
||||||
var parsedDateCreated = DateTime.Parse(reader["DateCreated"].ToString());
|
|
||||||
|
|
||||||
var dateCreated = DateTime.Parse(parsedDateCreated.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(rawLastLogin))
|
|
||||||
{
|
|
||||||
var parsedLastLogin = DateTime.Parse(rawLastLogin);
|
|
||||||
var lastLogin = DateTime.Parse(parsedLastLogin.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
||||||
user.LastLogin = lastLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.Id = id;
|
|
||||||
user.Username = username;
|
|
||||||
user.Password = password;
|
|
||||||
user.Nickname = nickname;
|
|
||||||
user.Email = email;
|
|
||||||
user.PhoneNumber = phoneNumber;
|
|
||||||
user.EmailVerified = emailVerified;
|
|
||||||
user.Firstname = firstname;
|
|
||||||
user.Lastname = lastname;
|
|
||||||
user.DateCreated = dateCreated;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
private User ParseSingleData(MySqlDataReader reader, bool ignoreLastLogin)
|
|
||||||
{
|
|
||||||
var user = new User();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["Id"].ToString());
|
|
||||||
var username = reader["Username"].ToString();
|
|
||||||
var nickname = reader["Nickname"].ToString();
|
|
||||||
var email = reader["Email"].ToString();
|
|
||||||
var phoneNumber = reader["PhoneNumber"].ToString();
|
|
||||||
var emailVerified = reader["EmailVerified"].ToString() == "1";
|
|
||||||
var firstname = reader["Firstname"].ToString();
|
|
||||||
var lastname = reader["Lastname"].ToString();
|
|
||||||
|
|
||||||
var parsedDateCreated = DateTime.Parse(reader["DateCreated"].ToString());
|
|
||||||
|
|
||||||
var dateCreated = DateTime.Parse(parsedDateCreated.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
||||||
|
|
||||||
if (!ignoreLastLogin)
|
|
||||||
{
|
|
||||||
var parsedLastLogin = DateTime.Parse(reader["LastLogin"].ToString());
|
|
||||||
var lastLogin = DateTime.Parse(parsedLastLogin.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
||||||
user.LastLogin = lastLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.Id = id;
|
|
||||||
user.Username = username;
|
|
||||||
user.Nickname = nickname;
|
|
||||||
user.Email = email;
|
|
||||||
user.PhoneNumber = phoneNumber;
|
|
||||||
user.EmailVerified = emailVerified;
|
|
||||||
user.Firstname = firstname;
|
|
||||||
user.Lastname = lastname;
|
|
||||||
user.DateCreated = dateCreated;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
|
||||||
|
|
||||||
using Icarus.Models;
|
|
||||||
|
|
||||||
namespace Icarus.Database.Repositories
|
|
||||||
{
|
|
||||||
public class YearRepository : BaseRepository
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public YearRepository(string connectionString)
|
|
||||||
{
|
|
||||||
_connectionString = connectionString;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public List<Year> GetSongYears()
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Year records");
|
|
||||||
|
|
||||||
var yearValues = new List<Year>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT yr.*, COUNT(*) AS SongCount FROM Year " +
|
|
||||||
"yr LEFT JOIN Song sng ON yr.YearId=sng.YearId " +
|
|
||||||
"GROUP BY yr.YearId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
yearValues = ParseData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return yearValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Year GetSongYear(Year year)
|
|
||||||
{
|
|
||||||
_logger.Info("Retrieving Year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT yr.*, COUNT(*) AS SongCount FROM Year " +
|
|
||||||
"yr LEFT JOIN Song sng ON yr.YearId=sng.YearId WHERE " +
|
|
||||||
"YearId=@YearId GROUP BY yr.YearId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", year.YearId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
year = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return year;
|
|
||||||
}
|
|
||||||
public Year GetSongYear(Song song)
|
|
||||||
{
|
|
||||||
var year = new Year();
|
|
||||||
|
|
||||||
_logger.Info("Retrieving Year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT yr.*, 0 AS SongCount FROM Year " +
|
|
||||||
"yr WHERE yr.YearValue=@YearValue";
|
|
||||||
|
|
||||||
using(var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearValue", song.Year);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
year = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return year;
|
|
||||||
}
|
|
||||||
public Year GetSongYear(Song song, bool retrieveCount)
|
|
||||||
{
|
|
||||||
var year = new Year();
|
|
||||||
|
|
||||||
_logger.Info("Retrieving year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = string.Empty;
|
|
||||||
|
|
||||||
if (retrieveCount)
|
|
||||||
query = "SELECT yr.*, COUNT(*) AS SongCount FROM Year yr " +
|
|
||||||
"LEFT JOIN Song sng ON yr.YearValue=sng.Year WHERE " +
|
|
||||||
"yr.YearValue=@YearValue GROUP BY yr.YearId LIMIT 1";
|
|
||||||
else
|
|
||||||
query = "SELECT yr.*, 0 AS SongCount FROM Year yr " +
|
|
||||||
"WHERE yr.YearValue=@YearValue LIMIT 1";
|
|
||||||
|
|
||||||
using(var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearValue", song.Year);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
year = ParseSingleData(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
return year;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoesYearExist(Year year)
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Year record exists");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT yr.*, 0 AS SongCount FROM Year yr WHERE " +
|
|
||||||
"yr.YearId=@YearId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", year.YearId);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
year = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (year.YearValue > 0)
|
|
||||||
{
|
|
||||||
_logger.Info("Year record exists");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Year record does not exist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public bool DoesYearExist(Song song)
|
|
||||||
{
|
|
||||||
_logger.Info("Checking to see if Year record exists");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "SELECT yr.*, 0 AS SongCount FROM Year yr WHERE " +
|
|
||||||
"yr.YearValue=@YearValue";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearValue", song.Year);
|
|
||||||
|
|
||||||
using (var reader = cmd.ExecuteReader())
|
|
||||||
{
|
|
||||||
var year = ParseSingleData(reader);
|
|
||||||
|
|
||||||
if (year.YearValue > 0)
|
|
||||||
{
|
|
||||||
_logger.Info("Year record exists");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Year record does not exist");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveYear(Year year)
|
|
||||||
{
|
|
||||||
_logger.Info("Saving Year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "INSERT INTO Year(YearValue) VALUES(@YearValue)";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearValue", year.YearValue);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UpdateYear(Year year)
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting Year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "UPDATE Year SET YearValue=@YearValue WHERE YearId=@YearId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", year.YearId);
|
|
||||||
cmd.Parameters.AddWithValue("@YearValue", year.YearValue);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DeleteYear(Year year)
|
|
||||||
{
|
|
||||||
_logger.Info("Deleting Year record");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var conn = GetConnection())
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
|
|
||||||
var query = "DELETE FROM Year WHERE YearId=@YearId";
|
|
||||||
|
|
||||||
using (var cmd = new MySqlCommand(query, conn))
|
|
||||||
{
|
|
||||||
cmd.Parameters.AddWithValue("@YearId", year.YearId);
|
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var msg = ex.Message;
|
|
||||||
_logger.Error(msg, "An error occurred");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Year> ParseData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
var yearValues = new List<Year>();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["YearId"].ToString());
|
|
||||||
var year = Convert.ToInt32(reader["YearValue"].ToString());
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
|
|
||||||
yearValues.Add(new Year
|
|
||||||
{
|
|
||||||
YearId = id,
|
|
||||||
YearValue = year,
|
|
||||||
SongCount = songCount
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return yearValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Year ParseSingleData(MySqlDataReader reader)
|
|
||||||
{
|
|
||||||
var yearValue = new Year();
|
|
||||||
|
|
||||||
while (reader.Read())
|
|
||||||
{
|
|
||||||
var id = Convert.ToInt32(reader["YearId"].ToString());
|
|
||||||
var year = Convert.ToInt32(reader["YearValue"].ToString());
|
|
||||||
var songCount = Convert.ToInt32(reader["SongCount"].ToString());
|
|
||||||
|
|
||||||
yearValue.YearId = id;
|
|
||||||
yearValue.YearValue = year;
|
|
||||||
yearValue.SongCount = songCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return yearValue;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
|
||||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="3.1.3" />
|
|
||||||
<PackageReference Include="DotNetZip" Version="1.13.3" />
|
|
||||||
<PackageReference Include="EntityFramework" Version="6.2.0" />
|
|
||||||
<PackageReference Include="ID3" Version="0.6.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.3">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="mysql.data" Version="8.0.15" />
|
|
||||||
<PackageReference Include="MySql.Data.Entity" Version="7.0.7-m61" />
|
|
||||||
<PackageReference Include="MySql.Data.EntityFrameworkCore" Version="8.0.15" />
|
|
||||||
<PackageReference Include="MySql.Data.EntityFrameworkCore.Design" Version="8.0.15" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.8.1" />
|
|
||||||
<PackageReference Include="RestSharp" Version="106.6.9" />
|
|
||||||
<PackageReference Include="SevenZip" Version="19.0.0" />
|
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
|
|
||||||
<PackageReference Include="taglib" Version="2.1.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Update="nlog.config" CopyToOutputDirectory="PreserveNewest" />
|
|
||||||
<Content Include="Images/Stock/*.*" CopyToOutputDirectory="PreserveNewest" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
|
||||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ActiveDebugProfile>Icarus</ActiveDebugProfile>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,34 +1,22 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 15.0.26124.0
|
VisualStudioVersion = 17.0.31903.59
|
||||||
MinimumVisualStudioVersion = 15.0.26124.0
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Icarus", "Icarus.csproj", "{3BEBAB33-17BF-4183-9664-3D537A684138}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Icarus", "Icarus\Icarus.csproj", "{EC7ADFAA-9CCA-40E4-B035-DC2ADF117CB4}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x64 = Debug|x64
|
|
||||||
Debug|x86 = Debug|x86
|
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x64 = Release|x64
|
|
||||||
Release|x86 = Release|x86
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{EC7ADFAA-9CCA-40E4-B035-DC2ADF117CB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{EC7ADFAA-9CCA-40E4-B035-DC2ADF117CB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{EC7ADFAA-9CCA-40E4-B035-DC2ADF117CB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|x64.Build.0 = Debug|Any CPU
|
{EC7ADFAA-9CCA-40E4-B035-DC2ADF117CB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{3BEBAB33-17BF-4183-9664-3D537A684138}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -1,313 +0,0 @@
|
|||||||
2019-05-23 20:25:46.2420 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:25:46.2666 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:25:46.3926 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:25:46.4144 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:25:46.4351 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:25:46.4703 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:26:13.6466 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:26:13.6651 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:26:13.8165 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:26:13.8351 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:26:13.8552 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:26:13.8939 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:33:39.8295 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:33:39.8438 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:33:39.9198 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:33:39.9238 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:33:39.9238 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:33:39.9871 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:33:40.2458 Info Configuration initialized.
|
|
||||||
2019-05-23 20:33:40.2602 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:33:42.2086 Info Shutting down logging...
|
|
||||||
2019-05-23 20:33:42.2458 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:34:06.6746 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:34:06.6896 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:34:06.7827 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:34:06.7827 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:34:06.8010 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:34:06.8321 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:34:06.8673 Info Configuration initialized.
|
|
||||||
2019-05-23 20:34:06.8673 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:34:07.7083 Info Shutting down logging...
|
|
||||||
2019-05-23 20:34:07.7346 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:35:03.8649 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:35:03.8783 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:35:03.9596 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:35:03.9596 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:35:03.9745 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:35:03.9958 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:35:04.0200 Info Configuration initialized.
|
|
||||||
2019-05-23 20:35:04.0200 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:35:04.5747 Info Shutting down logging...
|
|
||||||
2019-05-23 20:35:04.6042 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:35:41.2884 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:35:41.3011 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:35:41.3629 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:35:41.3629 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:35:41.3755 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:35:41.3973 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:35:41.4257 Info Configuration initialized.
|
|
||||||
2019-05-23 20:35:41.4257 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:35:42.0181 Info Shutting down logging...
|
|
||||||
2019-05-23 20:35:42.0437 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:36:03.3664 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:36:03.3803 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:36:03.4469 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:36:03.4469 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:36:03.4634 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:36:03.4897 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:36:03.5214 Info Configuration initialized.
|
|
||||||
2019-05-23 20:36:03.5214 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:36:04.0862 Info Shutting down logging...
|
|
||||||
2019-05-23 20:36:04.1162 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:37:13.4449 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:37:13.4578 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:37:13.5222 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:37:13.5222 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:37:13.5349 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:37:13.5575 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:37:13.5870 Info Configuration initialized.
|
|
||||||
2019-05-23 20:37:13.5870 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:37:14.1141 Info Shutting down logging...
|
|
||||||
2019-05-23 20:37:14.1395 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:37:38.9373 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:37:38.9373 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:37:39.0239 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:37:39.0239 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:37:39.0371 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:37:39.0624 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:37:39.0916 Info Configuration initialized.
|
|
||||||
2019-05-23 20:37:39.0984 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:37:39.2254 Info Shutting down logging...
|
|
||||||
2019-05-23 20:37:39.2461 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:38:15.2217 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:38:15.2426 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:38:15.3307 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:38:15.3307 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:38:15.3434 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:38:15.3733 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:38:15.4046 Info Configuration initialized.
|
|
||||||
2019-05-23 20:38:15.4103 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:38:16.3887 Info Shutting down logging...
|
|
||||||
2019-05-23 20:38:16.4170 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:38:56.3096 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:38:56.3228 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:38:56.3991 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:38:56.3991 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:38:56.4137 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:38:56.4412 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:38:56.4662 Info Configuration initialized.
|
|
||||||
2019-05-23 20:38:56.4711 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:38:57.5659 Info Shutting down logging...
|
|
||||||
2019-05-23 20:38:57.5921 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:39:33.6137 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:39:33.6328 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:39:33.7158 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:39:33.7209 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:39:33.7349 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\NLog.config...
|
|
||||||
2019-05-23 20:39:33.7661 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:39:33.7984 Info Configuration initialized.
|
|
||||||
2019-05-23 20:39:33.7984 Info NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c. File version: 4.5.11.8645. Product version: 4.5.11.
|
|
||||||
2019-05-23 20:39:35.3535 Info Shutting down logging...
|
|
||||||
2019-05-23 20:39:35.3853 Info Logger has been shut down.
|
|
||||||
2019-05-23 20:41:03.9531 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:41:04.0224 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:41:04.2489 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:41:04.2638 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:41:04.2801 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:41:04.3178 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:42:20.8771 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:42:20.8771 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:42:20.8771 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:42:20.8771 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:42:20.8771 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:42:20.8771 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:42:20.8912 Info Closing old configuration.
|
|
||||||
2019-05-23 20:42:20.9264 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:44:09.2436 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:44:09.2625 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:44:09.5033 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:44:09.5221 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:44:09.5436 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:44:09.5955 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:44:22.9386 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:44:22.9386 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:44:22.9386 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:44:22.9525 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:44:22.9525 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:44:22.9525 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:44:22.9525 Info Closing old configuration.
|
|
||||||
2019-05-23 20:44:22.9920 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:45:56.3589 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:45:56.3781 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:45:56.5714 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:45:56.5830 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:45:56.5944 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:45:56.6232 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:46:59.8334 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:46:59.8559 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:47:00.0588 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:47:00.0756 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:47:00.1007 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:47:00.1455 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:48:14.1040 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:48:14.1282 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:48:14.2899 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:48:14.3059 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:48:14.3273 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:48:14.3764 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:49:07.1970 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:49:07.2494 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:49:07.4433 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:49:07.4565 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:49:07.4760 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:49:07.5338 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:49:20.7109 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 20:49:20.7109 Info Found 45 configuration items
|
|
||||||
2019-05-23 20:49:20.7109 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 20:49:20.7184 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 20:49:20.7184 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 20:49:20.7184 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 20:49:20.7184 Info Closing old configuration.
|
|
||||||
2019-05-23 20:49:20.7514 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:24:18.4464 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:24:18.4889 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:24:18.7399 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:24:18.7604 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:24:18.7838 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:24:18.8238 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:25:06.3861 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:25:06.3904 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:25:06.3904 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:25:06.4052 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:25:06.4052 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:25:06.4052 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:25:06.4243 Info Closing old configuration.
|
|
||||||
2019-05-23 21:25:06.4727 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:26:26.1707 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:26:26.1964 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:26:26.3688 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:26:26.3866 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:26:26.4195 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:26:26.4805 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:27:58.0534 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:27:58.0751 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:27:58.2630 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:27:58.2786 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:27:58.2977 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:27:58.3440 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:28:30.3852 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:28:30.3901 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:28:30.3901 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:28:30.4094 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:28:30.4094 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:28:30.4094 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:28:30.4256 Info Closing old configuration.
|
|
||||||
2019-05-23 21:28:30.4744 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:28:35.1110 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:28:35.1110 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:28:35.1110 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:28:35.1110 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:28:35.1110 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:28:35.1110 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:28:35.1110 Info Closing old configuration.
|
|
||||||
2019-05-23 21:28:35.1110 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:33:27.3097 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:33:27.3317 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:33:27.6071 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:33:27.6230 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:33:27.6409 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:33:27.6860 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:34:21.2749 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:34:21.2749 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:34:21.2822 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:34:21.2822 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:34:21.2977 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:34:21.2977 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:34:21.2977 Info Closing old configuration.
|
|
||||||
2019-05-23 21:34:21.3496 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:34:44.8361 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:34:44.8361 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:34:44.8361 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:34:44.8475 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:34:44.8475 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:34:44.8475 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:34:44.8475 Info Closing old configuration.
|
|
||||||
2019-05-23 21:34:49.8402 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:36:39.6643 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:36:39.6956 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:36:39.9527 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:36:39.9527 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:36:39.9854 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:36:40.0214 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:37:11.5126 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:37:11.5149 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:37:11.5149 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:37:11.5149 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:37:11.5149 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:37:11.5149 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:37:11.5149 Info Closing old configuration.
|
|
||||||
2019-05-23 21:37:11.5688 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:37:55.3893 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:37:55.3912 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:37:55.3912 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:37:55.3912 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:37:55.4088 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:37:55.4088 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:37:55.4088 Info Closing old configuration.
|
|
||||||
2019-05-23 21:37:55.4088 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:44:40.0208 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:44:40.0474 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:44:40.2073 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:44:40.2186 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:44:40.2186 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:44:40.2868 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:45:19.6595 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:45:19.6595 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:45:19.6595 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:45:19.6595 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:45:19.6595 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:45:19.6595 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:45:19.6740 Info Closing old configuration.
|
|
||||||
2019-05-23 21:45:19.7116 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:51:00.1698 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:51:00.1840 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:51:00.2721 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:51:00.2721 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:51:00.2920 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:51:00.3152 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:51:25.1256 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:51:25.1256 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:51:25.1256 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:51:25.1256 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:51:25.1256 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:51:25.1256 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:51:25.1412 Info Closing old configuration.
|
|
||||||
2019-05-23 21:51:25.1648 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:51:25.2103 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:51:25.2103 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:51:25.2103 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:51:25.2103 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:51:25.2103 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:51:25.2103 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:51:25.2103 Info Closing old configuration.
|
|
||||||
2019-05-23 21:51:25.2182 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:53:11.2368 Info Logger closing down...
|
|
||||||
2019-05-23 21:53:11.2368 Info Closing old configuration.
|
|
||||||
2019-05-23 21:53:11.2368 Info Logger has been closed down.
|
|
||||||
2019-05-23 21:53:11.2368 Info Shutting down logging...
|
|
||||||
2019-05-23 21:53:11.2555 Info Logger has been shut down.
|
|
||||||
2019-05-23 21:54:25.6441 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:54:25.6761 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:54:25.9546 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:54:25.9757 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:54:25.9951 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:54:26.0361 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:54:55.6086 Info Message Template Auto Format enabled
|
|
||||||
2019-05-23 21:54:55.6086 Info Found 45 configuration items
|
|
||||||
2019-05-23 21:54:55.6086 Info Loading assembly: NLog.Web.AspNetCore
|
|
||||||
2019-05-23 21:54:55.6086 Info Adding target File Target[allfile]
|
|
||||||
2019-05-23 21:54:55.6086 Info Adding target File Target[ownFile-web]
|
|
||||||
2019-05-23 21:54:55.6086 Info Configured from an XML element in C:\Users\user0\Programming\C#\Icarus\bin\Debug\netcoreapp2.2\nlog.config...
|
|
||||||
2019-05-23 21:54:55.6280 Info Closing old configuration.
|
|
||||||
2019-05-23 21:54:55.6926 Info Found 45 configuration items
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
# Use 'var' when possible
|
||||||
|
csharp_style_var_for_built_in_types = true:suggestion
|
||||||
|
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_var_elsewhere = true:suggestion
|
||||||
|
|
||||||
|
# Use expression body for methods
|
||||||
|
csharp_style_expression_bodied_methods = true:silent
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
using Icarus.Authorization;
|
||||||
|
|
||||||
|
namespace Icarus.Authorization.Handlers;
|
||||||
|
|
||||||
|
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
|
||||||
|
{
|
||||||
|
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
|
||||||
|
{
|
||||||
|
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var scopes = context.User.FindFirst(c =>
|
||||||
|
c.Type == "scope" && c.Issuer == requirement.Issuer)!.Value.Split(' ');
|
||||||
|
|
||||||
|
if (scopes.Any(s => s == requirement.Scope))
|
||||||
|
{
|
||||||
|
context.Succeed(requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace Icarus.Authorization;
|
||||||
|
|
||||||
|
public class HasScopeRequirement : IAuthorizationRequirement
|
||||||
|
{
|
||||||
|
public string Issuer { get; }
|
||||||
|
public string Scope { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public HasScopeRequirement(string scope, string issuer)
|
||||||
|
{
|
||||||
|
Scope = scope ?? throw new ArgumentNullException(nameof(scope));
|
||||||
|
Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Org.BouncyCastle.Crypto.Parameters;
|
||||||
|
using Org.BouncyCastle.OpenSsl;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Icarus.Certs;
|
||||||
|
|
||||||
|
public class SigningIssuerCertificate : IDisposable
|
||||||
|
{
|
||||||
|
private readonly System.Security.Cryptography.RSACryptoServiceProvider _rsa;
|
||||||
|
|
||||||
|
public SigningIssuerCertificate()
|
||||||
|
{
|
||||||
|
_rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RsaSecurityKey GetIssuerSigningKey(string publicKeyPath)
|
||||||
|
{
|
||||||
|
var file = publicKeyPath;
|
||||||
|
var publicKey = System.IO.File.ReadAllText(file);
|
||||||
|
|
||||||
|
using (var reader = System.IO.File.OpenText(file))
|
||||||
|
{
|
||||||
|
var pem = new PemReader(reader);
|
||||||
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
|
var parameters = new System.Security.Cryptography.RSAParameters();
|
||||||
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
|
_rsa.ImportParameters(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RsaSecurityKey(_rsa);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_rsa?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SigningAudienceCertificate : IDisposable
|
||||||
|
{
|
||||||
|
private readonly System.Security.Cryptography.RSACryptoServiceProvider _rsa;
|
||||||
|
|
||||||
|
public SigningAudienceCertificate()
|
||||||
|
{
|
||||||
|
_rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SigningCredentials GetAudienceSigningKey(string keyPath)
|
||||||
|
{
|
||||||
|
var file = keyPath;
|
||||||
|
var publicKey = System.IO.File.ReadAllText(file);
|
||||||
|
|
||||||
|
using (var reader = System.IO.File.OpenText(file))
|
||||||
|
{
|
||||||
|
var pem = new PemReader(reader);
|
||||||
|
var o = (RsaKeyParameters)pem.ReadObject();
|
||||||
|
var parameters = new System.Security.Cryptography.RSAParameters();
|
||||||
|
parameters.Modulus = o.Modulus.ToByteArray();
|
||||||
|
parameters.Exponent = o.Exponent.ToByteArray();
|
||||||
|
_rsa.ImportParameters(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SigningCredentials(
|
||||||
|
key: new RsaSecurityKey(_rsa),
|
||||||
|
algorithm: SecurityAlgorithms.RsaSha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_rsa?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
public class AlbumManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private AlbumContext? _albumContext;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public AlbumManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_albumContext = new AlbumContext(_connectionString!);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public void SaveAlbumToDatabase(ref Song song)
|
||||||
|
{
|
||||||
|
_logger.Info("Starting process to save the album record of the song to the database");
|
||||||
|
|
||||||
|
var album = new Album();
|
||||||
|
|
||||||
|
album.Title = song.AlbumTitle;
|
||||||
|
album.AlbumArtist = song.Artist;
|
||||||
|
album.Year = song.Year!.Value;
|
||||||
|
var albumTitle = song.AlbumTitle;
|
||||||
|
var albumArtist = song.Artist;
|
||||||
|
|
||||||
|
var albumRetrieved = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(albumTitle) && alb.AlbumArtist!.Equals(albumArtist));
|
||||||
|
|
||||||
|
if (albumRetrieved == null)
|
||||||
|
{
|
||||||
|
album.SongCount = 1;
|
||||||
|
_albumContext.Add(album);
|
||||||
|
_albumContext.SaveChanges();
|
||||||
|
|
||||||
|
Console.WriteLine($"Album Id {album.Id}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
album.Id = albumRetrieved.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
song.AlbumId = album.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void DeleteAlbumFromDatabase(Song song)
|
||||||
|
{
|
||||||
|
var album = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(song.AlbumTitle));
|
||||||
|
|
||||||
|
if (album == null)
|
||||||
|
{
|
||||||
|
_logger.Info("Cannot delete the album record because it does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteAlbumFromDb(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Album UpdateAlbumInDatabase(Song oldSong, Song newSong)
|
||||||
|
{
|
||||||
|
var albumRecord = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(oldSong.AlbumTitle));
|
||||||
|
var oldAlbumTitle = oldSong.AlbumTitle;
|
||||||
|
var oldAlbumArtist = oldSong.Artist;
|
||||||
|
var newAlbumTitle = newSong.AlbumTitle;
|
||||||
|
var newAlbumArtist = newSong.Artist;
|
||||||
|
|
||||||
|
var info = string.Empty;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(newAlbumArtist))
|
||||||
|
newAlbumArtist = oldAlbumArtist;
|
||||||
|
if (string.IsNullOrEmpty(newAlbumTitle))
|
||||||
|
newAlbumTitle = oldAlbumTitle;
|
||||||
|
|
||||||
|
if ((string.IsNullOrEmpty(newAlbumTitle) && string.IsNullOrEmpty(newAlbumArtist) ||
|
||||||
|
oldAlbumTitle!.Equals(newAlbumTitle) && oldAlbumArtist!.Equals(newAlbumArtist)))
|
||||||
|
{
|
||||||
|
_logger.Info("No change to the song's album");
|
||||||
|
return albumRecord!;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = "Change to the song's album";
|
||||||
|
_logger.Info(info);
|
||||||
|
|
||||||
|
var existingAlbumRecord = _albumContext.Albums!.FirstOrDefault(alb => alb.Title!.Equals(oldSong.AlbumTitle));
|
||||||
|
if (existingAlbumRecord == null)
|
||||||
|
{
|
||||||
|
_logger.Info("Creating new album record");
|
||||||
|
|
||||||
|
var newAlbumRecord = new Album
|
||||||
|
{
|
||||||
|
Title = newAlbumTitle,
|
||||||
|
AlbumArtist = newAlbumArtist,
|
||||||
|
Year = newSong.Year!.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
_albumContext.Add(newAlbumRecord);
|
||||||
|
_albumContext.SaveChanges();
|
||||||
|
|
||||||
|
return newAlbumRecord;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Updating existing album record");
|
||||||
|
|
||||||
|
existingAlbumRecord = _albumContext.Albums!.FirstOrDefault(alb => alb.Title!.Equals(newSong.AlbumTitle));
|
||||||
|
existingAlbumRecord!.AlbumArtist = newAlbumArtist;
|
||||||
|
|
||||||
|
_albumContext.Update(existingAlbumRecord);
|
||||||
|
_albumContext.SaveChanges();
|
||||||
|
|
||||||
|
return existingAlbumRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteAlbumFromDb(Album album)
|
||||||
|
{
|
||||||
|
if (SongsInAlbum(album) <= 1)
|
||||||
|
{
|
||||||
|
_albumContext!.Remove(album);
|
||||||
|
_albumContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SongsInAlbum(Album album)
|
||||||
|
{
|
||||||
|
var sngContext = new SongContext(_connectionString!);
|
||||||
|
var songs = sngContext!.Songs!.Where(sng => sng.AlbumId == album.Id).ToList();
|
||||||
|
|
||||||
|
return songs.Count;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
public class ArtistManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private ArtistContext? _artistContext;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public ArtistManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_artistContext = new ArtistContext(_connectionString!);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public void SaveArtistToDatabase(ref Song song)
|
||||||
|
{
|
||||||
|
_logger.Info("Starting process to save the artist record of the song to the database");
|
||||||
|
|
||||||
|
var artist = new Artist
|
||||||
|
{
|
||||||
|
Name = song.Artist,
|
||||||
|
SongCount = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
var artistRetrieved = _artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(artist.Name));
|
||||||
|
|
||||||
|
if (artistRetrieved == null)
|
||||||
|
{
|
||||||
|
artist.SongCount = 1;
|
||||||
|
_artistContext.Add(artist);
|
||||||
|
_artistContext.SaveChanges();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
artist.Id = artistRetrieved.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
song.ArtistId = artist.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist UpdateArtistInDatabase(Song oldSongRecord, Song newSongRecord)
|
||||||
|
{
|
||||||
|
var oldArtistRecord = _artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(oldSongRecord.AlbumTitle));
|
||||||
|
var oldArtistName = oldArtistRecord!.Name;
|
||||||
|
var newArtistName = newSongRecord.Artist;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(newArtistName) || oldArtistName!.Equals(newArtistName))
|
||||||
|
{
|
||||||
|
_logger.Info("No change to the song's Artist");
|
||||||
|
return oldArtistRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Change to the song's record found");
|
||||||
|
|
||||||
|
if (oldArtistRecord.SongCount <= 1)
|
||||||
|
{
|
||||||
|
_logger.Info("Deleting artist record that no longer has any songs");
|
||||||
|
|
||||||
|
_artistContext.Remove(oldArtistRecord);
|
||||||
|
_artistContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(_artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(oldSongRecord.AlbumTitle)) != null))
|
||||||
|
{
|
||||||
|
_logger.Info("Creating new artist record");
|
||||||
|
|
||||||
|
var newArtistRecord = new Artist
|
||||||
|
{
|
||||||
|
Name = newArtistName
|
||||||
|
};
|
||||||
|
|
||||||
|
_artistContext.Add(newArtistRecord);
|
||||||
|
_artistContext.SaveChanges();
|
||||||
|
|
||||||
|
return newArtistRecord;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Updating existing artist record");
|
||||||
|
|
||||||
|
var existingArtistRecord = _artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(newSongRecord.AlbumTitle));
|
||||||
|
|
||||||
|
_artistContext.Update(existingArtistRecord!);
|
||||||
|
_artistContext.SaveChanges();
|
||||||
|
|
||||||
|
return existingArtistRecord!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteArtistFromDatabase(Song song)
|
||||||
|
{
|
||||||
|
if (!(_artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(song.Artist)) != null))
|
||||||
|
{
|
||||||
|
_logger.Info("Cannot delete the artist record because it does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var artist = _artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(song.Artist));
|
||||||
|
|
||||||
|
if (SongsOfArtist(artist!) <= 1)
|
||||||
|
{
|
||||||
|
_artistContext!.Remove(artist!);
|
||||||
|
_artistContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SongsOfArtist(Artist artist)
|
||||||
|
{
|
||||||
|
var sngContext = new SongContext(_connectionString!);
|
||||||
|
var songs = sngContext.Songs!.Where(sng => sng.ArtistId == artist.Id).ToList();
|
||||||
|
|
||||||
|
return songs.Count;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
public class BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
protected static Logger _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
||||||
|
protected IConfiguration? _config;
|
||||||
|
protected string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
using Icarus.Constants;
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
public class CoverArtManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _rootCoverArtPath;
|
||||||
|
private CoverArtContext? _coverArtContext;
|
||||||
|
private byte[]? _stockCoverArt = null;
|
||||||
|
private const string? _filename = "CoverArt.png";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public CoverArtManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_rootCoverArtPath = _config.GetValue<string>("CoverArtPath");
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public void SaveCoverArtToDatabase(ref Song song, ref CoverArt coverArt)
|
||||||
|
{
|
||||||
|
_logger.Info("Saving cover art record to the database");
|
||||||
|
_coverArtContext!.Add(coverArt);
|
||||||
|
_coverArtContext.SaveChanges();
|
||||||
|
|
||||||
|
song.CoverArtId = coverArt.Id;
|
||||||
|
}
|
||||||
|
public void DeleteCoverArtFromDatabase(CoverArt coverArt)
|
||||||
|
{
|
||||||
|
_logger.Info("Attempting to delete cover art from the database");
|
||||||
|
|
||||||
|
_coverArtContext!.Attach(coverArt);
|
||||||
|
_coverArtContext.Remove(coverArt);
|
||||||
|
_coverArtContext.SaveChanges();
|
||||||
|
}
|
||||||
|
public void DeleteCoverArt(CoverArt coverArt)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stockCoverArtPath = _rootCoverArtPath + _filename;
|
||||||
|
if (!string.Equals(stockCoverArtPath, coverArt.ImagePath(),
|
||||||
|
StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.Info("Song does not contain the stock cover art");
|
||||||
|
File.Delete(coverArt.ImagePath());
|
||||||
|
_logger.Info("Cover art deleted from the filesystem");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Song contains the stock cover art");
|
||||||
|
_logger.Info("Will not delete from from the filesystem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverArt? SaveCoverArt(Song song)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dirMgr = new DirectoryManager(_rootCoverArtPath!);
|
||||||
|
var defaultExtension = ".png";
|
||||||
|
dirMgr.CreateDirectory(song);
|
||||||
|
|
||||||
|
var coverArt = new CoverArt
|
||||||
|
{
|
||||||
|
SongTitle = song.Title!
|
||||||
|
};
|
||||||
|
|
||||||
|
var segment = coverArt.GenerateFilename(0);
|
||||||
|
coverArt.Directory = dirMgr.SongDirectory;
|
||||||
|
coverArt.Filename = segment + defaultExtension;
|
||||||
|
|
||||||
|
var metaData = new MetadataRetriever();
|
||||||
|
var imgBytes = metaData.RetrieveCoverArtBytes(song);
|
||||||
|
|
||||||
|
if (imgBytes != null)
|
||||||
|
{
|
||||||
|
_logger.Info("Saving cover art to the filesystem");
|
||||||
|
File.WriteAllBytes(coverArt.ImagePath(), imgBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Song has no cover art, applying stock cover art");
|
||||||
|
|
||||||
|
var coverArtFilePath = _rootCoverArtPath + $"{segment}{defaultExtension}";
|
||||||
|
coverArt.Directory = DirectoryPaths.CoverArtDirectory;
|
||||||
|
coverArt.Filename = DirectoryPaths.CoverArtFilename;
|
||||||
|
metaData.UpdateCoverArt(song, coverArt);
|
||||||
|
coverArt.Directory = this._rootCoverArtPath;
|
||||||
|
coverArt.Filename = $"{segment}{defaultExtension}";
|
||||||
|
File.WriteAllBytes(coverArt.ImagePath(), _stockCoverArt!);
|
||||||
|
}
|
||||||
|
|
||||||
|
coverArt.Type = metaData.CoverArtFileExtensionType(coverArt);
|
||||||
|
if (string.IsNullOrEmpty(coverArt.Type))
|
||||||
|
{
|
||||||
|
Console.WriteLine("File type is empty");
|
||||||
|
Console.WriteLine($"Directory: {coverArt.Directory}");
|
||||||
|
Console.WriteLine($"Filename: {coverArt.Filename}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return coverArt;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverArt SaveCoverArt(IFormFile data, Song song)
|
||||||
|
{
|
||||||
|
var cover = new CoverArt { SongTitle = song.Title };
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MetadataRetriever metaData = new MetadataRetriever();
|
||||||
|
var dirMgr = new DirectoryManager(_rootCoverArtPath!);
|
||||||
|
cover.Type = metaData.FileExtensionType(data);
|
||||||
|
var defaultExtension = "." + cover.Type;
|
||||||
|
dirMgr.CreateDirectory(song);
|
||||||
|
|
||||||
|
var segment = cover.GenerateFilename(0);
|
||||||
|
var imagePath = dirMgr.SongDirectory + segment + defaultExtension;
|
||||||
|
|
||||||
|
cover.Directory = dirMgr.SongDirectory;
|
||||||
|
cover.Filename = segment + defaultExtension;
|
||||||
|
|
||||||
|
using (var fileStream = new FileStream(cover.ImagePath(), FileMode.Create))
|
||||||
|
{
|
||||||
|
data.CopyTo(fileStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex.Message, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverArt GetCoverArt(Song song)
|
||||||
|
{
|
||||||
|
var title = song.Title;
|
||||||
|
var cov = _coverArtContext!.CoverArtImages!.FirstOrDefault(cov => cov.SongTitle!.Equals(title));
|
||||||
|
return cov!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
_coverArtContext = new CoverArtContext(_connectionString!);
|
||||||
|
var path = DirectoryPaths.CoverArtDirectory + DirectoryPaths.CoverArtFilename;
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(path))
|
||||||
|
_stockCoverArt = File.ReadAllBytes(path);
|
||||||
|
|
||||||
|
if (!File.Exists(_rootCoverArtPath + _filename))
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(_rootCoverArtPath + _filename,
|
||||||
|
_stockCoverArt!);
|
||||||
|
Console.WriteLine("Copied Stock Cover Art");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Types;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
// NOTE: Do not use metadata for the song's metadata
|
||||||
|
public class DirectoryManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private Song? _song;
|
||||||
|
private string? _rootSongDirectory;
|
||||||
|
private string? _songDirectory;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public string? SongDirectory
|
||||||
|
{
|
||||||
|
get => _songDirectory;
|
||||||
|
set => _songDirectory = value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public DirectoryManager(IConfiguration config, Song song)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_song = song;
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
public DirectoryManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
public DirectoryManager(string rootDirectory)
|
||||||
|
{
|
||||||
|
_rootSongDirectory = rootDirectory;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
// Does not include extension
|
||||||
|
public static string GenerateFilename(int length)
|
||||||
|
{
|
||||||
|
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
|
||||||
|
var random = new Random();
|
||||||
|
return new string(Enumerable.Repeat(chars, length).Select(s =>
|
||||||
|
s[random.Next(s.Length)]).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateDownloadFilename(int length, string extension, string title, bool? randomize)
|
||||||
|
{
|
||||||
|
if (randomize.HasValue && randomize.Value)
|
||||||
|
{
|
||||||
|
return GenerateFilename(length) + extension;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return title + extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateDirectory()
|
||||||
|
{
|
||||||
|
this.CreateDirectory(_song!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateDirectory(Song song)
|
||||||
|
{
|
||||||
|
this._song = song;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_songDirectory = AlbumDirectory();
|
||||||
|
|
||||||
|
if (!Directory.Exists(_songDirectory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(_songDirectory);
|
||||||
|
Console.WriteLine($"The directory has been created");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"The song will be saved in the following" +
|
||||||
|
$" directory: {_songDirectory}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int DeleteEmptyDirectories(string? directory, int level)
|
||||||
|
{
|
||||||
|
var deleted = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var curDir = directory;
|
||||||
|
for (var i = 0; i < level; i++)
|
||||||
|
{
|
||||||
|
if (!System.IO.Directory.Exists(curDir))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.IsDirectoryEmpty(curDir))
|
||||||
|
{
|
||||||
|
System.IO.Directory.Delete(curDir);
|
||||||
|
deleted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentDirectory = System.IO.Directory.GetParent(curDir);
|
||||||
|
|
||||||
|
curDir = parentDirectory!.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred {exMsg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteEmptyDirectories(Song song)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var albumDirectory = AlbumDirectory(song);
|
||||||
|
var artistDirectory = ArtistDirectory(song);
|
||||||
|
|
||||||
|
if (Directory.Exists(albumDirectory) && IsDirectoryEmpty(albumDirectory))
|
||||||
|
{
|
||||||
|
Directory.Delete(albumDirectory);
|
||||||
|
_logger.Info("Album directory deleted");
|
||||||
|
}
|
||||||
|
if (Directory.Exists(artistDirectory) && IsDirectoryEmpty(artistDirectory))
|
||||||
|
{
|
||||||
|
Directory.Delete(artistDirectory);
|
||||||
|
_logger.Info("Artist directory deleted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void Initialize(DirectoryType dirTypes = DirectoryType.Music)
|
||||||
|
{
|
||||||
|
switch (dirTypes)
|
||||||
|
{
|
||||||
|
case DirectoryType.Music:
|
||||||
|
_rootSongDirectory = _config!.GetValue<string>("RootMusicPath")!;
|
||||||
|
break;
|
||||||
|
case DirectoryType.CoverArt:
|
||||||
|
_rootSongDirectory = _config!.GetValue<string>("CoverArtPath")!;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsDirectoryEmpty(string path) =>
|
||||||
|
!(Directory.EnumerateFileSystemEntries(path).Any());
|
||||||
|
|
||||||
|
private string AlbumDirectory()
|
||||||
|
{
|
||||||
|
return AlbumDirectory(_song!);
|
||||||
|
}
|
||||||
|
private string AlbumDirectory(Song song)
|
||||||
|
{
|
||||||
|
var directory = ArtistDirectory(song);
|
||||||
|
var segment = SerializeValue(song.AlbumTitle!);
|
||||||
|
directory += $@"{segment}/";
|
||||||
|
Console.WriteLine($"Album directory {directory}");
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
private string ArtistDirectory(Song song)
|
||||||
|
{
|
||||||
|
var directory = _rootSongDirectory;
|
||||||
|
var segment = SerializeValue(song.Artist!);
|
||||||
|
directory += $@"{segment}/";
|
||||||
|
Console.WriteLine($"Artist directory {directory}");
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SerializeValue(string value)
|
||||||
|
{
|
||||||
|
const int length = 15;
|
||||||
|
const string chars = "ABCDEF0123456789";
|
||||||
|
var random = new Random();
|
||||||
|
var output = new string(Enumerable.Repeat(chars, length).Select(s =>
|
||||||
|
s[random.Next(s.Length)]).ToArray());
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
public class GenreManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private GenreContext? _genreContext;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public GenreManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_genreContext = new GenreContext(_connectionString!);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public void SaveGenreToDatabase(ref Song song)
|
||||||
|
{
|
||||||
|
_logger.Info("Starting process to save the genre record of the song to the database");
|
||||||
|
|
||||||
|
var genre = new Genre
|
||||||
|
{
|
||||||
|
GenreName = song.Genre,
|
||||||
|
SongCount = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
var genreName = song.Genre;
|
||||||
|
var genreRetrieved = _genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(genreName));
|
||||||
|
|
||||||
|
if (genreRetrieved == null)
|
||||||
|
{
|
||||||
|
_genreContext.Add(genre);
|
||||||
|
_genreContext.SaveChanges();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genre.Id = genreRetrieved.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
song.GenreId = genre.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Genre UpdateGenreInDatabase(Song oldSongRecord, Song newSongRecord)
|
||||||
|
{
|
||||||
|
var oldGenreRecord = _genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldSongRecord.Genre));
|
||||||
|
var oldGenreName = oldGenreRecord!.GenreName;
|
||||||
|
var newGenreName = newSongRecord.Genre;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(newGenreName) || oldGenreName!.Equals(newGenreName))
|
||||||
|
{
|
||||||
|
_logger.Info("No change to the song's Genre");
|
||||||
|
return oldGenreRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Change to the song's genre found");
|
||||||
|
|
||||||
|
if (oldGenreRecord.SongCount <= 1)
|
||||||
|
{
|
||||||
|
_logger.Info("Deleting genre record");
|
||||||
|
|
||||||
|
_genreContext.Remove(oldGenreRecord);
|
||||||
|
_genreContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(_genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldSongRecord.Genre)) != null))
|
||||||
|
{
|
||||||
|
_logger.Info("Creating new genre record");
|
||||||
|
|
||||||
|
var newGenreRecord = new Genre
|
||||||
|
{
|
||||||
|
GenreName = newGenreName
|
||||||
|
};
|
||||||
|
|
||||||
|
_genreContext.Add(newGenreRecord);
|
||||||
|
_genreContext.SaveChanges();
|
||||||
|
|
||||||
|
return newGenreRecord;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Info("Updating existing genre record");
|
||||||
|
|
||||||
|
var existingGenreRecord = _genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldGenreRecord.GenreName));
|
||||||
|
|
||||||
|
_genreContext.Update(existingGenreRecord!);
|
||||||
|
_genreContext.SaveChanges();
|
||||||
|
|
||||||
|
return existingGenreRecord!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteGenreFromDatabase(Song song)
|
||||||
|
{
|
||||||
|
if (!(_genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(song.Genre)) != null))
|
||||||
|
{
|
||||||
|
_logger.Info("Cannot delete the genre record because it does not exist");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var genre = _genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(song.Genre));
|
||||||
|
|
||||||
|
if (SongsInGenre(genre!) <= 1)
|
||||||
|
{
|
||||||
|
_genreContext.Remove(genre!);
|
||||||
|
_genreContext.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SongsInGenre(Genre genre)
|
||||||
|
{
|
||||||
|
var sngContext = new SongContext(_connectionString!);
|
||||||
|
var songs = sngContext.Songs!.Where(sng => sng.GenreId == genre.Id).ToList();
|
||||||
|
|
||||||
|
return songs.Count;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,479 @@
|
|||||||
|
using NLog;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
|
||||||
|
public class SongManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _tempDirectoryRoot;
|
||||||
|
private string? _archiveDirectoryRoot;
|
||||||
|
private string? _compressedSongFilename;
|
||||||
|
private string? _message;
|
||||||
|
private SongContext? _songContext;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public string? ArchiveDirectoryRoot
|
||||||
|
{
|
||||||
|
get => _archiveDirectoryRoot;
|
||||||
|
set => _archiveDirectoryRoot = value;
|
||||||
|
}
|
||||||
|
public string? CompressedSongFilename
|
||||||
|
{
|
||||||
|
get => _compressedSongFilename;
|
||||||
|
set => _compressedSongFilename = value;
|
||||||
|
}
|
||||||
|
public string? Message
|
||||||
|
{
|
||||||
|
get => _message;
|
||||||
|
set => _message = value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public SongManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
public SongManager(IConfiguration config, string tempDirectoryRoot)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_tempDirectoryRoot = tempDirectoryRoot;
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public SongResult UpdateSong(Song song)
|
||||||
|
{
|
||||||
|
var result = new SongResult();
|
||||||
|
if (!DoesSongExist(song))
|
||||||
|
{
|
||||||
|
result.SongTitle = song.Title;
|
||||||
|
result.Message = "Song does not exist";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oldSongRecord = _songContext!.RetrieveRecord(song);
|
||||||
|
song.Filename = oldSongRecord.Filename;
|
||||||
|
song.SongDirectory = oldSongRecord.SongDirectory;
|
||||||
|
|
||||||
|
MetadataRetriever updateMetadata = new MetadataRetriever();
|
||||||
|
updateMetadata.UpdateMetadata(song, oldSongRecord);
|
||||||
|
|
||||||
|
var updatedSong = updateMetadata.UpdatedSongRecord;
|
||||||
|
|
||||||
|
var albMgr = new AlbumManager(_config!);
|
||||||
|
var gnrMgr = new GenreManager(_config!);
|
||||||
|
var artMgr = new ArtistManager(_config!);
|
||||||
|
var updatedAlbum = albMgr.UpdateAlbumInDatabase(oldSongRecord, updatedSong!);
|
||||||
|
oldSongRecord.AlbumId = updatedAlbum.Id;
|
||||||
|
|
||||||
|
var updatedArtist = artMgr.UpdateArtistInDatabase(oldSongRecord, updatedSong!);
|
||||||
|
oldSongRecord.ArtistId = updatedArtist.Id;
|
||||||
|
|
||||||
|
var updatedGenre = gnrMgr.UpdateGenreInDatabase(oldSongRecord, updatedSong!);
|
||||||
|
oldSongRecord.GenreId = updatedGenre.Id;
|
||||||
|
|
||||||
|
UpdateSongInDatabase(ref oldSongRecord, ref updatedSong!, ref result);
|
||||||
|
|
||||||
|
DeleteEmptyDirectories(ref oldSongRecord, ref updatedSong);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
|
||||||
|
result.Message = $"An error occurred: {msg}";
|
||||||
|
result.SongTitle = song.Title;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteSongFromFileSystem(Song songMetaData)
|
||||||
|
{
|
||||||
|
bool successful = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var songPath = songMetaData.SongPath();
|
||||||
|
System.IO.File.Delete(songPath);
|
||||||
|
successful = !System.IO.File.Exists(songPath);
|
||||||
|
if (successful)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Song successfully deleted");
|
||||||
|
}
|
||||||
|
DirectoryManager dirMgr = new DirectoryManager(_config!, songMetaData);
|
||||||
|
var deletedAmount = dirMgr.DeleteEmptyDirectories(songMetaData.SongDirectory, 1);
|
||||||
|
if (deletedAmount > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{deletedAmount} directories deleted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DoesSongExist(Song song)
|
||||||
|
{
|
||||||
|
if (!_songContext!.DoesRecordExist(song))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public void DeleteSong(Song song)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (DeleteSongFromFilesystem(song, true))
|
||||||
|
{
|
||||||
|
_logger.Error("Failed to delete the song");
|
||||||
|
|
||||||
|
throw new Exception("Failed to delete the song");
|
||||||
|
}
|
||||||
|
_logger.Info("Song deleted from the filesystem");
|
||||||
|
|
||||||
|
var coverMgr = new CoverArtManager(_config!);
|
||||||
|
|
||||||
|
var coverArt = coverMgr.GetCoverArt(song);
|
||||||
|
coverMgr.DeleteCoverArt(coverArt);
|
||||||
|
|
||||||
|
DeleteSongFromDatabase(song);
|
||||||
|
coverMgr.DeleteCoverArtFromDatabase(coverArt);
|
||||||
|
var accessLevelContext = new AccessLevelContext(_config!.GetConnectionString("DefaultConnection")!);
|
||||||
|
var accessLevel = accessLevelContext.AccessLevels!.FirstOrDefault(al => al.SongId == song.Id);
|
||||||
|
accessLevelContext.AccessLevels!.Remove(accessLevel!);
|
||||||
|
accessLevelContext.SaveChanges();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Song SaveFlacSongToFileSystem(IFormFile songFile, IFormFile coverArtData, Song song)
|
||||||
|
{
|
||||||
|
// Save temp song (Should already be saved to the filesystem by the time it gets to this method)
|
||||||
|
// Save cover art
|
||||||
|
// Update the song's metadata with the song object
|
||||||
|
// Save song to its final directory
|
||||||
|
// Save cover art to the database
|
||||||
|
// Save song to the database
|
||||||
|
|
||||||
|
var coverMgr = new CoverArtManager(_config!);
|
||||||
|
var coverArt = coverMgr.SaveCoverArt(coverArtData, song);
|
||||||
|
|
||||||
|
var meta = new Utilities.MetadataRetriever();
|
||||||
|
meta.UpdateMetadata(song, song);
|
||||||
|
|
||||||
|
DirectoryManager dirMgr = new DirectoryManager(_config!, song);
|
||||||
|
dirMgr.CreateDirectory();
|
||||||
|
|
||||||
|
var tempPath = song.SongPath();
|
||||||
|
|
||||||
|
song.SongDirectory = dirMgr.SongDirectory;
|
||||||
|
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.FLAC);
|
||||||
|
|
||||||
|
var filePath = song.SongPath();
|
||||||
|
_logger.Info($"Absolute song path: {filePath}");
|
||||||
|
|
||||||
|
this.MoveSongToFinalDestination(tempPath, filePath);
|
||||||
|
|
||||||
|
SaveSongToDatabase(song, coverArt);
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveSongToFinalDestination(string sourcePath, string targetPath)
|
||||||
|
{
|
||||||
|
using (var fileStream = new FileStream(targetPath, FileMode.Create))
|
||||||
|
{
|
||||||
|
var songBytes = System.IO.File.ReadAllBytes(sourcePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(sourcePath) && System.IO.File.Exists(sourcePath) && fileStream.Length > 0)
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(sourcePath);
|
||||||
|
_logger.Info("Deleted temp song from filesystem: {0}", sourcePath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileStream.Write(songBytes, 0, songBytes.Count());
|
||||||
|
_logger.Info("Saved song to filesystem: {0}", targetPath);
|
||||||
|
|
||||||
|
System.IO.File.Delete(sourcePath);
|
||||||
|
_logger.Info("Deleted temp song from filesystem: {0}", sourcePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error($"An error occurred: {msg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Song successfully saved to filesystem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SongData> RetrieveSong(Song songMetaData)
|
||||||
|
{
|
||||||
|
var song = new SongData();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fetching song from filesystem");
|
||||||
|
song = await RetrieveSongFromFileSystem(songMetaData);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred: {exMsg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<SongData> RetrieveSongFromFileSystem(Song details)
|
||||||
|
{
|
||||||
|
byte[] uncompressedSong = await System.IO.File.ReadAllBytesAsync(details.SongPath());
|
||||||
|
|
||||||
|
return new SongData
|
||||||
|
{
|
||||||
|
Data = uncompressedSong
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public async Task<Song> SaveSongTemp(IFormFile songFile)
|
||||||
|
{
|
||||||
|
_logger.Info("Assigning song filename");
|
||||||
|
var song = new Song { SongDirectory = this._tempDirectoryRoot! };
|
||||||
|
var filename = await song.GenerateFilenameAsync(false) + "-" + songFile.FileName;
|
||||||
|
song.Filename = filename;
|
||||||
|
var songPath = song.SongPath();
|
||||||
|
|
||||||
|
using (var filestream = new FileStream(songPath, FileMode.Create))
|
||||||
|
{
|
||||||
|
_logger.Info("Saving temp song: {0}", songPath);
|
||||||
|
await songFile.CopyToAsync(filestream);
|
||||||
|
}
|
||||||
|
|
||||||
|
song.DateCreated = DateTime.Now;
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Icarus.Models.CreateFileResult Create(IFormFile file, string filePath, string prompt)
|
||||||
|
{
|
||||||
|
if (System.IO.File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return CreateFileResult.AlreadyExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var filestream = new FileStream(filePath, FileMode.Create))
|
||||||
|
{
|
||||||
|
Console.WriteLine(prompt);
|
||||||
|
file.CopyTo(filestream);
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return CreateFileResult.FileCreatedAndExists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool SongRecordChanged(Song currentSong, Song songUpdates)
|
||||||
|
{
|
||||||
|
var currentTitle = currentSong.Title;
|
||||||
|
var currentArtist = currentSong.Artist;
|
||||||
|
var currentAlbum = currentSong.AlbumTitle;
|
||||||
|
var currentGenre = currentSong.Genre;
|
||||||
|
var currentYear = currentSong.Year;
|
||||||
|
|
||||||
|
if (!currentTitle!.Equals(songUpdates.Title) || !currentArtist!.Equals(songUpdates.Artist) ||
|
||||||
|
!currentAlbum!.Equals(songUpdates.AlbumTitle) ||
|
||||||
|
!currentGenre!.Equals(songUpdates.Genre) || currentYear != songUpdates.Year)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteEmptyDirectories(ref Song oldSong, ref Song updatedSong)
|
||||||
|
{
|
||||||
|
DirectoryManager mgr = new DirectoryManager(_config!);
|
||||||
|
|
||||||
|
_logger.Info("Checking to see if there are any directories to delete");
|
||||||
|
mgr.DeleteEmptyDirectories(oldSong);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_connectionString = _config!.GetConnectionString("DefaultConnection");
|
||||||
|
_songContext = new SongContext(_connectionString!);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error Occurred: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void SaveSongToDatabase(Song song, CoverArt? cover)
|
||||||
|
{
|
||||||
|
_logger.Info("Starting process to save the song to the database");
|
||||||
|
|
||||||
|
var albumMgr = new AlbumManager(this._config!);
|
||||||
|
var artistMgr = new ArtistManager(this._config!);
|
||||||
|
var genreMgr = new GenreManager(this._config!);
|
||||||
|
var coverMgr = new CoverArtManager(this._config!);
|
||||||
|
albumMgr.SaveAlbumToDatabase(ref song);
|
||||||
|
artistMgr.SaveArtistToDatabase(ref song);
|
||||||
|
genreMgr.SaveGenreToDatabase(ref song);
|
||||||
|
|
||||||
|
var info = "Saving Song to DB";
|
||||||
|
_logger.Info(info);
|
||||||
|
|
||||||
|
this._songContext!.Add(song);
|
||||||
|
this._songContext!.SaveChanges();
|
||||||
|
|
||||||
|
if (cover != null)
|
||||||
|
{
|
||||||
|
coverMgr.SaveCoverArtToDatabase(ref song, ref cover!);
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessLevel = Icarus.Models.AccessLevel.DefaultLevel();
|
||||||
|
accessLevel.SongId = song.Id;
|
||||||
|
|
||||||
|
var accessLevelContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
accessLevelContext.Add(accessLevel);
|
||||||
|
accessLevelContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool DeleteSongFromFilesystem(Song song, bool deleteDirectory = false)
|
||||||
|
{
|
||||||
|
var songPath = song.SongPath();
|
||||||
|
|
||||||
|
_logger.Info("Deleting song from the filesystem");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.IO.File.Delete(songPath);
|
||||||
|
|
||||||
|
DeleteEmptyDirectories(ref song, ref song);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred when attempting to delete the song from the filesystem");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoesSongExistOnFilesystem(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DoesSongExistOnFilesystem(Song song)
|
||||||
|
{
|
||||||
|
if (!System.IO.File.Exists(song.SongPath()))
|
||||||
|
{
|
||||||
|
_logger.Info("Song does not exist on the filesystem");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Song exists on the filesystem");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void UpdateSongInDatabase(ref Song oldSongRecord, ref Song newSongRecord, ref SongResult result)
|
||||||
|
{
|
||||||
|
var updatedSongRecord = oldSongRecord;
|
||||||
|
|
||||||
|
var songContext = new SongContext(_connectionString!);
|
||||||
|
|
||||||
|
if (!SongRecordChanged(oldSongRecord, newSongRecord))
|
||||||
|
{
|
||||||
|
_logger.Info("No change to the song record");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Changes to song record found");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(newSongRecord.Title))
|
||||||
|
updatedSongRecord.Title = newSongRecord.Title;
|
||||||
|
if (!string.IsNullOrEmpty(newSongRecord.AlbumTitle))
|
||||||
|
{
|
||||||
|
updatedSongRecord.AlbumTitle = newSongRecord.AlbumTitle;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(newSongRecord.Artist))
|
||||||
|
{
|
||||||
|
updatedSongRecord.Artist = newSongRecord.Artist;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(newSongRecord.Genre))
|
||||||
|
{
|
||||||
|
updatedSongRecord.Genre = newSongRecord.Genre;
|
||||||
|
Console.WriteLine("Genre changed");
|
||||||
|
Console.WriteLine($"{updatedSongRecord.Genre} {newSongRecord.Genre}");
|
||||||
|
}
|
||||||
|
if (newSongRecord.Year != null || newSongRecord.Year > 0)
|
||||||
|
updatedSongRecord.Year = newSongRecord.Year;
|
||||||
|
|
||||||
|
_logger.Info("Applied changes to song record");
|
||||||
|
|
||||||
|
|
||||||
|
_logger.Info("Saving song metadata to the database");
|
||||||
|
|
||||||
|
songContext.Update(updatedSongRecord);
|
||||||
|
songContext.SaveChanges();
|
||||||
|
|
||||||
|
newSongRecord = updatedSongRecord;
|
||||||
|
|
||||||
|
result.Message = "Successfully updated song";
|
||||||
|
result.SongTitle = updatedSongRecord.Title!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteSongFromDatabase(Song song)
|
||||||
|
{
|
||||||
|
_logger.Info("Starting process to delete records related to the song from the database");
|
||||||
|
|
||||||
|
var albumMgr = new AlbumManager(_config!);
|
||||||
|
var artistMgr = new ArtistManager(_config!);
|
||||||
|
var genreMgr = new GenreManager(_config!);
|
||||||
|
var sngContext = new SongContext(_connectionString!);
|
||||||
|
sngContext.Songs!.Remove(song);
|
||||||
|
sngContext.SaveChanges();
|
||||||
|
artistMgr.DeleteArtistFromDatabase(song);
|
||||||
|
albumMgr.DeleteAlbumFromDatabase(song);
|
||||||
|
genreMgr.DeleteGenreFromDatabase(song);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
using Microsoft.VisualBasic;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
#region Classes
|
||||||
|
public class TokenManager : BaseManager
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _clientId;
|
||||||
|
private string? _clientSecret;
|
||||||
|
private string? _privateKeyPath = string.Empty;
|
||||||
|
private string? _privateKey = string.Empty;
|
||||||
|
private string? _publicKeyPath = string.Empty;
|
||||||
|
private string? _publicKey = string.Empty;
|
||||||
|
private string? _audience;
|
||||||
|
private string? _grantType;
|
||||||
|
private string? _url;
|
||||||
|
private string? SUCCESSFUL_TOKEN_MESSAGE = "Successfully retrieved token";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public TokenManager(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
InitializeValues();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public LoginResult RetrieveLoginResult(User user)
|
||||||
|
{
|
||||||
|
_logger.Info("Preparing Auth0 API request");
|
||||||
|
|
||||||
|
var client = new RestClient(_url!);
|
||||||
|
var request = new RestRequest("oauth/token", Method.POST);
|
||||||
|
var tokenRequest = RetrieveTokenRequest();
|
||||||
|
|
||||||
|
_logger.Info("Serializing token object into JSON");
|
||||||
|
var tokenObject = JsonConvert.SerializeObject(tokenRequest);
|
||||||
|
|
||||||
|
request.AddParameter("application/json; charset=utf-8",
|
||||||
|
tokenObject, ParameterType.RequestBody);
|
||||||
|
|
||||||
|
request.RequestFormat = DataFormat.Json;
|
||||||
|
|
||||||
|
_logger.Info("Sending request");
|
||||||
|
IRestResponse response = client.Execute(request);
|
||||||
|
_logger.Info("Response received");
|
||||||
|
|
||||||
|
|
||||||
|
_logger.Info("Deserializing response");
|
||||||
|
var tokenResult = JsonConvert
|
||||||
|
.DeserializeObject<TokenTierOne>(response.Content);
|
||||||
|
_logger.Info("Response deserialized");
|
||||||
|
|
||||||
|
return this.InitializeLoginResult(user, tokenResult!);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public LoginResult LoginSymmetric(User user)
|
||||||
|
{
|
||||||
|
var tokenResult = new TokenTierOne { TokenType = "JWT" };
|
||||||
|
|
||||||
|
var payload = Payload();
|
||||||
|
payload.Add(new Claim("user_id", user.Id.ToString(), ClaimValueTypes.Integer));
|
||||||
|
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var key = Encoding.ASCII.GetBytes(_config!["JWT:Secret"]!);
|
||||||
|
var tokenDescriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new ClaimsIdentity(new Claim[]
|
||||||
|
{
|
||||||
|
new Claim("user_id", user.Id.ToString(), ClaimValueTypes.Integer)
|
||||||
|
// Add more claims as needed
|
||||||
|
}),
|
||||||
|
Expires = DateTime.UtcNow.AddHours(1),
|
||||||
|
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
|
||||||
|
Issuer = _config["Jwt:Issuer"], // Add this line
|
||||||
|
Audience = _config["Jwt:Audience"]
|
||||||
|
};
|
||||||
|
|
||||||
|
tokenResult.AccessToken = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDescriptor));
|
||||||
|
|
||||||
|
var expClaim = payload.FirstOrDefault(cl =>
|
||||||
|
{
|
||||||
|
return cl.Type.Equals("exp");
|
||||||
|
});
|
||||||
|
|
||||||
|
var expiredDate = DateTime.Parse(expClaim!.Value);
|
||||||
|
var exp = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds);
|
||||||
|
tokenResult.Expiration = Convert.ToInt32(exp);
|
||||||
|
|
||||||
|
return this.InitializeLoginResult(user, tokenResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginResult InitializeLoginResult(User user, TokenTierOne token)
|
||||||
|
{
|
||||||
|
return new LoginResult
|
||||||
|
{
|
||||||
|
UserId = user.Id,
|
||||||
|
Username = user.Username,
|
||||||
|
Token = token.AccessToken,
|
||||||
|
TokenType = token.TokenType,
|
||||||
|
Expiration = token.Expiration,
|
||||||
|
Message = SUCCESSFUL_TOKEN_MESSAGE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAccessSong(string token, Song song, AccessLevel accessLevel)
|
||||||
|
{
|
||||||
|
if (accessLevel!.Level!.Equals(Models.AccessLevel.DefaultLevel().Level))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var tokenUserId = this.RetrieveUserIdFromToken(token);
|
||||||
|
if (tokenUserId == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenUserId.Value == song.UserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? GetBearerToken(HttpContext context)
|
||||||
|
{
|
||||||
|
string authorizationHeader = context.Request.Headers["Authorization"]!;
|
||||||
|
|
||||||
|
if (!authorizationHeader.IsNullOrEmpty() && authorizationHeader.StartsWith("Bearer", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string token = authorizationHeader.Substring("Bearer ".Length).Trim();
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid? RetrieveUserIdFromToken(string token)
|
||||||
|
{
|
||||||
|
var parsedToken = this.ContainsBearer(token) ? this.StripBearer(token) : token;
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var readTok = tokenHandler.ReadJwtToken(parsedToken);
|
||||||
|
|
||||||
|
foreach (var item in readTok.Payload)
|
||||||
|
{
|
||||||
|
if (item.Key == "user_id")
|
||||||
|
{
|
||||||
|
if (item.Value != null)
|
||||||
|
{
|
||||||
|
var id = item.Value.ToString();
|
||||||
|
return Guid.Parse(id!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string StripBearer(string token)
|
||||||
|
{
|
||||||
|
var start = 6;
|
||||||
|
var strippedToken = token.Substring(start);
|
||||||
|
|
||||||
|
return Strings.Trim(strippedToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsBearer(string token)
|
||||||
|
{
|
||||||
|
return token.Contains("Bearer");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string AllScopes()
|
||||||
|
{
|
||||||
|
var allScopes = new List<String>()
|
||||||
|
{
|
||||||
|
"download:songs",
|
||||||
|
"read:song_details",
|
||||||
|
"upload:songs",
|
||||||
|
"delete:songs",
|
||||||
|
"read:albums",
|
||||||
|
"read:artists",
|
||||||
|
"update:songs",
|
||||||
|
"stream:songs",
|
||||||
|
"read:genre",
|
||||||
|
"read:year",
|
||||||
|
"download:cover_art"
|
||||||
|
};
|
||||||
|
|
||||||
|
var scopes = string.Empty;
|
||||||
|
|
||||||
|
for (var i = 0; i < allScopes.Count; i++)
|
||||||
|
{
|
||||||
|
if (i == allScopes.Count - 1)
|
||||||
|
{
|
||||||
|
scopes += allScopes[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scopes += allScopes[i] + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Claim> Payload()
|
||||||
|
{
|
||||||
|
// TODO: Remove this hard coding
|
||||||
|
var expLimit = 30;
|
||||||
|
var currentDate = DateTime.Now;
|
||||||
|
var expiredDate = currentDate.AddMinutes(expLimit);
|
||||||
|
var issuer = "http://localhost:5002";
|
||||||
|
var audience = "http://localhost:5002";
|
||||||
|
var subject = _config!["JWT:Subject"];
|
||||||
|
|
||||||
|
var claim = new List<System.Security.Claims.Claim>()
|
||||||
|
{
|
||||||
|
new Claim("scope", AllScopes(), "string"),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Exp, expiredDate.ToString()),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Aud, audience),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Iss, issuer),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Sub, subject!),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Iat, currentDate.ToString())
|
||||||
|
};
|
||||||
|
|
||||||
|
return claim;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Deprecated function")]
|
||||||
|
private async Task<string> ReadKeyContent(string filepath)
|
||||||
|
{
|
||||||
|
return await System.IO.File.ReadAllTextAsync(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TokenRequest RetrieveTokenRequest()
|
||||||
|
{
|
||||||
|
_logger.Info("Retrieving token object");
|
||||||
|
|
||||||
|
return new TokenRequest
|
||||||
|
{
|
||||||
|
ClientId = _clientId,
|
||||||
|
ClientSecret = _clientSecret,
|
||||||
|
Audience = _audience,
|
||||||
|
GrantType = _grantType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeValues()
|
||||||
|
{
|
||||||
|
_logger.Info("Analyzing Auth0 information");
|
||||||
|
|
||||||
|
_clientId = _config!["Auth0:ClientId"];
|
||||||
|
_clientSecret = _config["Auth0:ClientSecret"];
|
||||||
|
_audience = _config["Auth0:ApiIdentifier"];
|
||||||
|
_grantType = "client_credentials";
|
||||||
|
_url = $"https://{_config["Auth0:Domain"]}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Testing Methods
|
||||||
|
// For testing purposes
|
||||||
|
private void PrintCredentials()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Auth0 credentials:");
|
||||||
|
Console.WriteLine($"Client Id: {_clientId}");
|
||||||
|
Console.WriteLine($"Client Secret: {_clientSecret}");
|
||||||
|
Console.WriteLine($"Audience: {_audience}");
|
||||||
|
Console.WriteLine($"Url: {_url}");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Classes
|
||||||
|
private class TokenRequest
|
||||||
|
{
|
||||||
|
[JsonProperty("client_id")]
|
||||||
|
public string? ClientId { get; set; }
|
||||||
|
[JsonProperty("client_secret")]
|
||||||
|
public string? ClientSecret { get; set; }
|
||||||
|
[JsonProperty("audience")]
|
||||||
|
public string? Audience { get; set; }
|
||||||
|
[JsonProperty("grant_type")]
|
||||||
|
public string? GrantType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TokenTierOne
|
||||||
|
{
|
||||||
|
[JsonProperty("access_token")]
|
||||||
|
public string? AccessToken { get; set; }
|
||||||
|
[JsonProperty("expires_in")]
|
||||||
|
public int Expiration { get; set; }
|
||||||
|
[JsonProperty("token_type")]
|
||||||
|
public string? TokenType { get; set; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
using NLog;
|
||||||
|
using TagLib;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Utilities;
|
||||||
|
|
||||||
|
public class MetadataRetriever
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private static NLog.Logger? _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
|
||||||
|
private List<string>? _supportedAudioFileTypes = new List<string> { "wav", "flac" };
|
||||||
|
private List<string>? _supportedImageFileTypes = new List<string> { "jpeg", "jpg", "png" };
|
||||||
|
private Song? _updatedSong;
|
||||||
|
private string? _message;
|
||||||
|
private string? _title;
|
||||||
|
private string? _artist;
|
||||||
|
private string? _album;
|
||||||
|
private string? _genre;
|
||||||
|
private int _year;
|
||||||
|
private int _duration;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public Song? UpdatedSongRecord
|
||||||
|
{
|
||||||
|
get => _updatedSong;
|
||||||
|
set => _updatedSong = value;
|
||||||
|
}
|
||||||
|
public string? Message
|
||||||
|
{
|
||||||
|
get => _message;
|
||||||
|
set => _message = value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public string CoverArtFileExtensionType(CoverArt cover)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Retrieving CoverArt file extension type");
|
||||||
|
|
||||||
|
using (var fileStream = System.IO.File.OpenRead(cover.ImagePath()))
|
||||||
|
{
|
||||||
|
var isRecognizableType = FileTypeChecker.FileTypeValidator.IsTypeRecognizable(fileStream);
|
||||||
|
|
||||||
|
if (!isRecognizableType)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileType = FileTypeChecker.FileTypeValidator.GetFileType(fileStream);
|
||||||
|
|
||||||
|
Console.WriteLine($"Filetype: {fileType}");
|
||||||
|
|
||||||
|
return fileType.Extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FileExtensionType(IFormFile file)
|
||||||
|
{
|
||||||
|
using (var fileStream = file.OpenReadStream())
|
||||||
|
{
|
||||||
|
var isRecognizableType = FileTypeChecker.FileTypeValidator.IsTypeRecognizable(fileStream);
|
||||||
|
|
||||||
|
if (!isRecognizableType)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var fileType = FileTypeChecker.FileTypeValidator.GetFileType(fileStream);
|
||||||
|
Console.WriteLine($"Filetype: {fileType}");
|
||||||
|
Console.WriteLine($"Extension: {fileType.Extension}");
|
||||||
|
|
||||||
|
return fileType.Extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FileExtensionType(string path)
|
||||||
|
{
|
||||||
|
var extensionRaw = System.IO.Path.GetExtension(path);
|
||||||
|
|
||||||
|
if (extensionRaw[0] == '.')
|
||||||
|
{
|
||||||
|
return extensionRaw.Substring(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return extensionRaw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSupportedFile(IFormFile file)
|
||||||
|
{
|
||||||
|
var supportedTypes = this._supportedAudioFileTypes;
|
||||||
|
this._supportedImageFileTypes!.ForEach(t =>
|
||||||
|
{
|
||||||
|
if (!supportedTypes!.Contains(t))
|
||||||
|
{
|
||||||
|
supportedTypes.Add(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var extensionType = this.FileExtensionType(file).ToLower();
|
||||||
|
|
||||||
|
return supportedTypes!.Contains(extensionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSupportedFile(string path)
|
||||||
|
{
|
||||||
|
var supportedTypes = this._supportedAudioFileTypes;
|
||||||
|
this._supportedImageFileTypes!.ForEach(t =>
|
||||||
|
{
|
||||||
|
if (!supportedTypes!.Contains(t))
|
||||||
|
{
|
||||||
|
supportedTypes.Add(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var extensionType = this.FileExtensionType(path).ToLower();
|
||||||
|
|
||||||
|
return supportedTypes!.Contains(extensionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Song RetrieveMetaData(string filePath)
|
||||||
|
{
|
||||||
|
Song song = new Song();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TagLib.File fileTag = TagLib.File.Create(filePath);
|
||||||
|
_title = fileTag.Tag.Title;
|
||||||
|
_artist = string.Join("", fileTag.Tag.Performers);
|
||||||
|
_album = fileTag.Tag.Album;
|
||||||
|
_genre = string.Join("", fileTag.Tag.Genres);
|
||||||
|
_year = (int)fileTag.Tag.Year;
|
||||||
|
_duration = (int)fileTag.Properties.Duration.TotalSeconds;
|
||||||
|
var albumArtist = string.Join("", fileTag.Tag.AlbumArtists);
|
||||||
|
var track = (int)fileTag.Tag.Track;
|
||||||
|
var disc = (int)fileTag.Tag.Disc;
|
||||||
|
|
||||||
|
song.Title = _title;
|
||||||
|
song.Artist = _artist;
|
||||||
|
song.AlbumTitle = _album;
|
||||||
|
song.AlbumArtist = albumArtist;
|
||||||
|
song.Genre = _genre;
|
||||||
|
song.Year = _year;
|
||||||
|
song.Duration = _duration;
|
||||||
|
song.Track = track;
|
||||||
|
song.Disc = disc;
|
||||||
|
song.TrackCount = (int)fileTag.Tag.TrackCount;
|
||||||
|
song.DiscCount = (int)fileTag.Tag.DiscCount;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
Console.WriteLine("An error occurred in MetadataRetriever");
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
_logger!.Error(msg, "An error occurred in MetadataRetriever");
|
||||||
|
}
|
||||||
|
|
||||||
|
return song;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RetrieveSongDuration(string filepath)
|
||||||
|
{
|
||||||
|
var fileTag = TagLib.File.Create(filepath);
|
||||||
|
var duration = (int)fileTag.Properties.Duration.TotalSeconds;
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] RetrieveCoverArtBytes(Song song)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine("Fetching image");
|
||||||
|
var tag = TagLib.File.Create(song.SongPath());
|
||||||
|
|
||||||
|
if (tag.Tag.Pictures.Count() == 0)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag.Tag.Pictures[0].Data.Data;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger!.Error(msg, "An error occurred in MetadataRetriever");
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void UpdateMetadata(Song updatedSong, Song oldSong)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InitializeUpdatedSong(oldSong);
|
||||||
|
var songValues = CheckSongValues(updatedSong);
|
||||||
|
PerformUpdate(updatedSong, songValues);
|
||||||
|
Message = "Successfully updated metadata";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred: {msg}");
|
||||||
|
_logger!.Error(msg, "An error occurred");
|
||||||
|
Message = "Failed to update metadata";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void UpdateCoverArt(Song song, CoverArt coverArt)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Updating song's cover art");
|
||||||
|
|
||||||
|
var tag = TagLib.File.Create(song.SongPath());
|
||||||
|
var pics = tag.Tag.Pictures;
|
||||||
|
Array.Resize(ref pics, 1);
|
||||||
|
|
||||||
|
pics[0] = new Picture(coverArt.ImagePath())
|
||||||
|
{
|
||||||
|
Description = "Cover Art"
|
||||||
|
};
|
||||||
|
|
||||||
|
tag.Tag.Pictures = pics;
|
||||||
|
tag.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PerformUpdate(Song updatedSong, SortedDictionary<string, bool> checkedValues)
|
||||||
|
{
|
||||||
|
var filePath = updatedSong.SongPath();
|
||||||
|
var title = updatedSong.Title;
|
||||||
|
var artist = updatedSong.Artist;
|
||||||
|
var album = updatedSong.AlbumTitle;
|
||||||
|
var genre = updatedSong.Genre;
|
||||||
|
var year = updatedSong.Year;
|
||||||
|
var albumArtist = updatedSong.AlbumArtist;
|
||||||
|
var track = updatedSong.Track;
|
||||||
|
var trackCount = updatedSong.TrackCount;
|
||||||
|
var disc = updatedSong.Disc;
|
||||||
|
var discCount = updatedSong.DiscCount;
|
||||||
|
TagLib.File fileTag = TagLib.File.Create(filePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Updating metadata of {title}");
|
||||||
|
_logger!.Info($"Updating metadata of {title}");
|
||||||
|
|
||||||
|
foreach (var key in checkedValues.Keys)
|
||||||
|
{
|
||||||
|
bool result = checkedValues[key];
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
switch (key.ToLower())
|
||||||
|
{
|
||||||
|
case "title":
|
||||||
|
_updatedSong!.Title = title;
|
||||||
|
fileTag.Tag.Title = title;
|
||||||
|
break;
|
||||||
|
case "artists":
|
||||||
|
_updatedSong!.Artist = artist;
|
||||||
|
fileTag.Tag.Performers = new[] { artist };
|
||||||
|
break;
|
||||||
|
case "album":
|
||||||
|
_updatedSong!.AlbumTitle = album;
|
||||||
|
fileTag.Tag.Album = album;
|
||||||
|
break;
|
||||||
|
case "genre":
|
||||||
|
_updatedSong!.Genre = genre;
|
||||||
|
fileTag.Tag.Genres = new[] { genre };
|
||||||
|
break;
|
||||||
|
case "year":
|
||||||
|
_updatedSong!.Year = year;
|
||||||
|
fileTag.Tag.Year = (uint)year!;
|
||||||
|
break;
|
||||||
|
case "albumartist":
|
||||||
|
_updatedSong!.AlbumArtist = albumArtist;
|
||||||
|
fileTag.Tag.AlbumArtists = new[] { albumArtist };
|
||||||
|
break;
|
||||||
|
case "track":
|
||||||
|
_updatedSong!.Track = track;
|
||||||
|
fileTag.Tag.Track = (uint)(track);
|
||||||
|
break;
|
||||||
|
case "trackcount":
|
||||||
|
_updatedSong!.TrackCount = trackCount;
|
||||||
|
fileTag.Tag.TrackCount = (uint)(trackCount);
|
||||||
|
break;
|
||||||
|
case "disc":
|
||||||
|
_updatedSong!.Disc = disc;
|
||||||
|
fileTag.Tag.Disc = (uint)(disc);
|
||||||
|
break;
|
||||||
|
case "disccount":
|
||||||
|
_updatedSong!.DiscCount = discCount;
|
||||||
|
fileTag.Tag.DiscCount = (uint)(discCount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileTag.Save();
|
||||||
|
|
||||||
|
Console.WriteLine("Successfully updated metadata");
|
||||||
|
_logger.Info("Successfully updated metadata");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred:\n{msg}");
|
||||||
|
_logger!.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void InitializeUpdatedSong(Song song)
|
||||||
|
{
|
||||||
|
_updatedSong = song;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SortedDictionary<string, bool> CheckSongValues(Song song)
|
||||||
|
{
|
||||||
|
var songValues = new SortedDictionary<string, bool>();
|
||||||
|
Console.WriteLine("Checking for null data");
|
||||||
|
_logger!.Info("Checking for null data");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
songValues["Title"] = String.IsNullOrEmpty(song.Title);
|
||||||
|
songValues["Artists"] = String.IsNullOrEmpty(song.Artist);
|
||||||
|
songValues["Album"] = String.IsNullOrEmpty(song.AlbumTitle);
|
||||||
|
songValues["Genre"] = String.IsNullOrEmpty(song.Genre);
|
||||||
|
songValues["AlbumArtist"] = String.IsNullOrEmpty(song.AlbumArtist);
|
||||||
|
|
||||||
|
songValues["Year"] = CheckIntField(song.Year);
|
||||||
|
songValues["Track"] = CheckIntField(song.Track);
|
||||||
|
songValues["TrackCount"] = CheckIntField(song.TrackCount);
|
||||||
|
songValues["Disc"] = CheckIntField(song.Disc);
|
||||||
|
songValues["DiscCount"] = CheckIntField(song.Disc);
|
||||||
|
|
||||||
|
Console.WriteLine("Checking for null data completed");
|
||||||
|
_logger.Info("Checking for null data completed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
Console.WriteLine($"An error occurred: \n{msg}");
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return songValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckIntField(int? value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (value == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
using BCrypt.Net;
|
||||||
|
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Utilities;
|
||||||
|
|
||||||
|
public class PasswordEncryption
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private static Logger _logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public bool VerifyPassword(User user, string password)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = BCrypt.Net.BCrypt.Verify(password, user.Password);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
_logger.Error(msg, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string HashPassword(User user)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string hashedPassword = string.Empty;
|
||||||
|
hashedPassword = BCrypt.Net.BCrypt.HashPassword(user.Password);
|
||||||
|
|
||||||
|
_logger.Info("Successfully hashed password");
|
||||||
|
|
||||||
|
return hashedPassword;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
_logger.Error(exMsg, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
string GenerateHash(string password, byte[] salt)
|
||||||
|
{
|
||||||
|
|
||||||
|
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
||||||
|
password: password, salt: salt,
|
||||||
|
prf: KeyDerivationPrf.HMACSHA1,
|
||||||
|
iterationCount: 10000,
|
||||||
|
numBytesRequested: 256 / 8));
|
||||||
|
|
||||||
|
return hashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] GenerateSalt()
|
||||||
|
{
|
||||||
|
byte[] salt = new byte[128 / 8];
|
||||||
|
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
rng.GetBytes(salt);
|
||||||
|
|
||||||
|
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.Utilities;
|
||||||
|
|
||||||
|
public class SongCompression
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
string? _compressedSongFilename;
|
||||||
|
string? _tempDirectory;
|
||||||
|
byte[]? _uncompressedSong;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Propterties
|
||||||
|
public string? CompressedSongFilename
|
||||||
|
{
|
||||||
|
get => _compressedSongFilename;
|
||||||
|
set => _compressedSongFilename = value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public SongCompression()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public SongCompression(string tempDirectory)
|
||||||
|
{
|
||||||
|
_tempDirectory = tempDirectory;
|
||||||
|
}
|
||||||
|
public SongCompression(byte[] uncompressedSong)
|
||||||
|
{
|
||||||
|
_uncompressedSong = uncompressedSong;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public async Task<SongData> RetrieveCompressedSong(Song song)
|
||||||
|
{
|
||||||
|
SongData songData = new SongData();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var archivePath = RetrieveCompressesSongPath(song);
|
||||||
|
Console.WriteLine($"Compressed song saved to: {archivePath}");
|
||||||
|
|
||||||
|
songData.Data = await System.IO.File.ReadAllBytesAsync(archivePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine($"An error ocurred: \n{exMsg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return songData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RetrieveCompressesSongPath(Song songDetails)
|
||||||
|
{
|
||||||
|
string tmpZipFilePath = _tempDirectory + songDetails.Filename;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var fi = new FileStream(songDetails.SongPath(), FileMode.Open))
|
||||||
|
{
|
||||||
|
using (var z = new Ionic.Zlib.ZlibStream(fi, Ionic.Zlib.CompressionMode.Compress))
|
||||||
|
{
|
||||||
|
using (var tr = new FileStream(tmpZipFilePath, FileMode.CreateNew))
|
||||||
|
{
|
||||||
|
z.CopyTo(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Successfully compressed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine("An error ocurred");
|
||||||
|
Console.WriteLine(exMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (songDetails.Filename!.Contains(Constants.FileExtensions.WAV_EXTENSION))
|
||||||
|
{
|
||||||
|
_compressedSongFilename = StripExtension(songDetails.Filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmpZipFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method not being used
|
||||||
|
public byte[] CompressedSong(byte[] uncompressedSong)
|
||||||
|
{
|
||||||
|
byte[]? compressedSong = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine("Song has been successfully compressed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var exMsg = ex.Message;
|
||||||
|
Console.WriteLine("An error ocurred:");
|
||||||
|
Console.WriteLine(exMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return compressedSong!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string StripExtension(string filename)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Before: {filename}");
|
||||||
|
int filenameLength = filename.Length;
|
||||||
|
Console.WriteLine($"Filename length {filenameLength}");
|
||||||
|
var endIndex = filenameLength - 1;
|
||||||
|
var startIndex = endIndex - 3;
|
||||||
|
Console.WriteLine($"Starting index {startIndex} and ending index {endIndex}");
|
||||||
|
var stripped = filename.Remove(startIndex, 4);
|
||||||
|
stripped += Constants.FileExtensions.ZIP_EXTENSION;
|
||||||
|
Console.WriteLine($"After {stripped}");
|
||||||
|
|
||||||
|
return stripped;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/accesslevel")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class AccessLevelController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<AccessLevelController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public AccessLevelController(ILogger<AccessLevelController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
this._logger = logger;
|
||||||
|
this._config = config;
|
||||||
|
this._connectionString = this._config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region HTTP Routes
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetAccessLevels(Guid? id, Guid? songId)
|
||||||
|
{
|
||||||
|
var accLevel = new Models.AccessLevel { };
|
||||||
|
var accessLevelContext = new Database.Contexts.AccessLevelContext(_connectionString!);
|
||||||
|
|
||||||
|
if (id != null)
|
||||||
|
{
|
||||||
|
accLevel = accessLevelContext.AccessLevels!.FirstOrDefault(al => al.Id == id);
|
||||||
|
}
|
||||||
|
else if (songId != null)
|
||||||
|
{
|
||||||
|
accLevel = accessLevelContext.GetAccessLevel(songId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = new GetAccessLevelsResponse { Data = new List<Models.AccessLevel>() };
|
||||||
|
|
||||||
|
if (accLevel?.Id.ToString().Length > 0)
|
||||||
|
{
|
||||||
|
response.Subject = "Successful";
|
||||||
|
response.Data.Add(accLevel);
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.Subject = "Failure";
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPatch("{id}")]
|
||||||
|
public IActionResult UpdateAccessLevel(Guid id, [FromBody] Models.AccessLevel accessLevel)
|
||||||
|
{
|
||||||
|
var response = new UpdateAccessLevelResponse { Data = new List<Models.AccessLevel>() };
|
||||||
|
var targetLevel = accessLevel.Level;
|
||||||
|
if (targetLevel == null)
|
||||||
|
{
|
||||||
|
response.Subject = "No level provided";
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!Models.AccessLevel.IsAccessLevelValid(targetLevel))
|
||||||
|
{
|
||||||
|
response.Subject = "Invalid level";
|
||||||
|
return BadRequest(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessLevelContext = new Database.Contexts.AccessLevelContext(this._connectionString!);
|
||||||
|
|
||||||
|
var fetchedAccLevel = accessLevelContext.AccessLevels!.FirstOrDefault(al => al.Id == id);
|
||||||
|
|
||||||
|
if (fetchedAccLevel == null)
|
||||||
|
{
|
||||||
|
response.Subject = "Nothing found";
|
||||||
|
return NotFound(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
var fetchedLevel = fetchedAccLevel!.Level;
|
||||||
|
|
||||||
|
if (fetchedLevel!.Equals(targetLevel))
|
||||||
|
{
|
||||||
|
// No change
|
||||||
|
response.Subject = "No change";
|
||||||
|
response.Data.Add(fetchedAccLevel);
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fetchedAccLevel.Level = targetLevel;
|
||||||
|
response.Subject = "Successful";
|
||||||
|
accessLevelContext.Update(fetchedAccLevel);
|
||||||
|
accessLevelContext.SaveChanges();
|
||||||
|
|
||||||
|
response.Data.Add(fetchedAccLevel);
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Responses
|
||||||
|
public class GetAccessLevelsResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[Newtonsoft.Json.JsonProperty("subject")]
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
[Newtonsoft.Json.JsonProperty("data")]
|
||||||
|
public List<Models.AccessLevel>? Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateAccessLevelResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[Newtonsoft.Json.JsonProperty("subject")]
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
[Newtonsoft.Json.JsonProperty("data")]
|
||||||
|
public List<Models.AccessLevel>? Data { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/album")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class AlbumController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<AlbumController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public AlbumController(ILogger<AlbumController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP Routes
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetAlbums()
|
||||||
|
{
|
||||||
|
var albumContext = new AlbumContext(_connectionString!);
|
||||||
|
|
||||||
|
var albums = albumContext.Albums!.ToList();
|
||||||
|
|
||||||
|
if (albums.Count > 0)
|
||||||
|
return Ok(albums);
|
||||||
|
else
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetAlbum(Guid id)
|
||||||
|
{
|
||||||
|
Album album = new Album { Id = id };
|
||||||
|
|
||||||
|
var albumContext = new AlbumContext(_connectionString!);
|
||||||
|
|
||||||
|
if (albumContext.DoesRecordExist(album))
|
||||||
|
{
|
||||||
|
album = albumContext.RetrieveRecord(album);
|
||||||
|
|
||||||
|
return Ok(album);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/artist")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class ArtistController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<ArtistController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public ArtistController(ILogger<ArtistController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP Routes
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetArtists()
|
||||||
|
{
|
||||||
|
var artistContext = new ArtistContext(_connectionString!);
|
||||||
|
|
||||||
|
var artists = artistContext.Artists.ToList();
|
||||||
|
|
||||||
|
if (artists.Count > 0)
|
||||||
|
return Ok(artists);
|
||||||
|
else
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetArtist(Guid id)
|
||||||
|
{
|
||||||
|
Artist artist = new Artist { Id = id };
|
||||||
|
|
||||||
|
var artistContext = new ArtistContext(_connectionString!);
|
||||||
|
|
||||||
|
if (artistContext.DoesRecordExist(artist))
|
||||||
|
{
|
||||||
|
artist = artistContext.RetrieveRecord(artist);
|
||||||
|
|
||||||
|
return Ok(artist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
public class BaseController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fiends
|
||||||
|
protected IConfiguration? _config;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
[ApiExplorerSettings(IgnoreApi = true)]
|
||||||
|
[Obsolete("Asymmetric key signing for tokens have been deprecated")]
|
||||||
|
protected string ParseBearerTokenFromHeader()
|
||||||
|
{
|
||||||
|
var token = string.Empty;
|
||||||
|
const string tokenType = "Bearer";
|
||||||
|
const string otherTokenType = "Jwt";
|
||||||
|
|
||||||
|
var req = Request;
|
||||||
|
var auth = req.Headers.Authorization;
|
||||||
|
var val = auth.ToString();
|
||||||
|
|
||||||
|
if ((val.Contains(tokenType) || val.Contains(otherTokenType)) && val.Split(" ").Count() > 1)
|
||||||
|
{
|
||||||
|
var split = val.Split(" ");
|
||||||
|
token = split[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Managers;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/coverart")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class CoverArtController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<CoverArtController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public CoverArtController(ILogger<CoverArtController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP Routes
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetCoverArts()
|
||||||
|
{
|
||||||
|
var coverArtContext = new CoverArtContext(_connectionString!);
|
||||||
|
|
||||||
|
var coverArtRecords = coverArtContext.CoverArtImages!.ToList();
|
||||||
|
|
||||||
|
if (coverArtRecords == null)
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("No cover art records");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("Found cover art records");
|
||||||
|
return Ok(coverArtRecords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetCoverArt(Guid id)
|
||||||
|
{
|
||||||
|
var coverArt = new CoverArt { Id = id };
|
||||||
|
|
||||||
|
var coverArtContext = new CoverArtContext(_connectionString!);
|
||||||
|
|
||||||
|
coverArt = coverArtContext.RetrieveRecord(coverArt);
|
||||||
|
|
||||||
|
if (coverArt != null)
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("Found cover art record");
|
||||||
|
var coverArtBytes = System.IO.File.ReadAllBytes(
|
||||||
|
coverArt.ImagePath());
|
||||||
|
|
||||||
|
return File(coverArtBytes, "application/x-msdownload",
|
||||||
|
coverArt.SongTitle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("Cover art not found");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("data/download/{id}")]
|
||||||
|
public async Task<IActionResult> Download(Guid id, [FromQuery] bool? randomizeFilename)
|
||||||
|
{
|
||||||
|
var songContext = new SongContext(_connectionString!);
|
||||||
|
var covMgr = new CoverArtManager(this._config!);
|
||||||
|
|
||||||
|
var songMetaData = songContext.RetrieveRecord(new Song { Id = id });
|
||||||
|
var c = covMgr.GetCoverArt(songMetaData);
|
||||||
|
|
||||||
|
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.JPG_EXTENSION, songMetaData.Title!, randomizeFilename);
|
||||||
|
|
||||||
|
var data = await c.GetData();
|
||||||
|
|
||||||
|
return File(data, "application/x-msdownload", filename);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/genre")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class GenreController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<GenreController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public GenreController(ILogger<GenreController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP Routes
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetGenres()
|
||||||
|
{
|
||||||
|
var genreStore = new GenreContext(_connectionString!);
|
||||||
|
|
||||||
|
var genres = genreStore!.Genres!.ToList();
|
||||||
|
|
||||||
|
if (genres.Count > 0)
|
||||||
|
{
|
||||||
|
return Ok(genres);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound(new List<Genre>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetGenre(Guid id)
|
||||||
|
{
|
||||||
|
var genre = new Genre { Id = id };
|
||||||
|
|
||||||
|
var genreStore = new GenreContext(_connectionString!);
|
||||||
|
|
||||||
|
if (genreStore.DoesRecordExist(genre))
|
||||||
|
{
|
||||||
|
genre = genreStore.RetrieveRecord(genre);
|
||||||
|
|
||||||
|
return Ok(genre);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound(new Genre());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Managers;
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/login")]
|
||||||
|
[ApiController]
|
||||||
|
public class LoginController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _connectionString;
|
||||||
|
private IConfiguration? _config;
|
||||||
|
private ILogger<LoginController> _logger;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Contructors
|
||||||
|
public LoginController(IConfiguration config, ILogger<LoginController> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP endpoints
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult Login([FromBody] User user)
|
||||||
|
{
|
||||||
|
var context = new UserContext(_connectionString!);
|
||||||
|
|
||||||
|
_logger.LogInformation("Starting process of validating credentials");
|
||||||
|
|
||||||
|
var message = "Invalid credentials";
|
||||||
|
var password = user.Password;
|
||||||
|
|
||||||
|
var loginRes = new LoginResult
|
||||||
|
{
|
||||||
|
Username = user.Username
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (context.Users.FirstOrDefault(usr => usr.Username!.Equals(user.Username)) != null)
|
||||||
|
{
|
||||||
|
user = context.Users.FirstOrDefault(usr => usr.Username!.Equals(user.Username))!;
|
||||||
|
|
||||||
|
var validatePass = new PasswordEncryption();
|
||||||
|
var validated = validatePass.VerifyPassword(user!, password!);
|
||||||
|
if (!validated)
|
||||||
|
{
|
||||||
|
loginRes.Message = message;
|
||||||
|
_logger.LogInformation(message);
|
||||||
|
|
||||||
|
return Ok(loginRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("Successfully validated user credentials");
|
||||||
|
|
||||||
|
TokenManager tk = new TokenManager(_config!);
|
||||||
|
|
||||||
|
loginRes = tk.LoginSymmetric(user!);
|
||||||
|
|
||||||
|
return Ok(loginRes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loginRes.Message = message;
|
||||||
|
|
||||||
|
return NotFound(loginRes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError("An error occurred: {0}", ex.Message);
|
||||||
|
_logger.LogError("Inner Exception: {0}", ex.InnerException!.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotFound(loginRes);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/register")]
|
||||||
|
[ApiController]
|
||||||
|
public class RegisterController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private IConfiguration? _config;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public RegisterController(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult RegisterUser([FromBody] User user)
|
||||||
|
{
|
||||||
|
PasswordEncryption pe = new PasswordEncryption();
|
||||||
|
user.Password = pe.HashPassword(user);
|
||||||
|
user.EmailVerified = false;
|
||||||
|
user.Status = "Registered";
|
||||||
|
user.DateCreated = DateTime.Now;
|
||||||
|
|
||||||
|
UserContext? context = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var connString = _config!.GetConnectionString("DefaultConnection");
|
||||||
|
context = new UserContext(connString!);
|
||||||
|
context.Add(user);
|
||||||
|
context.SaveChanges();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var msg = ex.Message;
|
||||||
|
var stackTrace = ex.StackTrace;
|
||||||
|
|
||||||
|
Console.WriteLine($"An error occurred: {msg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var registerResult = new RegisterResult
|
||||||
|
{
|
||||||
|
Username = user.Username
|
||||||
|
};
|
||||||
|
|
||||||
|
if (context!.Users.FirstOrDefault(sng => sng.Username!.Equals(user.Username)) != null)
|
||||||
|
{
|
||||||
|
registerResult.Message = "Successful registration";
|
||||||
|
registerResult.SuccessfullyRegistered = true;
|
||||||
|
|
||||||
|
return Ok(registerResult);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
registerResult.Message = "Registration failed";
|
||||||
|
registerResult.SuccessfullyRegistered = false;
|
||||||
|
|
||||||
|
return Ok(registerResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Utilities;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
using Icarus.Controllers.Managers;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/song/compressed/data")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class SongCompressedDataController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _connectionString;
|
||||||
|
private string? _songTempDir;
|
||||||
|
private string? _archiveDir;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public SongCompressedDataController(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
||||||
|
_archiveDir = _config.GetValue<string>("ArchivePath");
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region API Routes
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<IActionResult> DownloadCompressedSong(Guid id, [FromQuery] bool? randomizeFilename)
|
||||||
|
{
|
||||||
|
var context = new SongContext(_connectionString!);
|
||||||
|
|
||||||
|
SongCompression cmp = new SongCompression(_archiveDir!);
|
||||||
|
|
||||||
|
Console.WriteLine($"Archive directory root: {_archiveDir}");
|
||||||
|
|
||||||
|
Console.WriteLine("Starting process of retrieving comrpessed song");
|
||||||
|
var sng = context.RetrieveRecord(new Song { Id = id });
|
||||||
|
|
||||||
|
var tokenManager = new TokenManager(this._config!);
|
||||||
|
var accLvlContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
var accessLevel = accLvlContext.GetAccessLevel(sng.Id);
|
||||||
|
var token = tokenManager.GetBearerToken(HttpContext);
|
||||||
|
if (token == null || accessLevel == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenManager.CanAccessSong(token, sng, accessLevel))
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
SongData song = await cmp.RetrieveCompressedSong(sng);
|
||||||
|
|
||||||
|
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.ZIP_EXTENSION, sng.Title!, randomizeFilename);
|
||||||
|
|
||||||
|
return File(song.Data!, "application/x-msdownload", filename);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Managers;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/song")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class SongController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private readonly ILogger<SongController>? _logger;
|
||||||
|
private string? _connectionString;
|
||||||
|
private SongManager? _songMgr;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public SongController(IConfiguration config, ILogger<SongController> logger)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_logger = logger;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_songMgr = new SongManager(config);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
#region HTTP Endpoints
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetSongs()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Attemtping to retrieve songs");
|
||||||
|
_logger!.LogInformation("Attempting to retrieve songs");
|
||||||
|
|
||||||
|
var context = new SongContext(_connectionString!);
|
||||||
|
|
||||||
|
var songs = context.Songs!.ToList();
|
||||||
|
|
||||||
|
if (songs.Count > 0)
|
||||||
|
{
|
||||||
|
return Ok(songs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetSong(Guid id)
|
||||||
|
{
|
||||||
|
var context = new SongContext(_connectionString!);
|
||||||
|
|
||||||
|
var song = context.RetrieveRecord(new Song { Id = id });
|
||||||
|
|
||||||
|
Console.WriteLine("Here");
|
||||||
|
|
||||||
|
if (song.Id.ToString().Length != 0)
|
||||||
|
return Ok(song);
|
||||||
|
else
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public IActionResult UpdateSong(Guid id, [FromBody] Song song)
|
||||||
|
{
|
||||||
|
song.Id = id;
|
||||||
|
Console.WriteLine("Retrieving filepath of song");
|
||||||
|
_logger!.LogInformation("Retrieving filepath of song");
|
||||||
|
|
||||||
|
if (!_songMgr!.DoesSongExist(song))
|
||||||
|
{
|
||||||
|
return NotFound(new SongResult
|
||||||
|
{
|
||||||
|
Message = "Song does not exist"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenManager = new TokenManager(this._config!);
|
||||||
|
var accLvlContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
var accessLevel = accLvlContext.GetAccessLevel(song.Id);
|
||||||
|
var token = tokenManager.GetBearerToken(HttpContext);
|
||||||
|
if (token == null || accessLevel == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenManager.CanAccessSong(token, song, accessLevel))
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var songRes = _songMgr.UpdateSong(song);
|
||||||
|
|
||||||
|
return Ok(songRes);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Controllers.Managers;
|
||||||
|
using Icarus.Models;
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Route("api/v1/song/data")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class SongDataController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _connectionString;
|
||||||
|
private ILogger<SongDataController>? _logger;
|
||||||
|
private SongManager? _songMgr;
|
||||||
|
private string? _songTempDir;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public SongDataController(IConfiguration config, ILogger<SongDataController> logger)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_connectionString = _config.GetConnectionString("DefaultConnection");
|
||||||
|
_logger = logger;
|
||||||
|
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
|
||||||
|
_songMgr = new SongManager(config, _songTempDir!);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("download/{id}")]
|
||||||
|
public IActionResult Download(Guid id, [FromQuery] bool? randomizeFilename)
|
||||||
|
{
|
||||||
|
var tokenManager = new TokenManager(this._config!);
|
||||||
|
var songContext = new SongContext(this._connectionString!);
|
||||||
|
var accLvlContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
var songMetaData = songContext.RetrieveRecord(new Song { Id = id });
|
||||||
|
var accessLevel = accLvlContext.GetAccessLevel(songMetaData.Id);
|
||||||
|
var token = tokenManager.GetBearerToken(HttpContext);
|
||||||
|
if (token == null || accessLevel == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenManager.CanAccessSong(token, songMetaData, accessLevel))
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var song = _songMgr!.RetrieveSong(songMetaData).Result;
|
||||||
|
string filename;
|
||||||
|
|
||||||
|
switch (songMetaData.AudioType)
|
||||||
|
{
|
||||||
|
case "wav":
|
||||||
|
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.WAV_EXTENSION,
|
||||||
|
songMetaData.Title!, randomizeFilename);
|
||||||
|
break;
|
||||||
|
case "flac":
|
||||||
|
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.FLAC_EXTENSION,
|
||||||
|
songMetaData.Title!, randomizeFilename);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.DEFAULT_AUDIO_EXTENSION,
|
||||||
|
songMetaData.Title!, randomizeFilename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File(song.Data!, "application/x-msdownload", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: No longer being used
|
||||||
|
// Assumes that the song already has metadata such as
|
||||||
|
// Title
|
||||||
|
// Artist
|
||||||
|
// Album
|
||||||
|
// Genre
|
||||||
|
// Year
|
||||||
|
// Track
|
||||||
|
// Track count
|
||||||
|
// Disc
|
||||||
|
// Disc count
|
||||||
|
// Cover art
|
||||||
|
//
|
||||||
|
[HttpPost("upload"), DisableRequestSizeLimit]
|
||||||
|
[Obsolete("Support for this endoint is no longer supported")]
|
||||||
|
public IActionResult Upload([FromForm(Name = "file")] List<IFormFile> songData)
|
||||||
|
{
|
||||||
|
return new StatusCodeResult(StatusCodes.Status410Gone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The client is expected to send the file, metadata, and cover art separately.
|
||||||
|
// Any metadata already on the file will be overwritten with values from the metadata
|
||||||
|
// as well as the cover art
|
||||||
|
//
|
||||||
|
[HttpPost("upload/with/data")]
|
||||||
|
public IActionResult UploadWithData([FromForm] UploadSongWithDataForm up)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (up.SongData!.Length > 0 && up.CoverArtData!.Length > 0 && !string.IsNullOrEmpty(up.SongFile))
|
||||||
|
{
|
||||||
|
var meta = new Utilities.MetadataRetriever();
|
||||||
|
var tmpSong = this._songMgr!.SaveSongTemp(up.SongData).Result;
|
||||||
|
if (!meta.IsSupportedFile(tmpSong.SongPath()) && !meta.IsSupportedFile(up.CoverArtData))
|
||||||
|
{
|
||||||
|
return BadRequest("Media is not supported");
|
||||||
|
}
|
||||||
|
else if (!meta.IsSupportedFile(tmpSong.SongPath()))
|
||||||
|
{
|
||||||
|
return BadRequest("Song is not supported");
|
||||||
|
}
|
||||||
|
else if (!meta.IsSupportedFile(up.CoverArtData))
|
||||||
|
{
|
||||||
|
return BadRequest("Cover art is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
var song = Newtonsoft.Json.JsonConvert.DeserializeObject<Song>(up.SongFile);
|
||||||
|
var tokMgr = new TokenManager(this._config!);
|
||||||
|
var accessToken = Request.Headers["Authorization"];
|
||||||
|
var userId = tokMgr.RetrieveUserIdFromToken(accessToken!);
|
||||||
|
|
||||||
|
if (userId != null)
|
||||||
|
{
|
||||||
|
song!.UserId = userId.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger!.LogInformation($"Song title: {song!.Title}");
|
||||||
|
|
||||||
|
song.Filename = tmpSong.Filename;
|
||||||
|
song.SongDirectory = tmpSong.SongDirectory;
|
||||||
|
song.DateCreated = tmpSong.DateCreated;
|
||||||
|
song.AudioType = meta.FileExtensionType(tmpSong.SongPath());
|
||||||
|
|
||||||
|
switch (song.AudioType)
|
||||||
|
{
|
||||||
|
case "wav":
|
||||||
|
var _ = _songMgr.DeleteSongFromFileSystem(tmpSong);
|
||||||
|
return BadRequest(new UploadSongWithDataResponse
|
||||||
|
{
|
||||||
|
Subject = "No longer supported",
|
||||||
|
Message = "No support for .wav files",
|
||||||
|
Songs = new List<Song>()
|
||||||
|
});
|
||||||
|
case "flac":
|
||||||
|
song = _songMgr.SaveFlacSongToFileSystem(up.SongData, up.CoverArtData, song);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(song);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger!.LogError(ex.Message, "An error occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("delete/{id}")]
|
||||||
|
public IActionResult DeleteSong(Guid id)
|
||||||
|
{
|
||||||
|
var songContext = new SongContext(_connectionString!);
|
||||||
|
var songMetaData = songContext.RetrieveRecord(new Song { Id = id });
|
||||||
|
|
||||||
|
var tokenManager = new TokenManager(this._config!);
|
||||||
|
var accLvlContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
var accessLevel = accLvlContext.GetAccessLevel(songMetaData.Id);
|
||||||
|
var token = tokenManager.GetBearerToken(HttpContext);
|
||||||
|
if (token == null || accessLevel == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenManager.CanAccessSong(token, songMetaData, accessLevel))
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(songMetaData.Title))
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("Song does not exist");
|
||||||
|
return NotFound("Song does not exist");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger!.LogInformation("Starting process of deleting song from the filesystem and database");
|
||||||
|
|
||||||
|
_songMgr!.DeleteSong(songMetaData);
|
||||||
|
|
||||||
|
return Ok(songMetaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UploadSongWithDataForm
|
||||||
|
{
|
||||||
|
[FromForm(Name = "file")]
|
||||||
|
public IFormFile? SongData { get; set; }
|
||||||
|
// NOTE: Think about making this optional and if it is not provided, use the stock cover art
|
||||||
|
[FromForm(Name = "cover")]
|
||||||
|
public IFormFile? CoverArtData { get; set; }
|
||||||
|
[FromForm(Name = "metadata")]
|
||||||
|
public string? SongFile { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UploadSongWithDataResponse
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
[Newtonsoft.Json.JsonProperty("message")]
|
||||||
|
public string? Message { get; set; }
|
||||||
|
[Newtonsoft.Json.JsonProperty("subject")]
|
||||||
|
public string? Subject { get; set; }
|
||||||
|
[Newtonsoft.Json.JsonProperty("data")]
|
||||||
|
public List<Song>? Songs { get; set; }
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
namespace Icarus.Controllers.V1;
|
||||||
|
|
||||||
|
[Route("api/v1/song/stream")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class SongStreamController : BaseController
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private string? _connectionString;
|
||||||
|
private ILogger<SongStreamController>? _logger;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public SongStreamController(ILogger<SongStreamController> logger, IConfiguration config)
|
||||||
|
{
|
||||||
|
this._logger = logger;
|
||||||
|
this._config = config;
|
||||||
|
this._connectionString = this._config.GetConnectionString("DefaultConnection");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region HTTP endpoints
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<IActionResult> StreamSong(Guid id)
|
||||||
|
{
|
||||||
|
var context = new SongContext(_config!.GetConnectionString("DefaultConnection")!);
|
||||||
|
|
||||||
|
var song = context.Songs!.FirstOrDefault(sng => sng.Id == id);
|
||||||
|
if (song == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
var tokenManager = new Managers.TokenManager(this._config!);
|
||||||
|
var accLvlContext = new AccessLevelContext(this._connectionString!);
|
||||||
|
var accessLevel = accLvlContext.GetAccessLevel(song.Id);
|
||||||
|
var token = tokenManager.GetBearerToken(HttpContext);
|
||||||
|
if (token == null || accessLevel == null)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenManager.CanAccessSong(token, song, accessLevel))
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
var stream = new FileStream(song!.SongPath(), FileMode.Open, FileAccess.Read);
|
||||||
|
stream.Position = 0;
|
||||||
|
var filename = song.Filename;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(song.Filename))
|
||||||
|
{
|
||||||
|
filename = song.GenerateFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger!.LogInformation("Starting to stream song...>");
|
||||||
|
Console.WriteLine("Starting to streamsong...");
|
||||||
|
|
||||||
|
return await Task.Run(() =>
|
||||||
|
{
|
||||||
|
return File(stream, "application/octet-stream", filename);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class AccessLevelContext : DbContext
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
public DbSet<Models.AccessLevel>? AccessLevels { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public AccessLevelContext(DbContextOptions<AccessLevelContext> options) : base(options) { }
|
||||||
|
public AccessLevelContext(string connString) : base(new DbContextOptionsBuilder<AccessLevelContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
if (this.AccessLevels == null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
public Models.AccessLevel? GetAccessLevel(Guid songId)
|
||||||
|
{
|
||||||
|
var accessLevel = this.AccessLevels!.FirstOrDefault(acc => acc.SongId == songId);
|
||||||
|
return accessLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<Models.AccessLevel>().ToTable("AccessLevel");
|
||||||
|
|
||||||
|
modelBuilder.Entity<Models.AccessLevel>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<Models.AccessLevel>().Property(m => m.Level).IsRequired(true);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class AlbumContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Album>? Albums { get; set; }
|
||||||
|
|
||||||
|
public AlbumContext(DbContextOptions<AlbumContext> options) : base(options) { }
|
||||||
|
public AlbumContext(string connString) : base(new DbContextOptionsBuilder<AlbumContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<Album>()
|
||||||
|
.ToTable("Album");
|
||||||
|
|
||||||
|
modelBuilder.Entity<Album>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Album RetrieveRecord(Album album)
|
||||||
|
{
|
||||||
|
var albm = Albums!.FirstOrDefault(alb => alb.Id == album.Id);
|
||||||
|
return albm!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DoesRecordExist(Album album)
|
||||||
|
{
|
||||||
|
return Albums!.FirstOrDefault(alb => alb.Id == album.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class ArtistContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Artist> Artists { get; set; }
|
||||||
|
|
||||||
|
public ArtistContext(DbContextOptions<ArtistContext> options) : base(options) { }
|
||||||
|
public ArtistContext(string connString) : base(new DbContextOptionsBuilder<ArtistContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<Artist>()
|
||||||
|
.ToTable("Artist");
|
||||||
|
|
||||||
|
modelBuilder.Entity<Artist>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Artist RetrieveRecord(Artist artist)
|
||||||
|
{
|
||||||
|
|
||||||
|
return Artists.FirstOrDefault(arst => arst.Id == artist.Id)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool DoesRecordExist(Artist artist)
|
||||||
|
{
|
||||||
|
return Artists.FirstOrDefault(arst => arst.Id == artist.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class CoverArtContext : DbContext
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
public DbSet<CoverArt>? CoverArtImages { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public CoverArtContext(DbContextOptions<CoverArtContext> options) : base(options) { }
|
||||||
|
public CoverArtContext(string connString) : base(new DbContextOptionsBuilder<CoverArtContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<CoverArt>()
|
||||||
|
.ToTable("CoverArt");
|
||||||
|
modelBuilder.Entity<CoverArt>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoverArt RetrieveRecord(CoverArt cover)
|
||||||
|
{
|
||||||
|
return CoverArtImages!.FirstOrDefault(cov => cov.Id == cover.Id)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DoesRecordExist(CoverArt cover)
|
||||||
|
{
|
||||||
|
return CoverArtImages!.FirstOrDefault(cov => cov.Id == cover.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class GenreContext : DbContext
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
public DbSet<Genre>? Genres { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public GenreContext(DbContextOptions<GenreContext> options) : base(options) { }
|
||||||
|
public GenreContext(string connString) : base(new DbContextOptionsBuilder<GenreContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<Genre>()
|
||||||
|
.ToTable("Genre");
|
||||||
|
|
||||||
|
modelBuilder.Entity<Genre>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Genre RetrieveRecord(Genre genre)
|
||||||
|
{
|
||||||
|
var gnre = Genres!.FirstOrDefault(gnr => gnr.Id == genre.Id);
|
||||||
|
return gnre!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DoesRecordExist(Genre genre)
|
||||||
|
{
|
||||||
|
return Genres!.FirstOrDefault(gnr => gnr.Id == genre.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class SongContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<Song>? Songs { get; set; }
|
||||||
|
|
||||||
|
public SongContext(string connString) : base(new DbContextOptionsBuilder<SongContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SongContext(DbContextOptions<SongContext> options) : base(options) { }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.ToTable("Song");
|
||||||
|
|
||||||
|
modelBuilder.Entity<Song>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.Property(s => s.Year)
|
||||||
|
.IsRequired(false);
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.Property(s => s.GenreId)
|
||||||
|
.IsRequired(false);
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.Property(s => s.ArtistId)
|
||||||
|
.IsRequired(false);
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.Property(s => s.AlbumId)
|
||||||
|
.IsRequired(false);
|
||||||
|
modelBuilder.Entity<Song>()
|
||||||
|
.Property(s => s.CoverArtId)
|
||||||
|
.IsRequired(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Song RetrieveRecord(Song song)
|
||||||
|
{
|
||||||
|
var sng = Songs!.FirstOrDefault(sng => sng.Id == song.Id);
|
||||||
|
return sng!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool DoesRecordExist(Song song)
|
||||||
|
{
|
||||||
|
return Songs!.FirstOrDefault(sng => sng.Id == song.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
using Icarus.Models;
|
||||||
|
|
||||||
|
namespace Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
public class UserContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<User> Users { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public UserContext(DbContextOptions<UserContext> options) : base(options) { }
|
||||||
|
[ActivatorUtilitiesConstructor]
|
||||||
|
public UserContext(string connString) : base(new DbContextOptionsBuilder<UserContext>()
|
||||||
|
.UseMySQL(connString).Options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<User>()
|
||||||
|
.ToTable("User");
|
||||||
|
|
||||||
|
modelBuilder.Entity<User>(entity =>
|
||||||
|
{
|
||||||
|
entity.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
entity.Property(e => e.Id)
|
||||||
|
.HasColumnType("binary(16)"); // **** Map Guid to BINARY(16) ****
|
||||||
|
});
|
||||||
|
modelBuilder.Entity<User>()
|
||||||
|
.Property(u => u.LastLogin).IsRequired(false);
|
||||||
|
modelBuilder.Entity<User>()
|
||||||
|
.Property(u => u.DateCreated).HasDefaultValue(DateTime.Now);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public User RetrieveRecord(User user)
|
||||||
|
{
|
||||||
|
return Users.FirstOrDefault(usr => usr.Id == user.Id)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DoesRecordExist(User user)
|
||||||
|
{
|
||||||
|
return Users.FirstOrDefault(usr => usr.Id == user.Id) != null ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
|
<Version>0.1.40</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />
|
||||||
|
<PackageReference Include="EntityFramework" Version="6.5.1" />
|
||||||
|
<PackageReference Include="File.TypeChecker" Version="4.1.1" />
|
||||||
|
<PackageReference Include="Iconic.Zlib.Netstandard" Version="1.0.0" />
|
||||||
|
<PackageReference Include="JWT" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.14" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.14" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.14" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.14">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.11" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
|
||||||
|
<PackageReference Include="RestSharp" Version="106.15.0" />
|
||||||
|
<PackageReference Include="SevenZip" Version="19.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.1" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.7.1" />
|
||||||
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||||
|
<PackageReference Include="taglib" Version="2.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Models\Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="nlog.config" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
<Content Include="Images/Stock/*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,110 @@
|
|||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
|
using Icarus.Database.Contexts;
|
||||||
|
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
var MAX_REQUEST_BODY_SIZE = 51200000000;
|
||||||
|
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
|
||||||
|
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Icarus", Version = "v1" });
|
||||||
|
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Name = "Authorization",
|
||||||
|
Scheme = "Bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
Type = SecuritySchemeType.ApiKey,
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Description = "Bearer *Auth Token*",
|
||||||
|
});
|
||||||
|
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
{
|
||||||
|
new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Bearer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new string[] {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.WebHost.UseKestrel(option =>
|
||||||
|
{
|
||||||
|
option.Limits.MaxRequestBodySize = MAX_REQUEST_BODY_SIZE;
|
||||||
|
});
|
||||||
|
|
||||||
|
var Configuration = builder.Configuration;
|
||||||
|
|
||||||
|
var connString = Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.SaveToken = true;
|
||||||
|
var audience = Configuration["JWT:Audience"];
|
||||||
|
var issuer = Configuration["JWT:Issuer"];
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters()
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidAudience = audience,
|
||||||
|
ValidIssuer = issuer,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]!))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddDbContext<SongContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<AlbumContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<ArtistContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<UserContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<GenreContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString!));
|
||||||
|
builder.Services.AddDbContext<AccessLevelContext>(options => options.UseMySQL(connString!));
|
||||||
|
|
||||||
|
builder.Services.AddControllers()
|
||||||
|
.AddNewtonsoftJson();
|
||||||
|
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This should be enabled at some point
|
||||||
|
// app.UseHttpsRedirection();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
#pragma warning disable ASP0014
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
#pragma warning restore ASP0014
|
||||||
|
|
||||||
|
|
||||||
|
app.Run();
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "api/values",
|
"launchUrl": "swagger",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,8 @@
|
|||||||
"Icarus": {
|
"Icarus": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "api/values",
|
"dotnetRuneMessage": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "http://localhost:5002",
|
"applicationUrl": "http://localhost:5002",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Icarus.Types;
|
||||||
|
|
||||||
|
public enum CoverArtField
|
||||||
|
{
|
||||||
|
SongTitle = 0,
|
||||||
|
ImagePath
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Icarus.Types;
|
||||||
|
|
||||||
|
public enum DirectoryType
|
||||||
|
{
|
||||||
|
Music = 0,
|
||||||
|
CoverArt
|
||||||
|
};
|
||||||
@@ -12,6 +12,12 @@
|
|||||||
"ClientId": "",
|
"ClientId": "",
|
||||||
"ClientSecret": ""
|
"ClientSecret": ""
|
||||||
},
|
},
|
||||||
|
"JWT": {
|
||||||
|
"Issuer": "",
|
||||||
|
"Audience": "",
|
||||||
|
"Secret": "",
|
||||||
|
"Subject": ""
|
||||||
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
|
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
|
||||||
},
|
},
|
||||||
@@ -12,6 +12,12 @@
|
|||||||
"ClientId": "",
|
"ClientId": "",
|
||||||
"ClientSecret": ""
|
"ClientSecret": ""
|
||||||
},
|
},
|
||||||
|
"JWT": {
|
||||||
|
"Issuer": "",
|
||||||
|
"Audience": "",
|
||||||
|
"Secret": "",
|
||||||
|
"Subject": ""
|
||||||
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
|
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
|
||||||
},
|
},
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2019 Kun Deng
|
Copyright (c) 2021 Kun Deng
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||