Add project files.

This commit is contained in:
Steven Hildreth 2018-11-02 16:04:49 -05:00
parent adebe383a9
commit 0430305ebe
77 changed files with 3299 additions and 0 deletions

View file

@ -0,0 +1,78 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Artist : EntityModelBase
{
[MaxLength(100)]
public string AmgId { get; set; }
public string ArtistType { get; set; }
public string BandStatus { get; set; }
[MaxLength(65535)]
public string BioContext { get; set; }
public DateTime? BirthDate { get; set; }
[MaxLength(50)]
public string DiscogsId { get; set; }
[MaxLength(65535)]
[JsonIgnore]
[IgnoreDataMember]
public string ISNIList { get; set; }
[JsonProperty("isniList")]
public IEnumerable<string> ISNIListList
{
get
{
if (string.IsNullOrEmpty(this.ISNIList))
{
return null;
}
return this.ISNIList.Split('|');
}
}
[MaxLength(100)]
public string ITunesId { get; set; }
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[MaxLength(250)]
public string Name { get; set; }
[MaxLength(65535)]
public string Profile { get; set; }
public short? Rating { get; set; }
[MaxLength(500)]
public string RealName { get; set; }
[MaxLength(100)]
public string SpotifyId { get; set; }
public string Tooltip
{
get
{
return this.Name;
}
}
public Artist()
{
this.BandStatus = "1";
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Collection : EntityModelBase
{
public int CollectionCount { get; set; }
[MaxLength(1000)]
public string Description { get; set; }
[MaxLength(200)]
public string Edition { get; set; }
public int MaintainerId { get; set; }
public string CollectionType { get; set; }
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class CollectionRelease
{
public Collection Collection { get; set; }
public int ListNumber { get; set; }
}
}

View file

@ -0,0 +1,91 @@
using Mapster;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace Roadie.Api.Data.Models
{
public abstract class EntityModelBase
{
[MaxLength(65535)]
[JsonIgnore]
[IgnoreDataMember]
public string AlternateNames { get; set; }
public IEnumerable<string> AlternateNamesList
{
get
{
if (string.IsNullOrEmpty(this.AlternateNames))
{
return null;
}
return this.AlternateNames.Split('|');
}
}
public DateTime? BeginDate { get; set; }
[Required]
public DateTime CreatedDate { get; set; }
public DateTime? LastUpdated { get; set; }
public DateTime? EndDate { get; set; }
[Key]
[Required]
[AdaptMember("RoadieId")]
public Guid Id { get; set; }
public bool? IsLocked { get; set; }
[MaxLength(250)]
public string SortName { get; set; }
public int? Status { get; set; }
[MaxLength(65535)]
[JsonIgnore]
[IgnoreDataMember]
public string Tags { get; set; }
public IEnumerable<string> TagsList
{
get
{
if (string.IsNullOrEmpty(this.Tags))
{
return null;
}
return this.Tags.Split('|');
}
}
[MaxLength(65535)]
[JsonIgnore]
[IgnoreDataMember]
public string URLs { get; set; }
public IEnumerable<string> URLsList
{
get
{
if (string.IsNullOrEmpty(this.URLs))
{
return null;
}
return this.URLs.Split('|');
}
}
public EntityModelBase()
{
this.Id = Guid.NewGuid();
this.CreatedDate = DateTime.UtcNow;
this.Status = 0;
}
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Genre : EntityModelBase
{
[MaxLength(100)]
public string Name { get; set; }
}
}

View file

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Api.Data.Models
{
/// <summary>
/// Generic Info for a child item on a Detail record. Like a Label on a Release, or an Artist on a Release, or a Label for an Artist
/// </summary>
[Serializable]
public class Info
{
/// <summary>
/// The Id for the Info (like ArtistId, Or ReleaseId)
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Display name for the Info (like Artist Name or Release Title)
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// Any tooltip to use with the DisplayName
/// </summary>
public string Tooltip { get; set; }
/// <summary>
/// Url to the Image to show for the Info
/// </summary>
public string ImageUrl { get; set; }
/// <summary>
/// Url to see full details
/// </summary>
public string DetailUrl { get; set; }
/// <summary>
/// Any CSS class to apply
/// </summary>
public string CssClass { get; set; }
}
}

View file

@ -0,0 +1,28 @@
using Newtonsoft.Json;
using System;
using System.ComponentModel.DataAnnotations;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Label : EntityModelBase
{
[MaxLength(65535)]
public string BioContext { get; set; }
public DateTime? BirthDate { get; set; }
[MaxLength(50)]
public string DiscogsId { get; set; }
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[MaxLength(250)]
public string Name { get; set; }
[MaxLength(65535)]
public string Profile { get; set; }
}
}

View file

@ -0,0 +1,66 @@
using Mapster;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Release : EntityModelBase
{
[MaxLength(50)]
public string AmgId { get; set; }
public Artist Artist { get; set; }
[MaxLength(50)]
public string DiscogsId { get; set; }
public bool? IsVirtual { get; set; }
[MaxLength(100)]
public string ITunesId { get; set; }
[MaxLength(50)]
public string LastFMId { get; set; }
[MaxLength(65535)]
public string LastFMSummary { get; set; }
public string LibraryStatus { get; set; }
public short? MediaCount { get; set; }
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[MaxLength(65535)]
public string Profile { get; set; }
[Required]
public DateTime ReleaseDate { get; set; }
public string ReleaseType { get; set; }
[MaxLength(100)]
public string SpotifyId { get; set; }
public int? SubmissionId { get; set; }
[MaxLength(250)]
[Required]
public string Title { get; set; }
public short TrackCount { get; set; }
public List<ReleaseLabel> Labels { get; set; }
public List<ReleaseMedia> Medias { get; set; }
public List<ReleaseGenre> Genres { get; set; }
public List<CollectionRelease> Collections { get; set; }
}
}

View file

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class ReleaseGenre : EntityModelBase
{
public Genre Genre { get; set; }
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class ReleaseLabel : EntityModelBase
{
public string CatalogNumber { get; set; }
public Label Label { get; set; }
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class ReleaseMedia : EntityModelBase
{
public int MediaNumber { get; set; }
public string SubTitle { get; set; }
[Required]
public short TrackCount { get; set; }
public List<Track> Tracks { get; set; }
}
}

View file

@ -0,0 +1,52 @@
using Newtonsoft.Json;
using System;
using System.ComponentModel.DataAnnotations;
namespace Roadie.Api.Data.Models
{
[Serializable]
public class Track : EntityModelBase
{
[MaxLength(50)]
public string AmgId { get; set; }
// public Artist Artist { get; set; }
public int ArtistId { get; set; }
public int Duration { get; set; }
[MaxLength(32)]
public string Hash { get; set; }
[MaxLength(15)]
public string ISRC { get; set; }
[MaxLength(50)]
public string LastFMId { get; set; }
public DateTime? LastPlayed { get; set; }
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[MaxLength(65535)]
public string PartTitles { get; set; }
public int PlayedCount { get; set; }
public short Rating { get; set; }
public string ReleaseMediaId { get; set; }
[MaxLength(100)]
public string SpotifyId { get; set; }
[MaxLength(250)]
[Required]
public string Title { get; set; }
[Required]
public short TrackNumber { get; set; }
}
}

View file

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="3.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>
</Project>

51
RoadieApi.sln Normal file
View file

@ -0,0 +1,51 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api", "RoadieApi\Roadie.Api.csproj", "{68C80416-0D72-409D-B727-3FEA7AB7FD2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Library", "RoadieLibrary\Roadie.Library.csproj", "{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Roadie.Api.Data", "Roadie.Api.Data\Roadie.Api.Data.csproj", "{36070276-BE53-4D7B-98ED-4F3644B93336}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Debug|x64.ActiveCfg = Debug|x64
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Debug|x64.Build.0 = Debug|x64
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Release|Any CPU.Build.0 = Release|Any CPU
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Release|x64.ActiveCfg = Release|x64
{68C80416-0D72-409D-B727-3FEA7AB7FD2C}.Release|x64.Build.0 = Release|x64
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Debug|x64.ActiveCfg = Debug|x64
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Debug|x64.Build.0 = Debug|x64
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Release|Any CPU.Build.0 = Release|Any CPU
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Release|x64.ActiveCfg = Release|x64
{99DE01E6-A61C-4D7C-9DF7-513AD365D5E0}.Release|x64.Build.0 = Release|x64
{36070276-BE53-4D7B-98ED-4F3644B93336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Debug|x64.ActiveCfg = Debug|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Debug|x64.Build.0 = Debug|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Release|Any CPU.Build.0 = Release|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Release|x64.ActiveCfg = Release|Any CPU
{36070276-BE53-4D7B-98ED-4F3644B93336}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6023B6DB-4256-42E3-B993-9D1EC04A39CD}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,147 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Models;
using Roadie.Api.Services;
using Roadie.Library.Identity;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Controllers
{
[Produces("application/json")]
[Route("auth")]
[ApiController]
[AllowAnonymous]
public class AccountController : ControllerBase
{
private readonly IConfiguration configuration;
private readonly ILogger<AccountController> logger;
private readonly SignInManager<ApplicationUser> signInManager;
private readonly ITokenService tokenService;
private readonly UserManager<ApplicationUser> userManager;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IConfiguration configuration,
ILogger<AccountController> logger,
ITokenService tokenService)
{
this.userManager = userManager;
this.signInManager = signInManager;
this.configuration = configuration;
this.logger = logger;
this.tokenService = tokenService;
}
[HttpPost]
[Route("token")]
public async Task<IActionResult> CreateToken([FromBody]LoginModel model)
{
if (ModelState.IsValid)
{
try
{
//var u = await userManager.FindByNameAsync(model.Username);
//u.PasswordHash = userManager.PasswordHasher.HashPassword(u, model.Password);
//u.LastUpdated = DateTime.UtcNow;
//await userManager.UpdateAsync(u);
// Login user
var loginResult = await signInManager.PasswordSignInAsync(model.Username, model.Password, isPersistent: false, lockoutOnFailure: false);
if (!loginResult.Succeeded)
{
return BadRequest();
}
// If successful login return OK with generated token
var user = await userManager.FindByNameAsync(model.Username);
return Ok(this.tokenService.GenerateToken(user));
}
catch (Exception ex)
{
this.logger.LogError(ex, "Eror in CreateToken");
return BadRequest();
}
}
return BadRequest(ModelState);
}
[Authorize]
[HttpPost]
[Route("refreshtoken")]
public async Task<IActionResult> RefreshToken()
{
var username = User.Identity.Name ??
User.Claims.Where(c => c.Properties.ContainsKey("unique_name")).Select(c => c.Value).FirstOrDefault();
if (!String.IsNullOrWhiteSpace(username))
{
var user = await userManager.FindByNameAsync(username);
return Ok(this.tokenService.GenerateToken(user));
}
else
{
ModelState.AddModelError("Authentication", "Authentication failed!");
return BadRequest(ModelState);
}
}
[HttpPost]
[Route("register")]
[AllowAnonymous]
public async Task<IActionResult> Register([FromBody] RegisterModel registerModel)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = registerModel.Username,
Email = registerModel.Email,
CreatedDate = DateTime.UtcNow
};
var identityResult = await this.userManager.CreateAsync(user, registerModel.Password);
if (identityResult.Succeeded)
{
await signInManager.SignInAsync(user, isPersistent: false);
return Ok(this.tokenService.GenerateToken(user));
}
else
{
return BadRequest(identityResult.Errors);
}
}
return BadRequest(ModelState);
}
[HttpPost]
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordModel resetPasswordModel)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = resetPasswordModel.Username,
Email = resetPasswordModel.Email,
CreatedDate = DateTime.UtcNow
};
var identityResult = await this.userManager.ResetPasswordAsync(user, resetPasswordModel.Token, resetPasswordModel.Password);
if (identityResult.Succeeded)
{
await signInManager.SignInAsync(user, isPersistent: false);
return Ok(this.tokenService.GenerateToken(user));
}
else
{
return BadRequest(identityResult.Errors);
}
}
return BadRequest(ModelState);
}
}
}

