Compare commits

..

101 Commits

Author SHA1 Message Date
KD 12c4f56a22 Merge pull request #112 from kdeng00/version_bump
Version bump
2025-03-28 18:50:37 -04:00
KD 6d650b7962 Delete song endpoint Bug fix (#111)
* Bug fix

* Removed some code

* Simplifying method
2025-03-28 18:49:34 -04:00
KD 73bb417bde Version bump 2025-03-28 18:48:02 -04:00
KD b0277077f4 Version bump (#110) 2025-03-11 22:09:57 -04:00
KD 3edf6424d0 Updated packages (#109) 2025-03-11 22:04:45 -04:00
KD dcb51448aa tsk-76: Added model and context for AccessLevel (#108)
* tsk-76: Added model and context for AccessLevel

* Formatted code

* AccessLevel migrations are working

* minor formatting

* tsk-#76: Saving AccessLevel when uploading song

* tsk-#76: Added endpoints

* tsk-#76: Warning fix

* tsk-#76: Adding more controller code

* Functionality to modify access levels is operational

* Formatting

* tsk-#76: Added functionality

* tsk-#76: Formatting code

* tsk-#76: Adding more code

* tsk-#76: Formatting
2025-03-11 21:45:32 -04:00
KD 9d90247bf8 Suppressing warning for endpoints (#107)
* Suppressing warning for endpoints

* Minor refactoring
2025-03-01 16:36:02 -05:00
KD 86e54e086a #91: Deprecating upload endpoint (#106)
* #91: Deprecating upload endpoint

* #91: Marking method as obsolete and left a todo

* #91: Removed methods
2025-02-27 19:35:39 -05:00
KD fd3ce9f96a #103: Remove WAV support (#105)
* #103: Adding checks to prevent .wav files from being uploaded:

* #103: Added method to create song and moving some code around

* #103: Fixed build issue

* tsk-103: Cleanup of temporary files

* tsk-103: Formatting changes

* tsk-103: Minor changes

* tsk-103: Fixing build issue

* tsk-103: Refactored enum

* CORE-23734: Refactoring

* tsk-103: Confirmed functionality is working

* Removed commented code

* Removed commented code
2025-02-16 17:24:50 -05:00
KD a89580ac70 #102: Moving Models and constants to their own library (#104)
* #102: Moving Models and constants to their own library

* #102: Updated sln file

* #102: Updated README to include step install migration tool
2024-08-05 20:05:57 -04:00
KD 8900afdfd2 #93: Add flac support (#101)
* Added script shell to convert wav files to flac

* #93: Minor change to script to convert wav files to flac

* #93: Added more code to for the music file conversion

* #93: Script to convert wav files to flac files is done

* #93: Clean up

* #93: Starting work to implement flac support

* #93: Minor update to conversion script

* #93: Added dotnet manifest file

Includes the dotnet-ef tool

* #93: Updated README and migration script

* #93: Created skeleton for saving flac files

* #93: Making some changes to how the file extension is determined

* #93: Updated gitignore

* #93: Another gitignore update

* #93: Making some changes to the process of saving a song to the filesystem

* #93: Adding SQL script to drop and create database

* #93: Saving uploaded song to a temporary location for processing

* #93: Initializing some properties in the song model earlier

* #93: Uploading wav songs works. Moving on to flac support

* #93: Added more code to save flac files

* #93: Updated some code that affects filename generation for audio files

* #93: Song Model changes and support for different file types

* #93: Working on build errors, removed DotnetZip dependency, and added new Ionic.Zlip.Netstandard dependency

* #93: Reduce build errors

* #93: Removed ID3 dependency

* #93: Cleanup
2024-07-27 13:19:12 -04:00
Kun Deng 4b3fa78336 #95: Id changes to models (#99)
* #95: Updated Id of the CoverArt model

* Model and migration changes
2024-06-21 20:30:23 -04:00
Kun Deng 71656aa940 #94: Saving the file type of cover art, but there is still some work to do (#100)
* #94: Saving the file type of cover art, but there is still some work to do

The filename of cover art is hard coded to have the png extension. Need to correct this

* #94: Added a TODO

* #94: Corrected file extension being saved in the db

* Cleanup

* Saving databasescripts
2024-06-21 20:26:44 -04:00
Kun Deng 562bc87822 #74: Add UserID to the Song model (#98)
* #74: Add UserID to the Song model

* #74: Added functionality to retrieve user id from the token

* #74: Songs will now contain the User Id when uploading

* Updated Readme and script to add migrations

* #74: Some cleanup
2024-06-19 15:41:55 -04:00
Kun Deng ebb15b7cdb #79: Added query parameter to randomize filename when downloading songs (#96)
* #79: Added query parameter to randomize filename when downloading songs

Right now only the  endpoint has this parameter added

* #79: Added functionality to the comressed song endpoint

* Added functionality to the download cover art
2024-06-16 19:04:10 -04:00
Kun Deng 270b7d059c #90: Adding functionality to download cover art (#97)
* Added endpoint to download cover art

* Code cleanup

* More cleanup
2024-06-16 18:28:08 -04:00
Kun Deng 23c50de468 Net8 (#89)
* .NET 8 migration

* Fixed bugs with song management

* More cleanup and making some constants

* Updated yml

* Clean up

Removing comments, some cleanup, and moving the startup code into Program.cs

* Removing comments

* Fixed song deletion issue

* Added functionality to delete song directories

* Updated README
2024-06-15 12:17:12 -04:00
kdeng00 ececcb5ba3 Cover art changes 2024-06-09 13:10:51 -04:00
Kun Deng 8658dd34ab Merge pull request #87 from kdeng00/update_namespace
Migrating to modern c# namespace
2023-04-09 12:43:48 -04:00
kdeng00 c17c9cd329 Migrating to modern c# namespace
Using the short namesapce declaration for conciseness
2023-04-09 12:34:06 -04:00
Kun Deng 37cfda84b5 Merge pull request #86 from kdeng00/deprecate_asymmetric_keys
Deprecating asymmetric keys. Closes #84
2022-12-16 14:09:42 -05:00
Kun Deng 3ee17a77a8 Merge pull request #83 from kdeng00/dependabot/nuget/Newtonsoft.Json-13.0.2
Bump Newtonsoft.Json from 13.0.1 to 13.0.2
2022-12-16 14:07:06 -05:00
kdeng00 522be59973 Removing deprecated call
Removing method call that has been deprecated from one of the Controller classes
2022-12-16 13:56:56 -05:00
kdeng00 712a0a9a4a Updated config file 2022-12-16 13:54:18 -05:00
kdeng00 74569d85b6 Deprecating asymmetric keys
Starting work to deprecate using public and private keys to sign tokens
2022-12-16 13:48:15 -05:00
Kun Deng b660f8361f Merge pull request #85 from kdeng00/link_token_with_user
Token modification.  Closes #75
2022-12-16 13:04:37 -05:00
kdeng00 d460b5d5d6 Token modification
Addresses #84. Adding user ID to the access token.
2022-12-16 12:59:11 -05:00
dependabot[bot] 4a1c1f1f78 Bump Newtonsoft.Json from 13.0.1 to 13.0.2
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 13.0.1 to 13.0.2.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/13.0.1...13.0.2)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-08 15:46:41 +00:00
Kun Deng 66b5944f92 Merge pull request #81 from kdeng00/pre-release
Pre release
2022-09-05 17:13:11 -04:00
Kun Deng 80628292e2 Merge pull request #80 from kdeng00/v0.1.20
V0.1.20
2022-09-05 17:12:57 -04:00
Kun Deng 57f4ec1261 Merge pull request #78 from kdeng00/add_swagger_docs
Swagger docs. Close #71
2022-09-05 17:09:23 -04:00
Kun Deng c191d7ee7a Update README.md
Note about swagger
2022-09-05 17:07:26 -04:00
Kun Deng 73bfff3940 Cleanup 2022-09-05 17:02:25 -04:00
Kun Deng 38c056cc99 Swagger docs 2022-09-05 16:58:10 -04:00
Kun Deng 1643f78720 Delete v0.2.yml 2022-09-04 21:29:10 -04:00
Kun Deng 06bb52dfa5 v0.2 Branch 2022-09-04 21:23:11 -04:00
Kun Deng ab89d1602f Create dotnet.yml 2022-09-04 21:20:53 -04:00
Kun Deng 640971dea8 Merge pull request #77 from kdeng00/jwt_symmetric_keys
JWT symmetric keys.

This closes #73.
2022-09-04 20:58:13 -04:00
Kun Deng 664b0d520b Updated Readme 2022-09-04 20:56:37 -04:00
Kun Deng 11fe1f29e1 Updated Readme 2022-09-04 20:50:35 -04:00
Kun Deng 05b5de0939 Cleanup 2022-09-04 20:45:17 -04:00
Kun Deng d5944c470b Symmetric keys with jwt has been implemented 2022-09-04 20:34:33 -04:00
Kun Deng 00ef8d0242 Added JWT bearer authentication 2022-09-04 18:56:56 -04:00
Kun Deng 77c6ee00ea JWT symmetric keys
Updated config file to store neccessary information
2022-09-04 18:39:48 -04:00
Kun Deng 1bfd0a4931 Update Icarus.csproj 2022-08-30 21:42:20 -04:00
Kun Deng 6c3ce69873 Merge pull request #72 from kdeng00/remove_auth
Remove auth
2022-08-30 21:40:26 -04:00
Kun Deng a423e6e220 Update README.md
Updated to reflect removing dependence on Auth0.
2022-08-30 21:39:47 -04:00
Kun Deng f8ec65fd29 Tokens are validated in respective endpoints 2022-08-27 21:35:49 -04:00
Kun Deng 665407aac5 Code cleanup 2022-08-27 20:35:34 -04:00
Kun Deng e5bea187f4 Token validation 2022-08-27 20:16:01 -04:00
Kun Deng fd0f487615 Runtime fixes
Fixed issues preventing endpoints from successfully completing
2022-08-26 23:09:48 -04:00
Kun Deng d48716a54f Endpoint authorization
Tokens are validated for some of the endpoints. Need to add other measures to rule out bogus tokens.
2022-08-26 18:01:29 -04:00
Kun Deng 2cc13ac9bb Code changes
Did not run code. Had a spur of the moment to try something out.
2022-08-25 20:56:12 -04:00
Kun Deng 467a9d7e0f Saving changes
Using asymmetric validation
2022-08-13 18:23:03 -04:00
kdeng00 f0551a4801 Updates
Added packages and updated readme
2022-08-07 17:05:49 -04:00
kdeng00 2cd8c83e28 Updated config 2022-08-07 17:03:47 -04:00
Kun Deng 9797897b76 Added solution file 2022-06-30 21:44:28 -04:00
kdeng00 27cc80d114 Ready for release 2022-01-09 18:13:31 -05:00
kdeng00 27ee3d6ba5 Updated User model 2022-01-09 17:21:26 -05:00
kdeng00 1b6e70ce12 More cleanup 2021-12-29 14:27:04 -05:00
kdeng00 5669cdbdd0 Code cleanup 2021-12-29 14:13:38 -05:00
kdeng00 3a6e0f64bc New endpoint
New endpoint to upload song with metadata and cover art as separate entities
2021-12-29 14:06:52 -05:00
kdeng00 aa0a1ab5fe Refactoring 2021-12-26 22:17:14 -05:00
kdeng00 b529731c95 Song uploads
Uploading songs is functional and does not use the song metadata for the filename or directory creation
2021-12-25 21:36:42 -05:00
kdeng00 64e6f33d7c Refactoring 2021-12-25 11:28:02 -05:00
kdeng00 023298c6f8 Refactoring 2021-12-24 20:51:15 -05:00
kdeng00 f8d9c8e4a7 Authorization functioning 2021-12-24 16:45:40 -05:00
kdeng00 471fa71789 Updated Readme 2021-12-23 21:12:50 -05:00
kdeng00 edaea68296 Functional 2021-12-23 21:10:13 -05:00
kdeng00 8600d9b6bc Updates 2021-12-22 21:33:12 -05:00
kdeng00 922e527819 Removing repositories 2021-12-22 20:28:20 -05:00
kdeng00 46f0da4a5f Updated to .NET 6 2021-12-22 20:20:22 -05:00
kdeng00 16839b9bf8 Saving changes 2021-12-22 20:18:27 -05:00
Kun Deng 552d5dcd25 Merge pull request #70 from kdeng00/dependency-update
Dependency update
2021-08-01 20:08:26 -04:00
kdeng00 cadcf33ed6 Updated dependency 2021-08-01 20:07:40 -04:00
kdeng00 4f46f2ed94 Updated dependencies 2021-08-01 19:50:26 -04:00
kdeng00 560773bfff Now buildable targetting .net 3.1 2021-08-01 19:45:21 -04:00
kdeng00 43623d07c3 Removing unneeded file 2021-08-01 19:17:54 -04:00
kdeng00 b93d436c29 Removing user file 2021-08-01 19:15:26 -04:00
kdeng00 d80842e517 Changed song streaming to use only FileStream instead of FileStream and MemoryStream 2019-07-29 20:59:22 -04:00
amazing-username 2c3152a9a5 Added functionality to retrieve cover art records in json format 2019-07-29 01:07:16 +00:00
amazing-username 3948e25fc3 Incorrect method call for logging fixed 2019-07-20 01:47:16 +00:00
amazing-username a39c232c34 Added logging for cover art functionality 2019-07-17 20:15:07 -04:00
amazing-username 8ec7092272 Implemented Cover Art functionality #50 #52 2019-07-16 20:44:53 -04:00
amazing-username 84615472ef Cover art image gets deleted when the song has been deleted #50 2019-07-15 22:12:49 -04:00
amazing-username e4be56101a Added functionality to save the stock cover art to a song if the song does not contain a cover art #50 2019-07-14 22:40:49 -04:00
amazing-username 59895af3b4 Can download a cover art via the cover art's id. Just need to have a stock cover art for songs without any and update the documentation. #50 2019-07-13 16:04:39 -04:00
amazing-username 1004f6c93d Can successfully save the coverart record, now need to work on downloading the cover art #50 2019-07-13 10:13:15 -04:00
amazing-username 026a528a81 Cover art functionality added. Left TODO's on where to continue on. #50 2019-07-12 23:13:32 -04:00
amazing-username 226ca44206 Mover Cover Art work. #50 2019-07-11 23:15:45 -04:00
amazing-username 4940768d22 All the necessary functionality for the Cover Art repo added #51 2019-07-10 17:54:17 -04:00
amazing-username f7963237fd Added TODO's for checking if Cover art already exists. Added functionality in DirectoryManager to switch to the CoverArt path when explicitly request, otherwise defaults to the music root path. Added skeleton function for CoverArtRepository in the CoverArtRepository and SongManager 2019-07-09 21:03:52 -04:00
amazing-username 0ee1473639 Finished Cover art repository #51 2019-07-09 19:44:40 -04:00
amazing-username 2b59bfac32 Updates to the Cover art repository #51 2019-07-08 18:42:44 -04:00
amazing-username 0932be2f2b Added but did not complete the repository for cover art, updated migration script to create migration for CoverArt, and prepping for the cover art api 2019-07-07 15:02:38 -04:00
amazing-username 82686f5c33 Added cover art path to json files #53 2019-07-07 11:05:53 -04:00
amazing-username b5501e323f Added a cover art model. Better to do it now and not wait til later 2019-07-06 22:26:55 -04:00
amazing-username 089bd1191c Adding Cover art support #50 2019-07-05 20:37:38 -04:00
amazing-username 56fe805f80 Code cleanup and conforming to a coding covention 2019-07-04 17:19:40 -04:00
amazing-username ada8fa79d3 Cleaning up code convention inconsistencies 2019-07-04 15:57:43 -04:00
Kun Deng bc209c2363 Update README.md
#30
2019-06-23 13:11:55 -04:00
122 changed files with 4802 additions and 6488 deletions
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
+25
View File
@@ -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
+18
View File
@@ -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
-32
View File
@@ -1,32 +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;
}
}
}
-19
View File
@@ -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));
}
}
}
-28
View File
@@ -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
}
}
-28
View File
@@ -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
}
}
-13
View File
@@ -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
}
}
-205
View File
@@ -1,205 +0,0 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Icarus.Models;
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();
}
#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 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()
{
_rootSongDirectory = _config.GetValue<string>("RootMusicPath");
}
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
}
}
-28
View File
@@ -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
}
}
File diff suppressed because it is too large Load Diff
-141
View File
@@ -1,141 +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);
Console.WriteLine(tokenObject);
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");
Console.WriteLine(response.Content);
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
}
}
-28
View File
@@ -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
}
}
-292
View File
@@ -1,292 +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 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";
}
}
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,93 +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
}
}
-129
View File
@@ -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
}
}
-85
View File
@@ -1,85 +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
}
}
-85
View File
@@ -1,85 +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
}
}
-84
View File
@@ -1,84 +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
}
}
-89
View File
@@ -1,89 +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
}
}
View File
-71
View File
@@ -1,71 +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,65 +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
}
}
-133
View File
@@ -1,133 +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);
}
}
}
-149
View File
@@ -1,149 +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.Repositories;
namespace Icarus.Controllers.V1
{
[Route("api/v1/song/data")]
[ApiController]
public class SongDataController : ControllerBase
{
#region Fields
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
[HttpGet("{id}")]
[Route("private-scoped")]
[Authorize("download:songs")]
public async Task<IActionResult> Get(int id)
{
SongRepository context = HttpContext
.RequestServices
.GetService(typeof(SongRepository)) as SongRepository;
var songMetaData = context.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
{
SongRepository songRepository = HttpContext
.RequestServices
.GetService(typeof(SongRepository)) as SongRepository;
AlbumRepository albumStoreContext = HttpContext
.RequestServices
.GetService(typeof(AlbumRepository)) as AlbumRepository;
ArtistRepository artistStoreContext = HttpContext
.RequestServices
.GetService(typeof(ArtistRepository)) as ArtistRepository;
GenreRepository genreStore = HttpContext
.RequestServices
.GetService(typeof(GenreRepository)) as GenreRepository;
YearRepository yearStore = HttpContext
.RequestServices
.GetService(typeof(YearRepository)) as YearRepository;
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,
albumStoreContext, artistStoreContext,
genreStore, yearStore);
}
}
}
catch (Exception ex)
{
var msg = ex.Message;
_logger.LogError(msg, "An error occurred");
}
}
[HttpDelete("{id}")]
[Authorize("delete:songs")]
public IActionResult Delete(int id)
{
SongRepository context = HttpContext
.RequestServices
.GetService(typeof(SongRepository)) as SongRepository;
AlbumRepository albumStore = HttpContext
.RequestServices
.GetService(typeof(AlbumRepository)) as AlbumRepository;
ArtistRepository artistStore = HttpContext
.RequestServices
.GetService(typeof(ArtistRepository)) as ArtistRepository;
GenreRepository genreStore = HttpContext
.RequestServices
.GetService(typeof(GenreRepository)) as GenreRepository;
YearRepository yearStore = HttpContext
.RequestServices
.GetService(typeof(YearRepository)) as YearRepository;
var songMetaData = new Song{ Id = id };
Console.WriteLine($"Id {songMetaData.Id}");
songMetaData = context.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, context, albumStore,
artistStore, genreStore, yearStore);
return Ok();
}
}
}
}
-67
View File
@@ -1,67 +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 mem = new MemoryStream();
using (var stream = new FileStream(song.SongPath, FileMode.Open, FileAccess.Read))
{
await stream.CopyToAsync(mem);
}
mem.Position = 0;
_logger.LogInformation("Starting to stream song...>");
Console.WriteLine("Starting to streamsong...");
return File(mem, "application/octet-stream", Path.GetFileName(song.SongPath));
}
#endregion
}
}
-84
View File
@@ -1,84 +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
}
}
-27
View File
@@ -1,27 +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");
}
}
}
-27
View File
@@ -1,27 +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");
}
}
}
-27
View File
@@ -1,27 +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");
}
}
}
-68
View File
@@ -1,68 +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>()
.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);
}
}
}
-32
View File
@@ -1,32 +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);
}
}
}
-27
View File
@@ -1,27 +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");
}
}
}
-411
View File
@@ -1,411 +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
}
}
-370
View File
@@ -1,370 +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
}
}
-23
View File
@@ -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
}
}
-469
View File
@@ -1,469 +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
}
}
-326
View File
@@ -1,326 +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) VALUES(@Title, @AlbumTitle, " +
"@Artist, @Year, @Genre, @Duration, @Filename, @SongPath, " +
"@AlbumId, @ArtistId, @GenreId, @YearId)";
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.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())
});
}
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());
}
return song;
}
#endregion
}
}
-231
View File
@@ -1,231 +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
}
}
-381
View File
@@ -1,381 +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
}
}
-35
View File
@@ -1,35 +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" />
</ItemGroup>
</Project>
-9
View File
@@ -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>
+8 -20
View File
@@ -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
-313
View File
@@ -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,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));
}
}
+78
View File
@@ -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();
}
}
+146
View File
@@ -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
}
+128
View File
@@ -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
}
+479
View File
@@ -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
}
+308
View File
@@ -0,0 +1,308 @@
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 int? 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")
{
return Convert.ToInt32(item.Value);
}
}
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(int? id, int? songId)
{
var accLevel = new Models.AccessLevel { Id = 0 };
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 > 0)
{
response.Subject = "Successful";
response.Data.Add(accLevel);
return Ok(response);
}
else
{
response.Subject = "Failure";
return BadRequest(response);
}
}
[HttpPatch("{id}")]
public IActionResult UpdateAccessLevel(int 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
+65
View File
@@ -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(int 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
}
+67
View File
@@ -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(int 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
}
+37
View File
@@ -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(int 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(int 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
}
+71
View File
@@ -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(int 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
}
+96
View File
@@ -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(int 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
}
+109
View File
@@ -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(int id)
{
var context = new SongContext(_connectionString!);
var song = context.RetrieveRecord(new Song { Id = id });
Console.WriteLine("Here");
if (song.Id != 0)
return Ok(song);
else
return NotFound();
}
[HttpPut("{id}")]
public IActionResult UpdateSong(int 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
}
+231
View File
@@ -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(int 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(int 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(int 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,36 @@
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(int 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>().Property(m => m.Level).IsRequired(true);
}
#endregion
}
+33
View File
@@ -0,0 +1,33 @@
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");
}
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;
}
}
+34
View File
@@ -0,0 +1,34 @@
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");
}
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,34 @@
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");
}
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;
}
}
+36
View File
@@ -0,0 +1,36 @@
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");
}
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;
}
}
+53
View File
@@ -0,0 +1,53 @@
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>()
.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;
}
}
+42
View File
@@ -0,0 +1,42 @@
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>()
.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;
}
}
+46
View File
@@ -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.30</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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+110
View File
@@ -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"
+9
View File
@@ -0,0 +1,9 @@
using System;
namespace Icarus.Types;
public enum CoverArtField
{
SongTitle = 0,
ImagePath
};
+9
View File
@@ -0,0 +1,9 @@
using System;
namespace Icarus.Types;
public enum DirectoryType
{
Music = 0,
CoverArt
};
@@ -9,13 +9,20 @@
"Auth0": { "Auth0": {
"Domain": "[domain].auth0.com", "Domain": "[domain].auth0.com",
"ApiIdentifier": "https://[identifier]/api", "ApiIdentifier": "https://[identifier]/api",
"ClientId":"", "ClientId": "",
"ClientSecret":"" "ClientSecret": ""
},
"JWT": {
"Issuer": "",
"Audience": "",
"Secret": "",
"Subject": ""
}, },
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;" "DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
}, },
"RootMusicPath": "/music/path/", "RootMusicPath": "/music/path/",
"TemporaryMusicPath": "/music/temp/path/", "TemporaryMusicPath": "/music/temp/path/",
"ArchivePath": "/archive/path/" "ArchivePath": "/archive/path/",
"CoverArtPath": "/cover/art/path/"
} }
+10 -3
View File
@@ -9,13 +9,20 @@
"Auth0": { "Auth0": {
"Domain": "[domain].auth0.com", "Domain": "[domain].auth0.com",
"ApiIdentifier": "https://[identifier]/api", "ApiIdentifier": "https://[identifier]/api",
"ClientId":"", "ClientId": "",
"ClientSecret":"" "ClientSecret": ""
},
"JWT": {
"Issuer": "",
"Audience": "",
"Secret": "",
"Subject": ""
}, },
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Server=;Database=;Uid=;Pwd=;" "DefaultConnection": "Server=;Database=;Uid=;Pwd=;"
}, },
"RootMusicPath": "/music/path/", "RootMusicPath": "/music/path/",
"TemporaryMusicPath": "/music/temp/path/", "TemporaryMusicPath": "/music/temp/path/",
"ArchivePath": "/archive/path/" "ArchivePath": "/archive/path/",
"CoverArtPath": "/cover/art/path/"
} }
View File
+1 -1
View File
@@ -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
+51
View File
@@ -0,0 +1,51 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Icarus.Models;
public class AccessLevel
{
#region Properties
[Newtonsoft.Json.JsonProperty("id")]
public int Id { get; set; }
[Newtonsoft.Json.JsonProperty("level")]
public string? Level { get; set; }
[Newtonsoft.Json.JsonProperty("song_id")]
public int SongId { get; set; }
#endregion
#region Methods
public static AccessLevel DefaultLevel()
{
return new AccessLevel
{
Level = "Public"
};
}
public static AccessLevel PrivateLevel()
{
return new AccessLevel
{
Level = "Private"
};
}
public static bool IsAccessLevelValid(string level)
{
if (level.Equals(DefaultLevel().Level))
{
return true;
}
else if (level.Equals(PrivateLevel().Level))
{
return true;
}
else
{
return false;
}
}
#endregion
}
+11 -12
View File
@@ -1,24 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Icarus.Models namespace Icarus.Models;
public class Album
{ {
public class Album #region Properties
{
[JsonProperty("id")] [JsonProperty("id")]
public int AlbumId { get; set; } public int Id { get; set; }
[JsonProperty("title")] [JsonProperty("title")]
public string Title { get; set; } public string? Title { get; set; }
[JsonProperty("album_artist")] [JsonProperty("album_artist")]
public string AlbumArtist { get; set; } [Column("Artist")]
public string? AlbumArtist { get; set; }
[JsonProperty("song_count")] [JsonProperty("song_count")]
[NotMapped] [NotMapped]
public int SongCount { get; set; } public int SongCount { get; set; }
[JsonProperty("year")]
[JsonIgnore] public int Year { get; set; }
public List<Song> Songs { get; set; } #endregion
}
} }
+8 -11
View File
@@ -1,22 +1,19 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Icarus.Models namespace Icarus.Models;
public class Artist
{ {
public class Artist #region Properties
{
[JsonProperty("id")] [JsonProperty("id")]
public int ArtistId { get; set; } public int Id { get; set; }
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; } [Column("Artist")]
public string? Name { get; set; }
[JsonProperty("song_count")] [JsonProperty("song_count")]
[NotMapped] [NotMapped]
public int SongCount { get; set; } public int SongCount { get; set; }
#endregion
[JsonIgnore]
public List<Song> Songs { get; set; }
}
} }
+4 -7
View File
@@ -1,12 +1,9 @@
using System;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Icarus.Models namespace Icarus.Models;
public class BaseResult
{ {
public class BaseResult
{
[JsonProperty("message")] [JsonProperty("message")]
public string Message { get; set; } public string? Message { get; set; }
}
} }
+9
View File
@@ -0,0 +1,9 @@
namespace Icarus.Constants;
public class DirectoryPaths
{
public static string CoverArtDirectory => Directory.GetCurrentDirectory() + "/Images/Stock/";
public static string CoverArtFilename => "CoverArt.png";
public static string FILENAME_CHARACTERS = "ABCDEF0123456789";
public static int FILENAME_LENGTH = 25;
}
+22
View File
@@ -0,0 +1,22 @@
namespace Icarus.Constants;
public class FileExtensions
{
// Contains the default audio file extension with period at the beginning
public static string DEFAULT_AUDIO_EXTENSION = WAV_EXTENSION!;
// Contains file extension with period at the beginning
public static string MP3_EXTENSION = ".mp3";
// Contains file extension with period at the beginning
public static string WAV_EXTENSION = ".wav";
// Contains file extension with period at the beginning
public static string JPG_EXTENSION = ".jpg";
// Contains file extension with period at the beginning
public static string FLAC_EXTENSION = ".flac";
// Contains file extension with period at the beginning
public static string ZIP_EXTENSION = ".zip";
}

Some files were not shown because too many files have changed in this diff Show More