View file

@ -0,0 +1,57 @@
using Mapster;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using roadie.Library.Setttings;
using Roadie.Library.Caching;
using Roadie.Library.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using models = Roadie.Api.Data.Models;
namespace Roadie.Api.Controllers
{
[Produces("application/json")]
[Route("artist")]
[ApiController]
[Authorize]
public class ArtistController : EntityControllerBase
{
public ArtistController(IRoadieDbContext roadieDbContext, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, IRoadieSettings roadieSettings)
: base(roadieDbContext, cacheManager, configuration, roadieSettings)
{
this._logger = logger.CreateLogger("RoadieApi.Controllers.ArtistController"); ;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(this._roadieDbContext.Artists.ProjectToType<models.Artist>());
}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public IActionResult Get(Guid id)
{
var key = id.ToString();
var result = this._cacheManager.Get<models.Artist>(key, () =>
{
var d = this._roadieDbContext.Artists.FirstOrDefault(x => x.RoadieId == id);
if (d != null)
{
return d.Adapt<models.Artist>();
}
return null;
}, key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
}

View file

@ -0,0 +1,28 @@
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using roadie.Library.Setttings;
using Roadie.Library.Caching;
using Roadie.Library.Data;
namespace Roadie.Api.Controllers
{
public abstract class EntityControllerBase : ODataController
{
protected readonly ICacheManager _cacheManager;
protected readonly IConfiguration _configuration;
protected readonly IRoadieDbContext _roadieDbContext;
protected readonly IRoadieSettings _roadieSettings;
protected ILogger _logger;
public EntityControllerBase(IRoadieDbContext roadieDbContext, ICacheManager cacheManager, IConfiguration configuration, IRoadieSettings roadieSettings)
{
this._roadieDbContext = roadieDbContext;
this._cacheManager = cacheManager;
this._configuration = configuration;
this._roadieSettings = roadieSettings;
}
}
}

View file

@ -0,0 +1,56 @@
using Mapster;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using roadie.Library.Setttings;
using Roadie.Library.Caching;
using Roadie.Library.Data;
using System;
using System.Linq;
using models = Roadie.Api.Data.Models;
namespace Roadie.Api.Controllers
{
[Produces("application/json")]
[Route("label")]
[ApiController]
[Authorize]
public class LabelController : EntityControllerBase
{
public LabelController(IRoadieDbContext roadieDbContext, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, IRoadieSettings roadieSettings)
: base(roadieDbContext, cacheManager, configuration, roadieSettings)
{
this._logger = logger.CreateLogger("RoadieApi.Controllers.LabelController"); ;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(this._roadieDbContext.Labels.ProjectToType<models.Label>());
}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public IActionResult Get(Guid id)
{
var key = id.ToString();
var result = this._cacheManager.Get<models.Label>(key, () =>
{
var d = this._roadieDbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
if (d != null)
{
return d.Adapt<models.Label>();
}
return null;
}, key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
}

View file

@ -0,0 +1,64 @@
using Mapster;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using roadie.Library.Setttings;
using Roadie.Library.Caching;
using Roadie.Library.Data;
using System;
using System.Linq;
using models = Roadie.Api.Data.Models;
namespace Roadie.Api.Controllers
{
[Produces("application/json")]
[Route("release")]
[ApiController]
[Authorize]
public class ReleaseController : EntityControllerBase
{
public ReleaseController(IRoadieDbContext roadieDbContext, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, IRoadieSettings roadieSettings)
: base(roadieDbContext, cacheManager, configuration, roadieSettings)
{
this._logger = logger.CreateLogger("RoadieApi.Controllers.ReleaseController"); ;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(this._roadieDbContext.Releases.ProjectToType<models.Release>());
}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public IActionResult Get(Guid id)
{
var key = id.ToString();
var result = this._cacheManager.Get<models.Release>(key, () =>
{
var d = this._roadieDbContext
.Releases
.Include(x => x.Artist)
.Include(x => x.Labels).Include("Labels.Label")
.Include(x => x.Medias).Include("Medias.Tracks")
.Include(x => x.Genres).Include("Genres.Genre")
.Include(x => x.Collections).Include("Collections.Collection")
.FirstOrDefault(x => x.RoadieId == id);
if (d != null)
{
return d.Adapt<models.Release>();
}
return null;
}, key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
}

View file

@ -0,0 +1,56 @@
using Mapster;
using Microsoft.AspNet.OData;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using roadie.Library.Setttings;
using Roadie.Library.Caching;
using Roadie.Library.Data;
using System;
using System.Linq;
using models = Roadie.Api.Data.Models;
namespace Roadie.Api.Controllers
{
[Produces("application/json")]
[Route("track")]
[ApiController]
[Authorize]
public class TrackController : EntityControllerBase
{
public TrackController(IRoadieDbContext roadieDbContext, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, IRoadieSettings roadieSettings)
: base(roadieDbContext, cacheManager, configuration, roadieSettings)
{
this._logger = logger.CreateLogger("RoadieApi.Controllers.TrackController"); ;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(this._roadieDbContext.Tracks.ProjectToType<models.Track>());
}
[HttpGet("{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public IActionResult Get(Guid id)
{
var key = id.ToString();
var result = this._cacheManager.Get<models.Track>(key, () =>
{
var d = this._roadieDbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
if (d != null)
{
return d.Adapt<models.Track>();
}
return null;
}, key);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Models
{
public class LoginModel
{
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Roadie.Api.Models
{
public class RegisterModel : LoginModel
{
[Required]
[EmailAddress]
public String Email { get; set; }
[Required]
[Compare("Password")]
[RegularExpression("^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])).{8,}$", ErrorMessage = "Passwords must be at least 8 characters and contain at 3 of 4 of the following: upper case (A-Z), lower case (a-z), number (0-9) and special character (e.g. !@#$%^&*)")]
public String PasswordConfirmation { get; set; }
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Models
{
public class ResetPasswordModel : RegisterModel
{
[Required]
public string Token { get; set; }
}
}

50
RoadieApi/Program.cs Normal file
View file

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Roadie.Api
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
//public static void Main(string[] args)
//{
// var config = new ConfigurationBuilder()
// .SetBasePath(Directory.GetCurrentDirectory())
// .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
// .AddJsonFile("appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
// .AddCommandLine(args)
// .Build();
// var host = new WebHostBuilder()
// .UseKestrel()
// .UseConfiguration(config)
// .UseContentRoot(Directory.GetCurrentDirectory())
// .ConfigureLogging((hostingContext, logging) =>
// {
// logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
// })
// .UseStartup<Startup>()
// .Build();
// host.Run();
//}
}
}

View file

@ -0,0 +1,11 @@
{
"profiles": {
"Roadie.Api": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:5123/"
}
}
}

View file

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mapster" Version="3.2.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.5" />
<PackageReference Include="Microsoft.AspNetCore.OData" Version="7.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.3.0" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Roadie.Api.Data\Roadie.Api.Data.csproj" />
<ProjectReference Include="..\RoadieLibrary\Roadie.Library.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
using Roadie.Library.Data;
using Roadie.Library.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Services
{
public interface ITokenService
{
string GenerateToken(ApplicationUser user);
}
}

View file

@ -0,0 +1,49 @@
using Microsoft.Extensions.Configuration;
using Roadie.Library.Data;
using Roadie.Library.Identity;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace Roadie.Api.Services
{
public class TokenService : ITokenService
{
private readonly IConfiguration _configuration;
public TokenService(IConfiguration configuration)
{
this._configuration = configuration;
}
public string GenerateToken(ApplicationUser user)
{
var utcNow = DateTime.UtcNow;
var tokenHandler = new JwtSecurityTokenHandler();
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, utcNow.ToString())
};
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(this._configuration.GetValue<String>("Tokens:PrivateKey")));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
var jwt = new JwtSecurityToken(
signingCredentials: signingCredentials,
claims: claims,
notBefore: utcNow,
expires: utcNow.AddSeconds(this._configuration.GetValue<int>("Tokens:Lifetime")),
audience: this._configuration.GetValue<String>("Tokens:Audience"),
issuer: this._configuration.GetValue<String>("Tokens:Issuer")
);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
}
}

176
RoadieApi/Startup.cs Normal file
View file

@ -0,0 +1,176 @@
using Mapster;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OData.Edm;
using Newtonsoft.Json;
using roadie.Library.Setttings;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Data;
using Roadie.Library.Identity;
using System;
using System.IO;
using System.Reflection;
using models = Roadie.Api.Data.Models;
namespace Roadie.Api
{
public class Startup
{
private readonly IConfiguration _configuration;
private readonly ILoggerFactory _loggerFactory;
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
{
this._configuration = configuration;
this._loggerFactory = loggerFactory;
TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole(LogLevel.Trace);
app.UseCors("Cors");
app.UseAuthentication();
//app.UseSwagger();
//app.UseSwaggerUI(c =>
//{
// c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyComics API v1");
// c.RoutePrefix = string.Empty;
//});
app.UseMvc(b =>
{
b.Select().Expand().Filter().OrderBy().MaxTop(100).Count();
b.MapODataServiceRoute("odata", "odata", GetEdmModel());
});
}
public static string AssemblyDirectory
{
get
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("Cors", builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IRoadieSettings, RoadieSettings>(options =>
{
var settingsPath = Path.Combine(AssemblyDirectory, "settings.json");
var settings = new RoadieSettings();
if (File.Exists(settingsPath))
{
var settingsFileContents = File.ReadAllText(settingsPath);
var fromSettingsFile = Newtonsoft.Json.JsonConvert.DeserializeObject<RoadieSettings>(settingsFileContents);
if (fromSettingsFile != null)
{
settings.MergeWith(fromSettingsFile);
}
}
return settings;
});
var cacheManager = new MemoryCacheManager(this._loggerFactory.CreateLogger<MemoryCacheManager>(), new CachePolicy(TimeSpan.FromHours(1)));
services.AddSingleton<ICacheManager>(cacheManager);
services.AddEntityFrameworkMySql().AddDbContext<ApplicationUserDbContext>(options =>
options.UseMySql(this._configuration.GetConnectionString("RoadieDatabaseConnection")));
services.AddEntityFrameworkMySql().AddDbContext<IRoadieDbContext, RoadieDbContext>(options =>
options.UseMySql(this._configuration.GetConnectionString("RoadieDatabaseConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationUserDbContext>()
.AddClaimsPrincipalFactory<ApplicationClaimsFactory>();
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy => policy.RequireClaim("Admin"));
options.AddPolicy("Editor", policy => policy.RequireClaim("Editor"));
});
services.Configure<IConfiguration>(this._configuration);
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(this._configuration["Tokens:PrivateKey"]));
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(config =>
{
config.RequireHttpsMetadata = false;
config.SaveToken = true;
config.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = securityKey,
ValidateAudience = true,
ValidAudience = this._configuration["Tokens:Audience"],
ValidateIssuer = true,
ValidIssuer = this._configuration["Tokens:Issuer"],
ValidateLifetime = true,
ValidateIssuerSigningKey = true
};
});
//services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new Info
// {
// Title = "Roadie API",
// Version = "v1"
// });
//});
services.AddOData();
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<models.Artist>("Artist");
builder.EntitySet<models.Label>("Label");
builder.EntitySet<models.Release>("Release");
return builder.GetEdmModel();
}
}
}

View file

@ -0,0 +1,10 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View file

@ -0,0 +1,54 @@
{
"urls": "http://localhost:5123",
"Logging": {
"IncludeScopes": false,
"Console": {
"LogLevel": {
"Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
"Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
"Microsoft.AspNetCore.Mvc.Razor": "Error",
"Default": "Trace"
}
},
"LogLevel": {
"Information": "Debug"
}
},
"Tokens": {
"PrivateKey": "!1232bcdb4bebc80a0d080883d6deefuxlsh8bfc920c2a8cskeuxd8349sk412aa785662e594b4df48cb46aa3c652b40b3#",
"PublicKey": "91i4874y24134E50sz7dges68AB08",
"Lifetime": "86400",
"Issuer": "http://localhost:5123",
"Audience": "http://localhost:5500"
},
"ConnectionStrings": {
"RoadieDatabaseConnection": "server=voyager;userid=roadie;password=MenAtW0rk668;persistsecurityinfo=True;database=roadie;ConvertZeroDateTime=true"
},
"Settings": {
"SecretKey": "a9kf^!y@rd-ci0&7l#da6ko$(l@_$9(y^r^a@2j+8!7zpk!zw88wi069",
"SiteName": "Roadie",
"InboundFolder": "Z:/incoming/",
"LibraryFolder": "Z:/library/",
"SingleArtistHoldingFolder": "Z:/single_holding/",
"ArtistNameReplace": {
"AC/DC": [ "AC; DC", "AC;DC", "AC/ DC", "AC DC" ],
"Love/Hate": [ "Love; Hate", "Love;Hate", "Love/ Hate", "Love Hate" ]
},
"ApiKeys": [
{
"ApiName": "BingImageSearch",
"Key": "<KEY HERE>"
},
{
"ApiName": "LastFMApiKey",
"Key": "<KEY HERE>",
"KeySecret": "<SECRET HERE>"
},
{
"ApiName": "DiscogsConsumerKey",
"Key": "<KEY HERE>",
"KeySecret": "<SECRET HERE>"
}
]
}
}

View file

@ -0,0 +1,74 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
namespace Roadie.Library.Caching
{
public abstract class CacheManagerBase : ICacheManager
{
protected readonly CachePolicy _defaultPolicy = null;
protected readonly ILogger _logger = null;
protected readonly JsonSerializerSettings _serializerSettings = null;
public CacheManagerBase(ILogger logger, CachePolicy defaultPolicy)
{
this._logger = logger;
this._defaultPolicy = defaultPolicy;
this._serializerSettings = new JsonSerializerSettings
{
ContractResolver = new IgnoreJsonAttributesResolver(),
Formatting = Formatting.Indented
};
}
public abstract bool Add<TCacheValue>(string key, TCacheValue value);
public abstract bool Add<TCacheValue>(string key, TCacheValue value, CachePolicy policy);
public abstract bool Add<TCacheValue>(string key, TCacheValue value, string region, CachePolicy policy);
public abstract void Clear();
public abstract void ClearRegion(string region);
public abstract void Dispose();
public abstract bool Exists<TOut>(string key);
public abstract bool Exists<TOut>(string key, string region);
public abstract TOut Get<TOut>(string key);
public abstract TOut Get<TOut>(string key, string region);
public abstract TOut Get<TOut>(string key, Func<TOut> getItem, string region);
public abstract TOut Get<TOut>(string key, Func<TOut> getItem, string region, CachePolicy policy);
public abstract bool Remove(string key);
public abstract bool Remove(string key, string region);
protected TOut Deserialize<TOut>(string s)
{
if (string.IsNullOrEmpty(s))
{
return default(TOut);
}
try
{
return JsonConvert.DeserializeObject<TOut>(s, this._serializerSettings);
}
catch (Exception ex)
{
this._logger.LogError(ex, null, null);
}
return default(TOut);
}
protected string Serialize(object o)
{
return JsonConvert.SerializeObject(o, this._serializerSettings);
}
}
}

View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Caching
{
public sealed class CachePolicy
{
private readonly TimeSpan expiresAfter;
private readonly bool renewLeaseOnAccess;
public CachePolicy(TimeSpan expiresAfter, bool renewLeaseOnAccess = false)
{
this.expiresAfter = expiresAfter;
this.renewLeaseOnAccess = renewLeaseOnAccess;
}
public TimeSpan ExpiresAfter { get { return this.expiresAfter; } }
/// <summary>
/// If specified, each read of the item from the cache will reset the expiration time
/// </summary>
public bool RenewLeaseOnAccess { get { return this.renewLeaseOnAccess; } }
}
}

View file

@ -0,0 +1,33 @@
using System;
namespace Roadie.Library.Caching
{
public interface ICacheManager : IDisposable
{
bool Add<TCacheValue>(string key, TCacheValue value);
bool Add<TCacheValue>(string key, TCacheValue value, CachePolicy policy);
bool Add<TCacheValue>(string key, TCacheValue value, string region, CachePolicy policy);
void Clear();
void ClearRegion(string region);
bool Exists<TOut>(string key);
bool Exists<TOut>(string key, string region);
TOut Get<TOut>(string key, string region);
TOut Get<TOut>(string key);
TOut Get<TOut>(string key, Func<TOut> getItem, string region);
TOut Get<TOut>(string key, Func<TOut> getItem, string region, CachePolicy policy);
bool Remove(string key);
bool Remove(string key, string region);
}
}

View file

@ -0,0 +1,111 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Caching
{
public class MemoryCacheManager : CacheManagerBase
{
private MemoryCache _cache;
public MemoryCacheManager(ILogger logger, CachePolicy defaultPolicy)
: base(logger, defaultPolicy)
{
this._cache = new MemoryCache(new MemoryCacheOptions());
}
public override bool Add<TCacheValue>(string key, TCacheValue value)
{
using (var entry = _cache.CreateEntry(key))
{
_cache.Set(key, value);
return true;
}
}
public override bool Add<TCacheValue>(string key, TCacheValue value, CachePolicy policy)
{
using (var entry = _cache.CreateEntry(key))
{
_cache.Set(key, value, new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.UtcNow.Add(policy.ExpiresAfter) // new DateTimeOffset(DateTime.UtcNow, policy.ExpiresAfter)
});
return true;
}
}
public override bool Add<TCacheValue>(string key, TCacheValue value, string region, CachePolicy policy)
{
return this.Add(key, value, policy);
}
public override void Clear()
{
this._cache = new MemoryCache(new MemoryCacheOptions());
}
public override void ClearRegion(string region)
{
this.Clear();
}
public override void Dispose()
{
// throw new NotImplementedException();
}
public override bool Exists<TOut>(string key)
{
return this.Get<TOut>(key) != null;
}
public override bool Exists<TOut>(string key, string region)
{
return this.Exists<TOut>(key);
}
public override TOut Get<TOut>(string key)
{
return this._cache.Get<TOut>(key);
}
public override TOut Get<TOut>(string key, string region)
{
return this.Get<TOut>(key);
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region)
{
return this.Get<TOut>(key, getItem, region, this._defaultPolicy);
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region, CachePolicy policy)
{
var r = this.Get<TOut>(key, region);
if (r == null)
{
r = getItem();
this.Add(key, r, region, policy);
}
return r;
}
public override bool Remove(string key)
{
this._cache.Remove(key);
return true;
}
public override bool Remove(string key, string region)
{
return this.Remove(key);
}
}
}

View file

@ -0,0 +1,189 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Caching
{
/// <summary>
/// Redis Cache implemention
/// </summary>
/// <typeparam name="TCacheValue"></typeparam>
public class RedisCacheManager : CacheManagerBase
{
private bool _doTraceLogging = true;
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
return ConnectionMultiplexer.Connect("192.168.1.253:6379,allowAdmin=true");
});
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
private IDatabase _redis = null;
private IDatabase Redis
{
get
{
return this._redis ?? (this._redis = Connection.GetDatabase());
}
}
public RedisCacheManager(ILogger logger, CachePolicy defaultPolicy)
: base(logger, defaultPolicy)
{
}
public override bool Add<TCacheValue>(string key, TCacheValue value)
{
return this.Add(key, value, this._defaultPolicy);
}
public override bool Add<TCacheValue>(string key, TCacheValue value, CachePolicy policy)
{
return this.Add(key, value, null, this._defaultPolicy);
}
public override bool Add<TCacheValue>(string key, TCacheValue value, string region, CachePolicy policy)
{
if (this._doTraceLogging)
{
this._logger.LogTrace("Added [{0}], Region [{1}]", key, region);
}
return this.Redis.StringSet(key, this.Serialize(value));
}
public override void Clear()
{
var endpoints = Connection.GetEndPoints();
var server = Connection.GetServer(endpoints[0]);
server.FlushAllDatabases();
if (this._doTraceLogging)
{
this._logger.LogTrace("Cleared Cache");
}
}
public override void ClearRegion(string region)
{
this.Clear();
}
// Dispose() calls Dispose(true)
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
try
{
Connection.Close();
Connection.Dispose();
}
catch
{
}
}
// free native resources here if there are any
}
public override bool Exists<TOut>(string key)
{
return this.Exists<TOut>(key, null);
}
public override bool Exists<TOut>(string key, string region)
{
return this.Redis.KeyExists(key);
}
public override TOut Get<TOut>(string key)
{
return this.Get<TOut>(key, null);
}
public override TOut Get<TOut>(string key, string region)
{
return this.Get<TOut>(key, region, this._defaultPolicy);
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region)
{
return this.Get<TOut>(key, getItem, region, this._defaultPolicy);
}
private TOut Get<TOut>(string key, string region, CachePolicy policy)
{
var result = this.Deserialize<TOut>(this.Redis.StringGet(key));
if (result == null)
{
if (this._doTraceLogging)
{
this._logger.LogTrace("Get Cache Miss Key [{0}], Region [{1}]", key, region);
}
}
else if (this._doTraceLogging)
{
this._logger.LogTrace("Get Cache Hit Key [{0}], Region [{1}]", key, region);
}
return result;
}
public override TOut Get<TOut>(string key, Func<TOut> getItem, string region, CachePolicy policy)
{
var r = this.Get<TOut>(key, region);
if(r == null)
{
r = getItem();
this.Add(key, r, region, policy);
}
return r;
}
public override bool Remove(string key)
{
return this.Remove(key, null);
}
public override bool Remove(string key, string region)
{
if (this.Redis.KeyExists(key))
{
this.Redis.KeyDelete(key);
}
return false;
}
}
class IgnoreJsonAttributesResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
foreach (var prop in props)
{
prop.Ignored = false; // Ignore [JsonIgnore]
prop.Converter = null; // Ignore [JsonConverter]
prop.PropertyName = prop.UnderlyingName; // restore original property name
}
return props;
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
/// <summary>
/// This is a Api Key used by Roadie to interact with an API (ie KeyName is "BingImageSearch" and its key is the BingImageSearch Key)
/// </summary>
[Serializable]
public class ApiKey
{
public string ApiName { get; set; }
public string Key { get; set; }
public string Secret { get; set; }
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
[Serializable]
public class Converting
{
public bool DoDeleteAfter { get; set; }
public string M4AConvertCommand { get; set; }
public string OGGConvertCommand { get; set; }
public string APEConvertCommand { get; set; }
public Converting()
{
this.DoDeleteAfter = true;
this.M4AConvertCommand = "ffmpeg -i \"{0}\" -acodec libmp3lame -q:a 0 \"{1}\"";
this.OGGConvertCommand = "ffmpeg -i \"{0}\" -acodec libmp3lame -q:a 0 \"{1}\"";
this.APEConvertCommand = "ffmpeg -i \"{0}\" \"{1}\"";
}
}
}

View file

@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace roadie.Library.Setttings
{
public interface IRoadieSettings
{
List<ApiKey> ApiKeys { get; set; }
Dictionary<string, List<string>> ArtistNameReplace { get; set; }
Converting Converting { get; set; }
string DefaultTimeZone { get; set; }
string DiagnosticsPassword { get; set; }
IEnumerable<string> DontDoMetaDataProvidersSearchArtists { get; set; }
IEnumerable<string> FileExtensionsToDelete { get; set; }
string InboundFolder { get; set; }
Integrations Integrations { get; set; }
string LibraryFolder { get; set; }
Processing Processing { get; set; }
bool RecordNoResultSearches { get; set; }
RedisCache Redis { get; set; }
string SecretKey { get; set; }
string SingleArtistHoldingFolder { get; set; }
string SiteName { get; set; }
string SmtpFromAddress { get; set; }
string SmtpHost { get; set; }
string SmtpPassword { get; set; }
int SmtpPort { get; set; }
string SmtpUsername { get; set; }
bool SmtpUseSSl { get; set; }
Thumbnails Thumbnails { get; set; }
Dictionary<string, string> TrackPathReplace { get; set; }
bool UseSSLBehindProxy { get; set; }
string WebsocketAddress { get; set; }
void MergeWith(RoadieSettings secondary);
}
}

View file

@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
public class Integrations
{
private bool _lastFmEnabled = true;
private bool _discogsEnabled = true;
private string _lastFMApiKey = null;
private string _lastFMSecret = null;
private string _discogsConsumerKey = null;
private string _discogsConsumerSecret = null;
public string LastFMApiKey
{
get
{
if (string.IsNullOrEmpty(this._lastFMApiKey))
{
// TODO
//var keySetting = SettingsHelper.Instance.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
//if (keySetting != null)
//{
// this._lastFMApiKey = keySetting.Key;
// this._lastFMSecret = keySetting.Secret;
//}
//else
//{
// Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
//}
}
return this._lastFMApiKey;
}
}
public string LastFmApiSecret
{
get
{
if (string.IsNullOrEmpty(this._lastFMSecret))
{
// TODO
//var keySetting = SettingsHelper.Instance.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
//if (keySetting != null)
//{
// this._lastFMApiKey = keySetting.Key;
// this._lastFMSecret = keySetting.Secret;
//}
//else
//{
// Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
//}
}
return this._lastFMSecret;
}
}
public string DiscogsConsumerKey
{
get
{
if (string.IsNullOrEmpty(this._discogsConsumerKey))
{
// TODO
//var keySetting = SettingsHelper.Instance.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
//if (keySetting != null)
//{
// this._discogsConsumerKey = keySetting.Key;
// this._discogsConsumerSecret = keySetting.Secret;
//}
//else
//{
// Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
//}
}
return this._discogsConsumerKey;
}
}
public string DiscogsConsumerSecret
{
get
{
if (string.IsNullOrEmpty(this._discogsConsumerSecret))
{
// TODO
//var keySetting = SettingsHelper.Instance.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
//if (keySetting != null)
//{
// this._discogsConsumerKey = keySetting.Key;
// this._discogsConsumerSecret = keySetting.Secret;
//}
//else
//{
// Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
//}
}
return this._discogsConsumerSecret;
}
}
public short? DiscogsReadWriteTimeout { get; set; }
public short? DiscogsTimeout { get; set; }
public bool ITunesProviderEnabled { get; set; }
public bool MusicBrainzProviderEnabled { get; set; }
public bool SpotifyProviderEnabled { get; set; }
public bool DiscogsProviderEnabled
{
get
{
if(string.IsNullOrEmpty(this.DiscogsConsumerKey) || string.IsNullOrEmpty(this.DiscogsConsumerSecret))
{
return false;
}
return this._discogsEnabled;
}
set
{
this._discogsEnabled = value;
}
}
public bool LastFmProviderEnabled
{
get
{
if (string.IsNullOrEmpty(this.LastFMApiKey) || string.IsNullOrEmpty(this.LastFmApiSecret))
{
return false;
}
return this._lastFmEnabled;
}
set
{
this._lastFmEnabled = value;
}
}
public Integrations()
{
this.ITunesProviderEnabled = true;
this.MusicBrainzProviderEnabled = true;
this.SpotifyProviderEnabled = true;
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
[Serializable]
public class Processing
{
public bool DoAudioCleanup { get; set; }
public bool DoClearComments { get; set; }
public bool DoDeleteUnknowns { get; set; }
public bool DoFolderArtistNameSet { get; set; }
public bool DoMoveUnknowns { get; set; }
public bool DoParseFromDiscogsDB { get; private set; }
public bool DoParseFromDiscogsDBFindingTrackForArtist { get; private set; }
public bool DoParseFromFileName { get; set; }
public bool DoParseFromLastFM { get; private set; }
public bool DoParseFromMusicBrainz { get; private set; }
public bool DoSaveEditsToTags { get; set; }
public Dictionary<string,string> ReplaceStrings { get; set; }
public int MaximumArtistImagesToAdd { get; set; }
public int MaximumReleaseImagesToAdd { get; set; }
public string RemoveStringsRegex { get; set; }
public string UnknownFolder { get; set; }
public Processing()
{
this.DoAudioCleanup = true;
this.DoSaveEditsToTags = true;
this.DoClearComments = true;
this.ReplaceStrings = new Dictionary<string, string>();
this.ReplaceStrings.Add("-OBSERVER", "");
this.ReplaceStrings.Add("[Torrent Tatty]", "");
this.ReplaceStrings.Add("^", "");
this.ReplaceStrings.Add("_", " ");
this.ReplaceStrings.Add("-", " ");
this.ReplaceStrings.Add("~", ",");
this.RemoveStringsRegex = @"\b[0-9]+\s#\s\b";
this.MaximumArtistImagesToAdd = 12;
this.MaximumReleaseImagesToAdd = 12;
this.DoParseFromFileName = true;
this.DoParseFromDiscogsDBFindingTrackForArtist = true;
this.DoParseFromDiscogsDB = true;
this.DoParseFromMusicBrainz = true;
this.DoParseFromLastFM = true;
}
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
[Serializable]
public class RedisCache
{
public string ConnectionString { get; set; }
}
}

View file

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
[Serializable]
public sealed class RoadieSettings : IRoadieSettings
{
public bool UseSSLBehindProxy { get; set; }
public string SecretKey { get; set; }
public string WebsocketAddress { get; set; }
public string SiteName { get; set; }
public string InboundFolder { get; set; }
public string LibraryFolder { get; set; }
public Dictionary<string, string> TrackPathReplace { get; set; }
public string SingleArtistHoldingFolder { get; set; }
public string DefaultTimeZone { get; set; }
public Thumbnails Thumbnails { get; set; }
public List<ApiKey> ApiKeys { get; set; }
public Converting Converting { get; set; }
public Processing Processing { get; set; }
public Integrations Integrations { get; set; }
public string DiagnosticsPassword { get; set; }
public string SmtpFromAddress { get; set; }
public int SmtpPort { get; set; }
public string SmtpPassword { get; set; }
public string SmtpUsername { get; set; }
public string SmtpHost { get; set; }
public bool SmtpUseSSl { get; set; }
public IEnumerable<string> DontDoMetaDataProvidersSearchArtists { get; set; }
public IEnumerable<string> FileExtensionsToDelete { get; set; }
/// <summary>
/// If the artist name is found in the values then use the key.
/// <remark>This was desgined to handle 'AC/DC' type names as they contain the ID3 v2.3 spec artist seperator</remark>
/// </summary>
public Dictionary<string, List<string>> ArtistNameReplace { get; set; }
public bool RecordNoResultSearches { get; set; }
public RedisCache Redis { get; set; }
public RoadieSettings()
{
this.SiteName = "Roadie";
this.DefaultTimeZone = "US/Central";
this.DiagnosticsPassword = this.SiteName;
this.WebsocketAddress = "ws://localhost:3579/websocket";
this.TrackPathReplace = new Dictionary<string, string>();
this.Thumbnails = new Thumbnails();
this.Converting = new Converting();
this.Processing = new Processing();
this.Integrations = new Integrations();
this.ApiKeys = new List<ApiKey>();
this.DontDoMetaDataProvidersSearchArtists = new string[] { "Various Artists", "Sound Tracks" };
this.FileExtensionsToDelete = new string[] { ".cue", ".db", ".gif", ".html", ".ini", ".jpg", ".jpeg", ".log", ".mpg", ".m3u", ".png", ".nfo", ".nzb", ".sfv", ".srr", ".txt", ".url" };
this.ArtistNameReplace = new Dictionary<string, List<string>>();
this.RecordNoResultSearches = true;
}
public void MergeWith(RoadieSettings secondary)
{
foreach (var pi in typeof(RoadieSettings).GetProperties())
{
var priValue = pi.GetGetMethod().Invoke(this, null);
var secValue = pi.GetGetMethod().Invoke(secondary, null);
if (secValue != null && pi.CanWrite)
{
pi.GetSetMethod().Invoke(this, new object[] { secValue });
}
}
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace roadie.Library.Setttings
{
[Serializable]
public class Thumbnails
{
public short Height { get; set; }
public short Width { get; set; }
public Thumbnails()
{
this.Height = 80;
this.Width = 80;
}
}
}

View file

@ -0,0 +1,65 @@
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("artist")]
public partial class Artist : BeginAndEndNamedEntityBase
{
[Column("amgId")]
[MaxLength(100)]
public string AmgId { get; set; }
[Column("artistType", TypeName = "enum")]
public string ArtistType { get; set; }
[Column("bandStatus", TypeName = "enum")]
public BandStatus? BandStatus { get; set; }
[Column("bioContext", TypeName = "text")]
[MaxLength(65535)]
public string BioContext { get; set; }
[Column("birthDate", TypeName = "date")]
public DateTime? BirthDate { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[Column("isniList", TypeName = "text")]
[MaxLength(65535)]
public string ISNIList { get; set; }
[Column("iTunesId")]
[MaxLength(100)]
public string ITunesId { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("profile", TypeName = "text")]
[MaxLength(65535)]
public string Profile { get; set; }
[Column("rating")]
public short? Rating { get; set; }
[Column("realName")]
[MaxLength(500)]
public string RealName { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("thumbnail", TypeName = "blob")]
public byte[] Thumbnail { get; set; }
public List<Release> Releases { get; set; }
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
public abstract class BeginAndEndEntityBase : EntityBase
{
[Column("beginDate", TypeName = "date")]
public DateTime? BeginDate { get; set; }
[Column("endDate", TypeName = "date")]
public DateTime? EndDate { get; set; }
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
public abstract class BeginAndEndNamedEntityBase : NamedEntityBase
{
[Column("beginDate", TypeName = "date")]
public DateTime? BeginDate { get; set; }
[Column("endDate", TypeName = "date")]
public DateTime? EndDate { get; set; }
}
}

View file

@ -0,0 +1,41 @@
using Roadie.Library.Enums;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("collection")]
public partial class Collection : NamedEntityBase
{
[Column("collectionCount")]
public int CollectionCount { get; set; }
[Column("description")]
[MaxLength(1000)]
public string Description { get; set; }
[Column("edition")]
[MaxLength(200)]
public string Edition { get; set; }
[Column("listInCSV", TypeName = "text")]
[MaxLength(65535)]
public string ListInCSV { get; set; }
[Column("listInCSVFormat")]
[MaxLength(200)]
public string ListInCSVFormat { get; set; }
[Column("maintainerId")]
public int MaintainerId { get; set; }
[Column("thumbnail", TypeName = "blob")]
public byte[] Thumbnail { get; set; }
[Column("collectionType")]
public CollectionType? CollectionType { get; set; }
public ICollection<CollectionRelease> Releases { get; set; }
}
}

View file

@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("collectionrelease")]
public partial class CollectionRelease : EntityBase
{
public Collection Collection { get; set; }
[Column("collectionId")]
[Required]
public int CollectionId { get; set; }
[Column("listNumber")]
public int ListNumber { get; set; }
public Release Release { get; set; }
[Column("releaseId")]
[Required]
public int ReleaseId { get; set; }
}
}

View file

@ -0,0 +1,31 @@
using Roadie.Library.Enums;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
public abstract class EntityBase
{
[Column("createdDate")]
[Required]
public DateTime CreatedDate { get; set; }
[Column("id")]
[Key]
public int Id { get; set; }
public bool? IsLocked { get; set; }
[Column("lastUpdated")]
[Required]
public DateTime? LastUpdated { get; set; }
[Column("roadieId")]
[Required]
public Guid RoadieId { get; set; }
[Column("status", TypeName = "enum")]
public Statuses Status { get; set; }
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("genre")]
public partial class Genre : EntityBase
{
[Column("name")]
[MaxLength(100)]
public string Name { get; set; }
public ICollection<ReleaseGenre> Releases { get; set; }
}
}

View file

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
namespace Roadie.Library.Data
{
public interface IRoadieDbContext
{
DbSet<Artist> Artists { get; set; }
DbSet<CollectionRelease> CollectionReleases { get; set; }
DbSet<Collection> Collections { get; set; }
DbSet<Label> Labels { get; set; }
DbSet<Playlist> Playlists { get; set; }
DbSet<ReleaseGenre> ReleaseGenres { get; set; }
DbSet<ReleaseMedia> ReleaseMedias { get; set; }
DbSet<Release> Releases { get; set; }
DbSet<Track> Tracks { get; set; }
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("label")]
public partial class Label : BeginAndEndNamedEntityBase
{
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("profile", TypeName = "text")]
[MaxLength(65535)]
public string Profile { get; set; }
public List<ReleaseLabel> ReleaseLabels { get; set; }
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
public abstract class NamedEntityBase : EntityBase
{
[Column("sortName")]
[MaxLength(250)]
public string SortName { get; set; }
[MaxLength(250)]
[Column("name")]
public string Name { get; set; }
[Column("alternateNames", TypeName = "text")]
[MaxLength(65535)]
public string AlternateNames { get; set; }
[Column("tags", TypeName = "text")]
[MaxLength(65535)]
public string Tags { get; set; }
[Column("urls", TypeName = "text")]
[MaxLength(65535)]
public string URLs { get; set; }
}
}

View file

@ -0,0 +1,31 @@
using Roadie.Library.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("playlist")]
public partial class Playlist : NamedEntityBase
{
[Column("isPublic")]
public bool IsPublic { get; set; }
[Column("Description")]
[MaxLength(1000)]
public string Description { get; set; }
[Column("userId")]
public int? UserId { get; set; }
[Column("thumbnail", TypeName = "blob")]
public byte[] Thumbnail { get; set; }
public ApplicationUser User { get; set; }
public ICollection<PlaylistTrack> Tracks { get; set; }
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("playlisttrack")]
public partial class PlaylistTrack : EntityBase
{
[Column("listNumber")]
[Required]
public int ListNumber { get; set; }
[Column("trackId")]
public int TrackId { get; set; }
[Column("playListId")]
public int PlayListId { get; set; }
public Track Track { get; set; }
public Playlist Playlist { get; set; }
}
}

View file

@ -0,0 +1,90 @@
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("release")]
public partial class Release : EntityBase
{
[Column("amgId")]
[MaxLength(50)]
public string AmgId { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
public Artist Artist { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[Column("isVirtual")]
public bool? IsVirtual { get; set; }
[Column("itunesId")]
[MaxLength(100)]
public string ITunesId { get; set; }
[Column("lastFMId")]
[MaxLength(50)]
public string LastFMId { get; set; }
[Column("lastFMSummary", TypeName = "text")]
[MaxLength(65535)]
public string LastFMSummary { get; set; }
[Column("libraryStatus")]
public LibraryStatus? LibraryStatus { get; set; }
[Column("mediaCount")]
public short? MediaCount { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("profile", TypeName = "text")]
[MaxLength(65535)]
public string Profile { get; set; }
[Column("releaseDate")]
[Required]
public DateTime ReleaseDate { get; set; }
[Column("releaseType")]
public ReleaseType? ReleaseType { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("submissionId")]
public int? SubmissionId { get; set; }
[MaxLength(250)]
[Column("title")]
[Required]
public string Title { get; set; }
[Column("trackCount")]
public short TrackCount { get; set; }
[Column("thumbnail", TypeName = "blob")]
public byte[] Thumbnail { get; set; }
public ICollection<ReleaseLabel> Labels { get; set; }
public ICollection<ReleaseMedia> Medias { get; set; }
public ICollection<ReleaseGenre> Genres { get; set; }
public ICollection<CollectionRelease> Collections { get; set; }
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("releaseGenreTable")]
public partial class ReleaseGenre
{
[Column("id")]
[Key]
public int Id { get; set; }
[Column("releaseId")]
[Required]
public int ReleaseId { get; set; }
public Release Release { get; set; }
[Column("genreId")]
[Required]
public int GenreId { get; set; }
public Genre Genre { get; set; }
}
}

View file

@ -0,0 +1,27 @@
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("releaselabel")]
public class ReleaseLabel : BeginAndEndEntityBase
{
[Column("releaseId")]
public int ReleaseId { get; set; }
public Release Release { get; set; }
[Column("labelId")]
public int LabelId { get; set; }
public Label Label { get; set; }
[Column("catalogNumber")]
public string CatalogNumber { get; set; }
}
}

View file

@ -0,0 +1,32 @@
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Data
{
[Table("releasemedia")]
public class ReleaseMedia : EntityBase
{
[Column("releaseId")]
public int ReleaseId { get; set; }
public Release Release { get; set; }
[Column("releaseSubTitle")]
[MaxLength(500)]
public string SubTitle { get; set; }
[Column("trackCount")]
[Required]
public short TrackCount { get; set; }
[Column("releaseMediaNumber")]
public short MediaNumber { get; set; }
public ICollection<Track> Tracks { get; set; }
}
}

View file

@ -0,0 +1,95 @@
using Microsoft.EntityFrameworkCore;
using Roadie.Library.Enums;
using System;
using System.Diagnostics;
namespace Roadie.Library.Data
{
public class RoadieDbContext : DbContext, IRoadieDbContext
{
public DbSet<Artist> Artists { get; set; }
public DbSet<Label> Labels { get; set; }
public DbSet<Release> Releases { get; set; }
public DbSet<Track> Tracks { get; set; }
public DbSet<ReleaseGenre> ReleaseGenres { get; set; }
public DbSet<ReleaseMedia> ReleaseMedias { get; set; }
public DbSet<Collection> Collections { get; set; }
public DbSet<CollectionRelease> CollectionReleases { get; set; }
public DbSet<Playlist> Playlists { get; set; }
public RoadieDbContext(DbContextOptions<RoadieDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder
.Entity<Release>()
.Property(e => e.ReleaseType)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v) ? ReleaseType.Unknown : (ReleaseType)Enum.Parse(typeof(ReleaseType), v))
.HasDefaultValue(ReleaseType.Unknown);
builder
.Entity<Release>()
.Property(e => e.LibraryStatus)
.HasConversion(
v => v.ToString(),
v => (LibraryStatus)Enum.Parse(typeof(LibraryStatus), v))
.HasDefaultValue(LibraryStatus.Incomplete);
builder
.Entity<Collection>()
.Property(e => e.CollectionType)
.HasConversion(
v => v.ToString(),
v => (CollectionType)Enum.Parse(typeof(CollectionType), v))
.HasDefaultValue(CollectionType.Unknown);
builder.Entity<ReleaseLabel>()
.HasOne(rl => rl.Release)
.WithMany(r => r.Labels)
.HasForeignKey(rl => rl.ReleaseId);
builder.Entity<ReleaseLabel>()
.HasOne(rl => rl.Label)
.WithMany(l => l.ReleaseLabels)
.HasForeignKey(rl => rl.LabelId);
builder.Entity<ReleaseMedia>()
.HasMany(rm => rm.Tracks)
.WithOne(t => t.ReleaseMedia)
.HasForeignKey(rm => rm.ReleaseMediaId);
builder.Entity<ReleaseMedia>()
.HasOne(rm => rm.Release)
.WithMany(r => r.Medias)
.HasForeignKey(r => r.ReleaseId);
builder.Entity<ReleaseGenre>()
.HasKey(rg => new { rg.ReleaseId, rg.GenreId });
builder.Entity<ReleaseGenre>()
.HasOne(rg => rg.Release)
.WithMany(r => r.Genres)
.HasForeignKey(rg => rg.ReleaseId);
builder.Entity<ReleaseGenre>()
.HasOne(rg => rg.Genre)
.WithMany(g => g.Releases)
.HasForeignKey(rg => rg.GenreId);
builder.Entity<CollectionRelease>()
.HasOne(cr => cr.Release)
.WithMany(r => r.Collections)
.HasForeignKey(cr => cr.ReleaseId);
builder.Entity<CollectionRelease>()
.HasOne(cr => cr.Collection)
.WithMany(c => c.Releases)
.HasForeignKey(cr => cr.CollectionId);
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("track")]
public partial class Track : EntityBase
{
[Column("alternateNames", TypeName = "text")]
[MaxLength(65535)]
public string AlternateNames { get; set; }
[Column("amgId")]
[MaxLength(50)]
public string AmgId { get; set; }
public Artist Artist { get; set; }
[Column("artistId")]
public int? ArtistId { get; set; }
[Column("duration")]
public int Duration { get; set; }
[Column("fileName")]
[MaxLength(500)]
public string FileName { get; set; }
[Column("filePath")]
[MaxLength(1000)]
public string FilePath { get; set; }
[Column("fileSize")]
public int FileSize { get; set; }
[Column("hash")]
[MaxLength(32)]
public string Hash { get; set; }
[Column("isrc")]
[MaxLength(15)]
public string ISRC { get; set; }
[Column("lastFMId")]
[MaxLength(50)]
public string LastFMId { get; set; }
[Column("lastPlayed")]
public DateTime? LastPlayed { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("partTitles", TypeName = "text")]
[MaxLength(65535)]
public string PartTitles { get; set; }
[Column("playedCount")]
public int PlayedCount { get; set; }
[Column("rating")]
public short Rating { get; set; }
[Column("releaseMediaId")]
public int ReleaseMediaId { get; set; }
public ReleaseMedia ReleaseMedia { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("tags", TypeName = "text")]
[MaxLength(65535)]
public string Tags { get; set; }
[MaxLength(250)]
[Column("title")]
[Required]
public string Title { get; set; }
[Column("trackNumber")]
[Required]
public short TrackNumber { get; set; }
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum ArtistType : int
{
Unknown = 0,
Person,
Group,
Orchestra,
Choir,
Character,
Other
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum BandStatus
{
Active,
OnHold,
SplitUp,
ChangedName
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum BookmarkType : short
{
Artist = 1,
Release = 2,
Track = 3,
Playlist = 4,
Collection = 5,
Label = 6
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Enums
{
public enum CollectionType : short
{
Unknown = 0,
Collection,
Chart,
Rank
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Enums
{
public enum LibraryStatus : short
{
Incomplete = 0,
Complete,
Missing,
Wishlist
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum QueMessageType
{
ArtistFolder,
ReleaseFolder
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Enums
{
public enum ReleaseType : short
{
Unknown = 0,
Release,
EP,
Single
}
}

View file

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum RequestStatus
{
New = 0,
Processed = 1
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.Enums
{
public enum Statuses : short
{
Ok = 0,
New = 1,
Complete = 2,
Incomplete = 3,
Missing = 4,
Wishlist =5,
Deleted = 99
}
}

View file

@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Roadie.Library.Identity
{
public class ApplicationClaimsFactory : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
{
public const string SecurityClaimRoleType = "req-security-claim";
private readonly ApplicationUserDbContext _applicationUserDbContext = null;
public ApplicationClaimsFactory(
ApplicationUserDbContext applicationUserDbContext,
UserManager<ApplicationUser> userManager,
RoleManager<ApplicationRole> roleManager,
IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
_applicationUserDbContext = applicationUserDbContext;
}
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var usersRoles = (from ur in _applicationUserDbContext.UsersInRoles.Where(x => x.UserId == user.Id)
join r in _applicationUserDbContext.Roles on ur.UserRoleId equals r.Id
select r);
IEnumerable<Claim> userClaims = null;
if (usersRoles.Any())
{
userClaims = usersRoles.Select(x => new Claim(SecurityClaimRoleType, x.Name));
}
return new ClaimsPrincipal(new ClaimsIdentity(userClaims, "Password"));
}
}
}

View file

@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Identity;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userrole")]
public partial class ApplicationRole : IdentityRole<int>
{
[Column("createdDate")]
public DateTime? CreatedDate { get; set; }
[Column("description")]
[StringLength(200)]
public string Description { get; set; }
[Column("id")]
[Key]
public override int Id { get; set; }
[Column("isLocked")]
public bool? IsLocked { get; set; }
[Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("name")]
[Required]
[StringLength(80)]
public override string Name { get; set; }
[Column("roadieId")]
[StringLength(36)]
public string RoadieId { get; set; }
[Column("status")]
public short? Status { get; set; }
}
}

View file

@ -0,0 +1,112 @@
using Microsoft.AspNetCore.Identity;
using Roadie.Library.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("user")]
public partial class ApplicationUser : IdentityUser<int>
{
[Column("apiToken")]
[StringLength(100)]
public string ApiToken { get; set; }
[Column("avatar", TypeName = "blob")]
public byte[] Avatar { get; set; }
[Column("createdDate")]
public DateTime? CreatedDate { get; set; }
[Column("doUseHtmlPlayer")]
public bool? DoUseHtmlPlayer { get; set; }
[Column("email")]
[Required]
[StringLength(100)]
public override string Email { get; set; }
[Column("ftpDirectory")]
[StringLength(500)]
public string FtpDirectory { get; set; }
[Column("ftpPassword")]
[StringLength(500)]
public string FtpPassword { get; set; }
[Column("ftpUrl")]
[StringLength(250)]
public string FtpUrl { get; set; }
[Column("ftpUsername")]
[StringLength(50)]
public string FtpUsername { get; set; }
[Column("id")]
[Key]
public override int Id { get; set; }
[Column("isActive")]
public bool? IsActive { get; set; }
[Column("isLocked")]
public bool? IsLocked { get; set; }
[Column("isPrivate")]
public bool? IsPrivate { get; set; }
[Column("lastApiAccess")]
public DateTime? LastApiAccess { get; set; }
[Column("lastLogin")]
public DateTime? LastLogin { get; set; }
[Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("password")]
[Required]
[StringLength(100)]
public override string PasswordHash { get; set; }
[Column("playerTrackLimit")]
public short? PlayerTrackLimit { get; set; }
[Column("profile", TypeName = "text")]
[StringLength(65535)]
public string Profile { get; set; }
[Column("randomReleaseLimit")]
public short? RandomReleaseLimit { get; set; }
[Column("recentlyPlayedLimit")]
public short? RecentlyPlayedLimit { get; set; }
[Column("registeredOn")]
public DateTime? RegisteredOn { get; set; }
[Column("roadieId")]
[StringLength(36)]
public string RoadieId { get; set; }
[Column("status")]
public short? Status { get; set; }
[Column("timeformat")]
[StringLength(50)]
public string Timeformat { get; set; }
[Column("timezone")]
[StringLength(50)]
public string Timezone { get; set; }
[Column("username")]
[Required]
[StringLength(20)]
public string Username { get; set; }
public ICollection<Playlist> Playlists { get; set; }
}
}

View file

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Identity
{
public class ApplicationUserDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int>
{
public DbSet<UsersInRoles> UsersInRoles { get; set; }
public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().ToTable("user");
modelBuilder.Entity<ApplicationRole>().ToTable("userrole");
}
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace Roadie.Library.Identity
{
[Table("usersInRoles")]
public class UsersInRoles
{
[Column("id")]
[Key]
public int Id { get; set; }
[Column("userId")]
public int UserId { get; set; }
[Column("userRoleId")]
public int UserRoleId { get; set; }
}
}

View file

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.4" />
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.1.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
<PackageReference Include="System.Runtime.Caching" Version="4.5.0" />
</ItemGroup>
</Project>