Cleaning up files.

This commit is contained in:
Steven Hildreth 2019-06-30 17:14:36 -05:00
parent 4fa59f442a
commit 1402cfbb72
46 changed files with 3967 additions and 3826 deletions

View file

@ -18,7 +18,7 @@
"Width": 320
},
"DontDoMetaDataProvidersSearchArtists": [ "Various Artists", "Sound Tracks" ],
"FileExtensionsToDelete": [ ".accurip", ".cue", ".dat", ".db", ".exe", ".htm", ".html", ".ini", ".log", ".jpg", ".jpeg", ".par", ".par2", ".pdf", ".png", ".md5", ".mht", ".mpg", ".m3u", ".nfo", ".nzb", ".pls", ".sfv", ".srr", ".txt", ".url" ],
"FileExtensionsToDelete": [ ".accurip", ".bmp", ".cue", ".dat", ".db", ".exe", ".htm", ".html", ".ini", ".log", ".jpg", ".jpeg", ".par", ".par2", ".pdf", ".png", ".md5", ".mht", ".mpg", ".m3u", ".nfo", ".nzb", ".pls", ".sfv", ".srr", ".txt", ".url" ],
"RecordNoResultSearches": true,
"ArtistNameReplace": {
"AC/DC": [ "AC; DC", "AC;DC", "AC/ DC", "AC DC" ],
@ -100,6 +100,4 @@
]
}
}
}
}

View file

@ -1,8 +1,5 @@
using Microsoft.AspNetCore.SignalR;
using Roadie.Library.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Hubs
@ -14,4 +11,4 @@ namespace Roadie.Api.Hubs
await Clients.All.SendAsync("PlayActivity", playActivity);
}
}
}
}

View file

@ -1,8 +1,4 @@
using Microsoft.AspNetCore.SignalR;
using Roadie.Library.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Api.Hubs
@ -14,4 +10,4 @@ namespace Roadie.Api.Hubs
await Clients.All.SendAsync("SendSystemActivity", scanActivity);
}
}
}
}

View file

@ -20,7 +20,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>

View file

@ -1,7 +1,12 @@
using System;
namespace Roadie.Library
{
public class AppException
[Serializable]
public class AppException : Exception
{
public AppException(string message) : base(message)
{
}
}
}

View file

@ -0,0 +1,28 @@
using Roadie.Library.Enums;
using Roadie.Library.Identity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("collectionMissing")]
public partial class CollectionMissing
{
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("collectionId")]
public int CollectionId { get; set; }
[Column("isArtistFound")]
public bool IsArtistFound { get; set; }
[Column("position")]
public int Position { get; set; }
[Column("artist")]
[MaxLength(1000)]
public string Artist { get; set; }
[Column("release")]
[MaxLength(1000)]
public string Release { get; set; }
}
}

View file

@ -18,6 +18,7 @@ namespace Roadie.Library.Data
DbSet<Bookmark> Bookmarks { get; set; }
ChangeTracker ChangeTracker { get; }
DbSet<ChatMessage> ChatMessages { get; set; }
DbSet<CollectionMissing> CollectionMissings { get; set; }
DbSet<CollectionRelease> CollectionReleases { get; set; }
DbSet<Collection> Collections { get; set; }
DbSet<Comment> Comments { get; set; }

View file

@ -13,6 +13,7 @@ namespace Roadie.Library.Data
public DbSet<Bookmark> Bookmarks { get; set; }
public DbSet<ChatMessage> ChatMessages { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<CollectionMissing> CollectionMissings { get; set; }
public DbSet<CommentReaction> CommentReactions { get; set; }
public DbSet<CollectionRelease> CollectionReleases { get; set; }
public DbSet<Collection> Collections { get; set; }

View file

@ -1,83 +1,18 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace Roadie.Library
{
[Serializable]
public class AppException : Exception
{
public AppException() : base()
{
}
public AppException(string message) : base(message)
{
}
public AppException(string message, params object[] args)
: base(String.Format(CultureInfo.CurrentCulture, message, args))
{
}
}
[Serializable]
public class OperationResult<T>
{
private List<Exception> _errors;
private List<string> _messages;
[JsonIgnore]
[XmlIgnore]
public Dictionary<string, object> AdditionalData { get; set; } = new Dictionary<string, object>();
public Dictionary<string, object> AdditionalClientData { get; set; } = new Dictionary<string, object>();
/// <summary>
/// Client friendly exceptions
/// </summary>
[JsonProperty("errors")]
public IEnumerable<AppException> AppExceptions
{
get
{
if (this.Errors == null || !this.Errors.Any())
{
return null;
}
return this.Errors.Select(x => new AppException(x.Message));
}
}
public T Data { get; set; }
/// <summary>
/// Server side visible exceptions
/// </summary>
[JsonIgnore]
public IEnumerable<Exception> Errors { get; set; }
[JsonIgnore]
public bool IsNotFoundResult { get; set; }
[JsonIgnore]
public bool IsAccessDeniedResult { get; set; }
public bool IsSuccess { get; set; }
public IEnumerable<string> Messages
{
get
{
return this._messages;
}
}
public long OperationTime { get; set; }
public OperationResult()
{
}
@ -86,53 +21,89 @@ namespace Roadie.Library
{
if (messages != null && messages.Any())
{
this.AdditionalData = new Dictionary<string, object>();
messages.ToList().ForEach(x => this.AddMessage(x));
AdditionalData = new Dictionary<string, object>();
messages.ToList().ForEach(AddMessage);
}
}
public OperationResult(bool isNotFoundResult, IEnumerable<string> messages = null)
{
this.IsNotFoundResult = isNotFoundResult;
IsNotFoundResult = isNotFoundResult;
if (messages != null && messages.Any())
{
this.AdditionalData = new Dictionary<string, object>();
messages.ToList().ForEach(x => this.AddMessage(x));
AdditionalData = new Dictionary<string, object>();
messages.ToList().ForEach(AddMessage);
}
}
public OperationResult(bool isNotFoundResult, string message)
{
this.IsNotFoundResult = isNotFoundResult;
this.AddMessage(message);
IsNotFoundResult = isNotFoundResult;
AddMessage(message);
}
public OperationResult(string message = null)
{
this.AdditionalData = new Dictionary<string, object>();
this.AddMessage(message);
AdditionalData = new Dictionary<string, object>();
AddMessage(message);
}
public OperationResult(Exception error = null)
{
this.AddError(error);
AddError(error);
}
public OperationResult(string message = null, Exception error = null)
{
this.AddMessage(message);
this.AddError(error);
AddMessage(message);
AddError(error);
}
[JsonIgnore]
[XmlIgnore]
public Dictionary<string, object> AdditionalData { get; set; } = new Dictionary<string, object>();
public Dictionary<string, object> AdditionalClientData { get; set; } = new Dictionary<string, object>();
/// <summary>
/// Client friendly exceptions
/// </summary>
[JsonProperty("errors")]
public IEnumerable<AppException> AppExceptions
{
get
{
if (Errors == null || !Errors.Any()) return null;
return Errors.Select(x => new AppException(x.Message));
}
}
public T Data { get; set; }
/// <summary>
/// Server side visible exceptions
/// </summary>
[JsonIgnore]
public IEnumerable<Exception> Errors { get; set; }
[JsonIgnore] public bool IsNotFoundResult { get; set; }
[JsonIgnore] public bool IsAccessDeniedResult { get; set; }
public bool IsSuccess { get; set; }
public IEnumerable<string> Messages => _messages;
public long OperationTime { get; set; }
public void AddError(Exception exception)
{
if (exception != null)
{
if (this._errors == null)
{
this._errors = new List<Exception>();
}
this._errors.Add(exception);
if (_errors == null) _errors = new List<Exception>();
_errors.Add(exception);
}
}
@ -140,11 +111,9 @@ namespace Roadie.Library
{
if (!string.IsNullOrEmpty(message))
{
if (this._messages == null)
{
this._messages = new List<string>();
}
this._messages.Add(message);
if (_messages == null) _messages = new List<string>();
_messages.Add(message);
}
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
@ -11,9 +11,9 @@
<PackageReference Include="AutoCompare.Core" Version="1.0.0" />
<PackageReference Include="CsvHelper" Version="12.1.2" />
<PackageReference Include="EFCore.BulkExtensions" Version="2.4.7" />
<PackageReference Include="FluentFTP" Version="25.0.3" />
<PackageReference Include="FluentFTP" Version="25.0.4" />
<PackageReference Include="Hashids.net" Version="1.2.2" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.7" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.8" />
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
<PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
<PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" />

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,10 @@ using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Models;
using Roadie.Library.Models.Collections;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
@ -15,7 +17,6 @@ using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
using models = Roadie.Library.Models;
namespace Roadie.Api.Services
@ -23,169 +24,163 @@ namespace Roadie.Api.Services
public class BookmarkService : ServiceBase, IBookmarkService
{
public BookmarkService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<BookmarkService> logger)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<BookmarkService> logger)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
}
public Task<Library.Models.Pagination.PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
public Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser,
PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
{
var sw = new Stopwatch();
sw.Start();
var result = (from b in this.DbContext.Bookmarks
join u in this.DbContext.Users on b.UserId equals u.Id
where b.UserId == roadieUser.Id
where (filterType == null || b.BookmarkType == filterType)
select new BookmarkList
{
Comment = b.Comment,
Position = b.Position,
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
DatabaseId = b.Id,
Id = b.RoadieId,
CreatedDate = b.CreatedDate,
LastUpdated = b.LastUpdated,
Type = b.BookmarkType,
BookmarkTargetId = b.BookmarkTargetId
});
var result = from b in DbContext.Bookmarks
join u in DbContext.Users on b.UserId equals u.Id
where b.UserId == roadieUser.Id
where filterType == null || b.BookmarkType == filterType
select new models.BookmarkList
{
Comment = b.Comment,
Position = b.Position,
User = new models.DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
DatabaseId = b.Id,
Id = b.RoadieId,
CreatedDate = b.CreatedDate,
LastUpdated = b.LastUpdated,
Type = b.BookmarkType,
BookmarkTargetId = b.BookmarkTargetId
};
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "CreatedDate", "DESC" } }) : request.OrderValue(null);
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "CreatedDate", "DESC" } })
: request.OrderValue();
var rowCount = result.Count();
BookmarkList[] rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
var user = this.GetUser(roadieUser.UserId);
var user = GetUser(roadieUser.UserId);
foreach (var row in rows)
{
switch (row.Type)
{
case BookmarkType.Artist:
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (artist == null)
{
continue;
}
row.Bookmark = new DataToken
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (artist == null) continue;
row.Bookmark = new models.DataToken
{
Text = artist.Name,
Value = artist.RoadieId.ToString()
};
row.Artist = models.ArtistList.FromDataArtist(artist, this.MakeArtistThumbnailImage(artist.RoadieId));
row.Thumbnail = this.MakeArtistThumbnailImage(artist.RoadieId);
row.Artist =
models.ArtistList.FromDataArtist(artist, MakeArtistThumbnailImage(artist.RoadieId));
row.Thumbnail = MakeArtistThumbnailImage(artist.RoadieId);
row.SortName = artist.SortName ?? artist.Name;
break;
case BookmarkType.Release:
var release = this.DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (release == null)
{
continue;
}
row.Bookmark = new DataToken
var release = DbContext.Releases.Include(x => x.Artist)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (release == null) continue;
row.Bookmark = new models.DataToken
{
Text = release.Title,
Value = release.RoadieId.ToString()
};
row.Release = models.Releases.ReleaseList.FromDataRelease(release, release.Artist, this.HttpContext.BaseUrl, this.MakeArtistThumbnailImage(release.Artist.RoadieId), this.MakeReleaseThumbnailImage(release.RoadieId));
row.Thumbnail = this.MakeReleaseThumbnailImage(release.RoadieId);
row.Release = ReleaseList.FromDataRelease(release, release.Artist, HttpContext.BaseUrl,
MakeArtistThumbnailImage(release.Artist.RoadieId),
MakeReleaseThumbnailImage(release.RoadieId));
row.Thumbnail = MakeReleaseThumbnailImage(release.RoadieId);
row.SortName = release.Title;
break;
case BookmarkType.Track:
var track = this.DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (track == null)
{
continue;
}
row.Bookmark = new DataToken
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (track == null) continue;
row.Bookmark = new models.DataToken
{
Text = track.Title,
Value = track.RoadieId.ToString()
};
row.Track = TrackList.FromDataTrack(this.MakeTrackPlayUrl(user, track.Id, track.RoadieId),
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
this.HttpContext.BaseUrl,
this.MakeTrackThumbnailImage(track.RoadieId),
this.MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
this.MakeArtistThumbnailImage(track.ReleaseMedia.Release.Artist.RoadieId),
this.MakeArtistThumbnailImage(track.TrackArtist == null ? null : (Guid?)track.TrackArtist.RoadieId));
row.Track.TrackPlayUrl = this.MakeTrackPlayUrl(user, track.Id, track.RoadieId);
row.Thumbnail = this.MakeTrackThumbnailImage(track.RoadieId);
row.Track = models.TrackList.FromDataTrack(MakeTrackPlayUrl(user, track.Id, track.RoadieId),
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
HttpContext.BaseUrl,
MakeTrackThumbnailImage(track.RoadieId),
MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(track.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(track.TrackArtist == null
? null
: (Guid?)track.TrackArtist.RoadieId));
row.Track.TrackPlayUrl = MakeTrackPlayUrl(user, track.Id, track.RoadieId);
row.Thumbnail = MakeTrackThumbnailImage(track.RoadieId);
row.SortName = track.Title;
break;
case BookmarkType.Playlist:
var playlist = this.DbContext.Playlists
.Include(x => x.User)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (playlist == null)
{
continue;
}
row.Bookmark = new DataToken
var playlist = DbContext.Playlists
.Include(x => x.User)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (playlist == null) continue;
row.Bookmark = new models.DataToken
{
Text = playlist.Name,
Value = playlist.RoadieId.ToString()
};
row.Playlist = models.Playlists.PlaylistList.FromDataPlaylist(playlist, playlist.User, this.MakePlaylistThumbnailImage(playlist.RoadieId), this.MakeUserThumbnailImage(playlist.User.RoadieId));
row.Thumbnail = this.MakePlaylistThumbnailImage(playlist.RoadieId);
row.Playlist = PlaylistList.FromDataPlaylist(playlist, playlist.User,
MakePlaylistThumbnailImage(playlist.RoadieId),
MakeUserThumbnailImage(playlist.User.RoadieId));
row.Thumbnail = MakePlaylistThumbnailImage(playlist.RoadieId);
row.SortName = playlist.Name;
break;
case BookmarkType.Collection:
var collection = this.DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (collection == null)
{
continue;
}
row.Bookmark = new DataToken
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (collection == null) continue;
row.Bookmark = new models.DataToken
{
Text = collection.Name,
Value = collection.RoadieId.ToString()
};
row.Collection = models.Collections.CollectionList.FromDataCollection(collection, (from crc in this.DbContext.CollectionReleases
where crc.CollectionId == collection.Id
select crc.Id).Count(), this.MakeCollectionThumbnailImage(collection.RoadieId));
row.Thumbnail = this.MakeCollectionThumbnailImage(collection.RoadieId);
row.Collection = CollectionList.FromDataCollection(collection,
(from crc in DbContext.CollectionReleases
where crc.CollectionId == collection.Id
select crc.Id).Count(), MakeCollectionThumbnailImage(collection.RoadieId));
row.Thumbnail = MakeCollectionThumbnailImage(collection.RoadieId);
row.SortName = collection.SortName ?? collection.Name;
break;
case BookmarkType.Label:
var label = this.DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (label == null)
{
continue;
}
row.Bookmark = new DataToken
var label = DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (label == null) continue;
row.Bookmark = new models.DataToken
{
Text = label.Name,
Value = label.RoadieId.ToString()
};
row.Label = models.LabelList.FromDataLabel(label, this.MakeLabelThumbnailImage(label.RoadieId));
row.Thumbnail = this.MakeLabelThumbnailImage(label.RoadieId);
row.Label = models.LabelList.FromDataLabel(label, MakeLabelThumbnailImage(label.RoadieId));
row.Thumbnail = MakeLabelThumbnailImage(label.RoadieId);
row.SortName = label.SortName ?? label.Name;
break;
}
};
;
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<BookmarkList>
return Task.FromResult(new Library.Models.Pagination.PagedResult<models.BookmarkList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,

View file

@ -8,8 +8,10 @@ using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Models.Collections;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Statistics;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
@ -20,28 +22,27 @@ using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
using Roadie.Library.Models;
namespace Roadie.Api.Services
{
public class CollectionService : ServiceBase, ICollectionService
{
private IBookmarkService BookmarkService { get; } = null;
private IBookmarkService BookmarkService { get; }
public CollectionService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<CollectionService> logger,
IBookmarkService bookmarkService)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<CollectionService> logger,
IBookmarkService bookmarkService)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
this.BookmarkService = bookmarkService;
BookmarkService = bookmarkService;
}
/// <summary>
/// Get blank Collection to add
/// Get blank Collection to add
/// </summary>
/// <param name="roadieUser"></param>
/// <returns></returns>
@ -57,16 +58,16 @@ namespace Roadie.Api.Services
};
var result = collection.Adapt<Collection>();
result.Id = id;
result.Thumbnail = this.MakeNewImage("collection");
result.MediumThumbnail = this.MakeNewImage("collection");
result.Maintainer = new Library.Models.DataToken
result.Thumbnail = MakeNewImage("collection");
result.MediumThumbnail = MakeNewImage("collection");
result.Maintainer = new DataToken
{
Value = roadieUser.UserId.ToString(),
Text = roadieUser.UserName
};
sw.Stop();
return new OperationResult<Collection>()
return new OperationResult<Collection>
{
Data = result,
IsSuccess = true,
@ -74,39 +75,42 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id,
IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var result = await this.CacheManager.GetAsync<OperationResult<Collection>>(cacheKey, async () =>
{
return await this.CollectionByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id,
includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey,
async () => { return await CollectionByIdAction(id, includes); }, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
var userBookmarkResult =
await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
}
result.Data.UserBookmarked =
userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) !=
null;
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
var userCommentReaction =
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Collection>(result.Messages)
{
Data = result?.Data,
@ -122,28 +126,27 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collection = this.DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
if (collection == null)
{
return new OperationResult<bool>(true, $"Collection Not Found [{ id }]");
}
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
if (collection == null) return new OperationResult<bool>(true, $"Collection Not Found [{id}]");
if (!user.IsEditor)
{
this.Logger.LogWarning($"DeleteCollection: Access Denied: `{ collection }`, By User `{user }`");
Logger.LogWarning($"DeleteCollection: Access Denied: `{collection}`, By User `{user}`");
return new OperationResult<bool>("Access Denied");
}
try
{
this.DbContext.Collections.Remove(collection);
await this.DbContext.SaveChangesAsync();
DbContext.Collections.Remove(collection);
await DbContext.SaveChangesAsync();
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
this.Logger.LogInformation($"DeleteCollection `{ collection }`, By User `{user }`");
Logger.LogInformation($"DeleteCollection `{collection}`, By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
@ -153,7 +156,8 @@ namespace Roadie.Api.Services
};
}
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request,
bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
{
var sw = new Stopwatch();
sw.Start();
@ -167,7 +171,7 @@ namespace Roadie.Api.Services
join `artist` a on r.artistId = a.id
where a.roadieId = {0}";
collections = this.DbContext.Collections.FromSql(sql, artistId);
collections = DbContext.Collections.FromSql(sql, artistId);
}
else if (releaseId.HasValue)
{
@ -177,25 +181,27 @@ namespace Roadie.Api.Services
join `release` r on r.id = cr.releaseId
where r.roadieId = {0}";
collections = this.DbContext.Collections.FromSql(sql, releaseId);
collections = DbContext.Collections.FromSql(sql, releaseId);
}
else
{
collections = this.DbContext.Collections;
collections = DbContext.Collections;
}
var result = (from c in collections
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && c.Name.Contains(request.Filter)))
where (request.FilterToStatusValue == Statuses.Ok || (c.Status == request.FilterToStatusValue))
select CollectionList.FromDataCollection(c, (from crc in this.DbContext.CollectionReleases
where crc.CollectionId == c.Id
select crc.Id).Count(), this.MakeCollectionThumbnailImage(c.RoadieId)));
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } }) : request.OrderValue(null);
var result = from c in collections
where request.FilterValue.Length == 0 ||
request.FilterValue.Length > 0 && c.Name.Contains(request.Filter)
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
select CollectionList.FromDataCollection(c, (from crc in DbContext.CollectionReleases
where crc.CollectionId == c.Id
select crc.Id).Count(), MakeCollectionThumbnailImage(c.RoadieId));
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
if (request.FilterToStatusValue == Statuses.Incomplete)
{
rows = rows.OrderByDescending(x => x.PercentComplete).ThenBy(x => x.SortName).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
{
@ -208,7 +214,7 @@ namespace Roadie.Api.Services
}
/// <summary>
/// Updates (or Adds) Collection
/// Updates (or Adds) Collection
/// </summary>
public async Task<OperationResult<bool>> UpdateCollection(User user, Collection model)
{
@ -219,16 +225,15 @@ namespace Roadie.Api.Services
sw.Start();
var errors = new List<Exception>();
data.Collection collection = new data.Collection();
var collection = new data.Collection();
if (!isNew)
{
collection = this.DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
if (collection == null)
{
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", model.Id));
}
}
collection.IsLocked = model.IsLocked;
collection.Name = model.Name;
collection.SortName = model.SortName;
@ -251,26 +256,23 @@ namespace Roadie.Api.Services
collection.Thumbnail = ImageHelper.ConvertToJpegFormat(collectionImage);
// Resize to store in database as thumbnail
collection.Thumbnail = ImageHelper.ResizeImage(collection.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
collection.Thumbnail = ImageHelper.ResizeImage(collection.Thumbnail,
Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
}
if (model.Maintainer?.Value != null)
{
var maintainer = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
if (maintainer != null)
{
collection.MaintainerId = maintainer.Id;
}
var maintainer =
DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
if (maintainer != null) collection.MaintainerId = maintainer.Id;
}
collection.LastUpdated = now;
if (isNew)
{
await this.DbContext.Collections.AddAsync(collection);
}
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(collection.CacheRegion);
this.Logger.LogInformation($"UpdateArtist `{ collection }` By User `{ user }`");
if (isNew) await DbContext.Collections.AddAsync(collection);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(collection.CacheRegion);
Logger.LogInformation($"UpdateArtist `{collection}` By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
@ -285,16 +287,15 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
sw.Start();
var collection = this.GetCollection(id);
var collection = GetCollection(id);
if (collection == null)
{
return Task.FromResult(new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id)));
}
return Task.FromResult(new OperationResult<Collection>(true,
string.Format("Collection Not Found [{0}]", id)));
var result = collection.Adapt<Collection>();
var maintainer = this.DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
result.Maintainer = new Library.Models.DataToken
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
result.Maintainer = new DataToken
{
Text = maintainer.UserName,
Value = maintainer.RoadieId.ToString()
@ -302,9 +303,10 @@ namespace Roadie.Api.Services
result.AlternateNames = collection.AlternateNames;
result.Tags = collection.Tags;
result.URLs = collection.URLs;
result.Thumbnail = this.MakeCollectionThumbnailImage(collection.RoadieId);
result.MediumThumbnail = base.MakeThumbnailImage(id, "collection", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
result.CollectionFoundCount = (from crc in this.DbContext.CollectionReleases
result.Thumbnail = MakeCollectionThumbnailImage(collection.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(id, "collection", Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height);
result.CollectionFoundCount = (from crc in DbContext.CollectionReleases
where crc.CollectionId == collection.Id
select crc.Id).Count();
if (includes != null && includes.Any())
@ -321,31 +323,30 @@ namespace Roadie.Api.Services
}
if (includes.Contains("releases"))
{
result.Releases = (from crc in this.DbContext.CollectionReleases
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
result.Releases = (from crc in DbContext.CollectionReleases
join r in DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
where crc.CollectionId == collection.Id
orderby crc.ListNumber
select new CollectionRelease
{
ListNumber = crc.ListNumber,
Release = Library.Models.Releases.ReleaseList.FromDataRelease(r, r.Artist, this.HttpContext.BaseUrl, this.MakeArtistThumbnailImage(r.Artist.RoadieId), this.MakeReleaseThumbnailImage(r.RoadieId))
Release = ReleaseList.FromDataRelease(r, r.Artist, HttpContext.BaseUrl,
MakeArtistThumbnailImage(r.Artist.RoadieId), MakeReleaseThumbnailImage(r.RoadieId))
}).ToArray();
}
if (includes.Contains("stats"))
{
var collectionReleases = (from crc in this.DbContext.CollectionReleases
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
where crc.CollectionId == collection.Id
select r);
var collectionReleases = from crc in DbContext.CollectionReleases
join r in DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
where crc.CollectionId == collection.Id
select r;
var collectionTracks = (from crc in this.DbContext.CollectionReleases
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where crc.CollectionId == collection.Id
select t);
var collectionTracks = from crc in DbContext.CollectionReleases
join r in DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where crc.CollectionId == collection.Id
select t;
result.Statistics = new CollectionStatistics
{
@ -359,25 +360,31 @@ namespace Roadie.Api.Services
TrackPlayedCount = collectionReleases.Sum(x => x.PlayedCount)
};
}
if (includes.Contains("comments"))
{
var collectionComments = this.DbContext.Comments.Include(x => x.User).Where(x => x.CollectionId == collection.Id).OrderByDescending(x => x.CreatedDate).ToArray();
var collectionComments = DbContext.Comments.Include(x => x.User)
.Where(x => x.CollectionId == collection.Id).OrderByDescending(x => x.CreatedDate).ToArray();
if (collectionComments.Any())
{
var comments = new List<Comment>();
var commentIds = collectionComments.Select(x => x.Id).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
select cr).ToArray();
foreach (var collectionComment in collectionComments)
{
var comment = collectionComment.Adapt<Comment>();
comment.DatabaseId = collectionComment.Id;
comment.User = UserList.FromDataUser(collectionComment.User, this.MakeUserThumbnailImage(collectionComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Like);
comment.User = UserList.FromDataUser(collectionComment.User,
MakeUserThumbnailImage(collectionComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x =>
x.CommentId == collectionComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment);
}
result.Comments = comments;
}
}

View file

@ -10,7 +10,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
@ -19,11 +18,11 @@ namespace Roadie.Api.Services
public class CommentService : ServiceBase, ICommentService
{
public CommentService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<CommentService> logger)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<CommentService> logger)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
}
@ -33,12 +32,10 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var artist = this.DbContext.Artists
.FirstOrDefault(x => x.RoadieId == artistId);
var artist = DbContext.Artists
.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null)
{
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistId));
}
var newComment = new data.Comment
{
@ -46,9 +43,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(artist.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(artist.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -65,12 +62,10 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var collection = this.DbContext.Collections
.FirstOrDefault(x => x.RoadieId == collectionId);
var collection = DbContext.Collections
.FirstOrDefault(x => x.RoadieId == collectionId);
if (collection == null)
{
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", collectionId));
}
var newComment = new data.Comment
{
@ -78,9 +73,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(collection.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(collection.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -97,12 +92,9 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var genre = this.DbContext.Genres
.FirstOrDefault(x => x.RoadieId == genreId);
if (genre == null)
{
return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", genreId));
}
var genre = DbContext.Genres
.FirstOrDefault(x => x.RoadieId == genreId);
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", genreId));
var newComment = new data.Comment
{
@ -110,9 +102,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(genre.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(genre.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -129,12 +121,9 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var label = this.DbContext.Labels
.FirstOrDefault(x => x.RoadieId == labelId);
if (label == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", labelId));
}
var label = DbContext.Labels
.FirstOrDefault(x => x.RoadieId == labelId);
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", labelId));
var newComment = new data.Comment
{
@ -142,9 +131,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(label.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -161,12 +150,10 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var playlist = this.DbContext.Playlists
.FirstOrDefault(x => x.RoadieId == playlistId);
var playlist = DbContext.Playlists
.FirstOrDefault(x => x.RoadieId == playlistId);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", playlistId));
}
var newComment = new data.Comment
{
@ -174,9 +161,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(playlist.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(playlist.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -193,12 +180,10 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var release = this.DbContext.Releases
.FirstOrDefault(x => x.RoadieId == releaseId);
var release = DbContext.Releases
.FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null)
{
return new OperationResult<bool>(true, string.Format("Release Not Found [{0}]", releaseId));
}
var newComment = new data.Comment
{
@ -206,9 +191,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(release.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(release.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -225,12 +210,9 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var track = this.DbContext.Tracks
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null)
{
return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", trackId));
}
var track = DbContext.Tracks
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null) return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", trackId));
var newComment = new data.Comment
{
@ -238,9 +220,9 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
this.DbContext.Comments.Add(newComment);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(track.CacheRegion);
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(track.CacheRegion);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -257,14 +239,11 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var comment = this.DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null)
{
return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
}
this.DbContext.Remove(comment);
await this.DbContext.SaveChangesAsync();
this.ClearCaches(comment);
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
DbContext.Remove(comment);
await DbContext.SaveChangesAsync();
ClearCaches(comment);
sw.Stop();
result = true;
return new OperationResult<bool>
@ -281,12 +260,10 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var comment = this.DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null)
{
return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
}
var userCommentReaction = this.DbContext.CommentReactions.FirstOrDefault(x => x.CommentId == comment.Id && x.UserId == user.Id);
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
var userCommentReaction =
DbContext.CommentReactions.FirstOrDefault(x => x.CommentId == comment.Id && x.UserId == user.Id);
if (userCommentReaction == null)
{
userCommentReaction = new data.CommentReaction
@ -294,17 +271,20 @@ namespace Roadie.Api.Services
CommentId = comment.Id,
UserId = user.Id.Value
};
this.DbContext.CommentReactions.Add(userCommentReaction);
DbContext.CommentReactions.Add(userCommentReaction);
}
userCommentReaction.Reaction = reaction == CommentReaction.Unknown ? null : reaction.ToString();
await this.DbContext.SaveChangesAsync();
this.ClearCaches(comment);
var userCommentReactions = (from cr in this.DbContext.CommentReactions
await DbContext.SaveChangesAsync();
ClearCaches(comment);
var userCommentReactions = (from cr in DbContext.CommentReactions
where cr.CommentId == comment.Id
select cr).ToArray();
var additionalData = new Dictionary<string, object>();
additionalData.Add("likedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
additionalData.Add("dislikedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
additionalData.Add("likedCount",
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
additionalData.Add("dislikedCount",
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
sw.Stop();
result = true;
return new OperationResult<bool>
@ -322,59 +302,38 @@ namespace Roadie.Api.Services
switch (comment.CommentType)
{
case CommentType.Artist:
var artist = this.DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
if (artist != null)
{
this.CacheManager.ClearRegion(artist.CacheRegion);
}
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
if (artist != null) CacheManager.ClearRegion(artist.CacheRegion);
break;
case CommentType.Collection:
var collection = this.DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
if (collection != null)
{
this.CacheManager.ClearRegion(collection.CacheRegion);
}
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
if (collection != null) CacheManager.ClearRegion(collection.CacheRegion);
break;
case CommentType.Genre:
var genre = this.DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
if (genre != null)
{
this.CacheManager.ClearRegion(genre.CacheRegion);
}
var genre = DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
if (genre != null) CacheManager.ClearRegion(genre.CacheRegion);
break;
case CommentType.Label:
var label = this.DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
if (label != null)
{
this.CacheManager.ClearRegion(label.CacheRegion);
}
var label = DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
if (label != null) CacheManager.ClearRegion(label.CacheRegion);
break;
case CommentType.Playlist:
var playlist = this.DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
if (playlist != null)
{
this.CacheManager.ClearRegion(playlist.CacheRegion);
}
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
if (playlist != null) CacheManager.ClearRegion(playlist.CacheRegion);
break;
case CommentType.Release:
var release = this.DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
if (release != null)
{
this.CacheManager.ClearRegion(release.CacheRegion);
}
var release = DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
if (release != null) CacheManager.ClearRegion(release.CacheRegion);
break;
case CommentType.Track:
var track = this.DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
if (track != null)
{
this.CacheManager.ClearRegion(track.CacheRegion);
}
var track = DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
if (track != null) CacheManager.ClearRegion(track.CacheRegion);
break;
}
}

View file

@ -2,8 +2,6 @@
using Roadie.Library.Configuration;
using System.Net;
using System.Net.Mail;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
namespace Roadie.Api.Services
@ -14,28 +12,25 @@ namespace Roadie.Api.Services
public EmailSenderService(IRoadieSettings configuration)
{
this.Configuration = configuration;
Configuration = configuration;
}
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
using (MailMessage mail = new MailMessage(this.Configuration.SmtpFromAddress, email))
using (var mail = new MailMessage(Configuration.SmtpFromAddress, email))
{
using (SmtpClient client = new SmtpClient())
using (var client = new SmtpClient())
{
client.Port = this.Configuration.SmtpPort;
client.EnableSsl = this.Configuration.SmtpUseSSl;
client.Port = Configuration.SmtpPort;
client.EnableSsl = Configuration.SmtpUseSSl;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(this.Configuration.SmtpUsername, this.Configuration.SmtpPassword);
client.Host = this.Configuration.SmtpHost;
client.Credentials = new NetworkCredential(Configuration.SmtpUsername, Configuration.SmtpPassword);
client.Host = Configuration.SmtpHost;
mail.Subject = subject;
mail.IsBodyHtml = true;
mail.Body = htmlMessage;
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
};
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
await client.SendMailAsync(mail);
}
}

View file

@ -19,16 +19,17 @@ namespace Roadie.Api.Services
public class GenreService : ServiceBase, IGenreService
{
public GenreService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<GenreService> logger)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<GenreService> logger)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
}
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
public Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request,
bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
@ -38,30 +39,31 @@ namespace Roadie.Api.Services
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
}
var result = (from g in this.DbContext.Genres
let releaseCount = (from rg in this.DbContext.ReleaseGenres
where rg.GenreId == g.Id
select rg.Id).Count()
let artistCount = (from rg in this.DbContext.ArtistGenres
var result = from g in DbContext.Genres
let releaseCount = (from rg in DbContext.ReleaseGenres
where rg.GenreId == g.Id
select rg.Id).Count()
where (request.FilterValue.Length == 0 || (g.Name.Contains(request.FilterValue)))
select new GenreList
{
DatabaseId = g.Id,
Id = g.RoadieId,
Genre = new DataToken
{
Text = g.Name,
Value = g.RoadieId.ToString()
},
ReleaseCount = releaseCount,
ArtistCount = artistCount,
CreatedDate = g.CreatedDate,
LastUpdated = g.LastUpdated,
});
let artistCount = (from rg in DbContext.ArtistGenres
where rg.GenreId == g.Id
select rg.Id).Count()
where request.FilterValue.Length == 0 || g.Name.Contains(request.FilterValue)
select new GenreList
{
DatabaseId = g.Id,
Id = g.RoadieId,
Genre = new DataToken
{
Text = g.Name,
Value = g.RoadieId.ToString()
},
ReleaseCount = releaseCount,
ArtistCount = artistCount,
CreatedDate = g.CreatedDate,
LastUpdated = g.LastUpdated
};
GenreList[] rows = null;
GenreList[] rows;
var rowCount = result.Count();
if (doRandomize ?? false)
{
@ -71,9 +73,12 @@ namespace Roadie.Api.Services
}
else
{
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } }) : request.OrderValue(null);
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Genre.Text", "ASC" } })
: request.OrderValue();
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<GenreList>
{

View file

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Roadie.Library.Configuration;
using Roadie.Library.Utility;
@ -7,22 +8,18 @@ namespace Roadie.Api.Services
public class HttpContext : IHttpContext
{
public string BaseUrl { get; set; }
public string ImageBaseUrl { get; set; }
public HttpContext(IRoadieSettings configuration, IUrlHelper urlHelper)
{
var scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
if (configuration.UseSSLBehindProxy)
{
scheme = "https";
}
if (configuration.UseSSLBehindProxy) scheme = "https";
var host = urlHelper.ActionContext.HttpContext.Request.Host;
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
{
host = new Microsoft.AspNetCore.Http.HostString(configuration.BehindProxyHost);
}
this.BaseUrl = $"{ scheme }://{ host }";
this.ImageBaseUrl = $"{ this.BaseUrl}/images";
host = new HostString(configuration.BehindProxyHost);
BaseUrl = $"{scheme}://{host}";
ImageBaseUrl = $"{BaseUrl}/images";
}
}
}

View file

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.WebUtilities;
using Roadie.Library.Encoding;
using System.Text;
using System.Web;
namespace Roadie.Api.Services
@ -28,7 +29,7 @@ namespace Roadie.Api.Services
public string UrlEncodeBase64(string input)
{
return WebEncoders.Base64UrlEncode(System.Text.Encoding.ASCII.GetBytes(input));
return WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(input));
}
}
}

View file

@ -11,7 +11,8 @@ namespace Roadie.Api.Services
{
Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId);
Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId,
bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
@ -27,16 +28,19 @@ namespace Roadie.Api.Services
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user);
Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false,
bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false);
Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId, bool isReadOnly = false,
bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanInboundFolder(ApplicationUser user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanLibraryFolder(ApplicationUser user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false,
bool wasDoneForInvalidTrackPlay = false);
}
}

View file

@ -13,14 +13,15 @@ namespace Roadie.Api.Services
{
Task<OperationResult<Artist>> ById(User roadieUser, Guid id, IEnumerable<string> includes);
Task<PagedResult<ArtistList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
Task<PagedResult<ArtistList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
bool? onlyIncludeWithReleases = true);
Task<OperationResult<bool>> MergeArtists(User user, Guid artistToMergeId, Guid artistToMergeIntoId);
Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateArtist(User user, Artist artist);
Task<OperationResult<Library.Models.Image>> UploadArtistImage(User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadArtistImage(User user, Guid id, IFormFile file);
}
}

View file

@ -8,6 +8,7 @@ namespace Roadie.Api.Services
{
public interface IBookmarkService
{
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
BookmarkType? filterType = null);
}
}

View file

@ -16,7 +16,8 @@ namespace Roadie.Api.Services
Task<OperationResult<bool>> DeleteCollection(User user, Guid id);
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
Guid? releaseId = null, Guid? artistId = null);
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
}

View file

@ -1,5 +1,6 @@
using Microsoft.Net.Http.Headers;
using Roadie.Library;
using Roadie.Library.Models;
using Roadie.Library.Models.Users;
using Roadie.Library.SearchEngines.Imaging;
using System;
@ -10,30 +11,36 @@ namespace Roadie.Api.Services
{
public interface IImageService
{
Task<FileOperationResult<Library.Models.Image>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>>
ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height,
EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> CollectionImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null);
Task<OperationResult<bool>> Delete(User user, Guid id);
Task<OperationResult<IEnumerable<ImageSearchResult>>> ImageProvidersSearch(string query);
Task<FileOperationResult<Library.Models.Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> ReleaseImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height,
EntityTagHeaderValue etag = null);
Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10);
Task<FileOperationResult<Library.Models.Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Image>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
}
}

View file

@ -10,8 +10,11 @@ namespace Roadie.Api.Services
{
public interface IPlayActivityService
{
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null,
DateTime? newerThan = null);
Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble);
Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble);
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
}
}

View file

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Roadie.Library;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Users;
@ -13,16 +14,18 @@ namespace Roadie.Api.Services
{
Task<OperationResult<Release>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<PagedResult<ReleaseList>> List(User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
Task<PagedResult<ReleaseList>> List(User user, PagedRequest request, bool? doRandomize = false,
IEnumerable<string> includes = null);
Task<OperationResult<bool>> MergeReleases(User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
Task<OperationResult<bool>> MergeReleases(User user, Guid releaseToMergeId, Guid releaseToMergeIntoId,
bool addAsMedia);
Task<FileOperationResult<byte[]>> ReleaseZipped(User roadieUser, Guid id);
Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateRelease(User user, Release release);
Task<OperationResult<Library.Models.Image>> UploadReleaseImage(User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadReleaseImage(User user, Guid id, IFormFile file);
}
}

View file

@ -1,73 +1,82 @@
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
using Roadie.Library.Models;
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
using System.Threading.Tasks;
using User = Roadie.Library.Models.Users.User;
namespace Roadie.Api.Services
{
public interface ISubsonicService
{
Task<SubsonicOperationResult<Response>> AddChatMessage(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> AddChatMessage(Request request, User roadieUser);
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> Authenticate(Request request);
Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, Roadie.Library.Models.Users.User roadieUser, int position, string comment);
Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, User roadieUser, int position,
string comment);
Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, Roadie.Library.Models.Users.User roadieUser, string name, string[] songIds, string playlistId = null);
Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, User roadieUser, string name,
string[] songIds, string playlistId = null);
Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> DeletePlaylist(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> DeletePlaylist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbum(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbum(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbumInfo(Request request, Roadie.Library.Models.Users.User roadieUser, AlbumInfoVersion version);
Task<SubsonicOperationResult<Response>>
GetAlbumInfo(Request request, User roadieUser, AlbumInfoVersion version);
Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, Roadie.Library.Models.Users.User roadieUser, AlbumListVersions version);
Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, User roadieUser,
AlbumListVersions version);
Task<SubsonicOperationResult<Response>> GetArtist(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent,
ArtistInfoVersion version);
Task<SubsonicOperationResult<Response>> GetArtists(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtists(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetBookmarks(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetBookmarks(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, Roadie.Library.Models.Users.User roadieUser, long? since);
Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, User roadieUser, long? since);
Task<SubsonicFileOperationResult<Roadie.Library.Models.Image>> GetCoverArt(Request request, int? size);
Task<SubsonicFileOperationResult<Image>> GetCoverArt(Request request, int? size);
Task<SubsonicOperationResult<Response>> GetGenres(Request request);
Task<SubsonicOperationResult<Response>> GetIndexes(Request request, Roadie.Library.Models.Users.User roadieUser, long? ifModifiedSince = null);
Task<SubsonicOperationResult<Response>> GetIndexes(Request request, User roadieUser,
long? ifModifiedSince = null);
SubsonicOperationResult<Response> GetLicense(Request request);
SubsonicOperationResult<Response> GetLyrics(Request request, string artistId, string title);
Task<SubsonicOperationResult<Response>> GetMusicDirectory(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetMusicDirectory(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetMusicFolders(Request request);
Task<SubsonicOperationResult<Response>> GetNowPlaying(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetNowPlaying(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylist(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylists(Request request, Roadie.Library.Models.Users.User roadieUser, string filterToUserName);
Task<SubsonicOperationResult<Response>> GetPlaylists(Request request, User roadieUser, string filterToUserName);
Task<SubsonicOperationResult<Response>> GetPlayQueue(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlayQueue(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPodcasts(Request request);
Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, Roadie.Library.Models.Users.User roadieUser, SimilarSongsVersion version, int? count = 50);
Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, User roadieUser,
SimilarSongsVersion version, int? count = 50);
Task<SubsonicOperationResult<Response>> GetSong(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetSong(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSongsByGenre(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<SubsonicOperationResult<Response>> GetSongsByGenre(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetStarred(Request request, Roadie.Library.Models.Users.User roadieUser, StarredVersion version);
Task<SubsonicOperationResult<Response>> GetStarred(Request request, User roadieUser, StarredVersion version);
Task<SubsonicOperationResult<Response>> GetTopSongs(Request request, Roadie.Library.Models.Users.User roadieUser, int? count = 50);
Task<SubsonicOperationResult<Response>> GetTopSongs(Request request, User roadieUser, int? count = 50);
Task<SubsonicOperationResult<Response>> GetUser(Request request, string username);
@ -75,14 +84,18 @@ namespace Roadie.Api.Services
SubsonicOperationResult<Response> Ping(Request request);
Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, Roadie.Library.Models.Users.User roadieUser, string current, long? position);
Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, User roadieUser, string current,
long? position);
Task<SubsonicOperationResult<Response>> Search(Request request, Roadie.Library.Models.Users.User roadieUser, SearchVersion version);
Task<SubsonicOperationResult<Response>> Search(Request request, User roadieUser, SearchVersion version);
Task<SubsonicOperationResult<Response>> SetRating(Request request, Roadie.Library.Models.Users.User roadieUser, short rating);
Task<SubsonicOperationResult<Response>> SetRating(Request request, User roadieUser, short rating);
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, Roadie.Library.Models.Users.User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, User roadieUser, bool star,
string[] albumIds = null, string[] artistIds = null);
Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, Roadie.Library.Models.Users.User roadieUser, string playlistId, string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null, int[] songIndexesToRemove = null);
Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, User roadieUser, string playlistId,
string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null,
int[] songIndexesToRemove = null);
}
}

View file

@ -12,11 +12,13 @@ namespace Roadie.Api.Services
{
Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes);
Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
Task<PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false,
Guid? releaseId = null);
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser);
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes,
User roadieUser);
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
}

View file

@ -43,8 +43,8 @@ namespace Roadie.Api.Services
Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating);
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token);
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
}
}

View file

@ -6,6 +6,7 @@ using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
@ -25,105 +26,91 @@ namespace Roadie.Api.Services
public class ImageService : ServiceBase, IImageService
{
private IImageSearchEngine BingSearchEngine { get; }
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
private IImageSearchEngine ITunesSearchEngine { get; }
private string Referrer { get; }
private string RequestIp { get; }
public ImageService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<ImageService> logger,
IDefaultNotFoundImages defaultNotFoundImages)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<ImageService> logger,
IDefaultNotFoundImages defaultNotFoundImages)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
this.DefaultNotFoundImages = defaultNotFoundImages;
this.BingSearchEngine = new BingImageSearchEngine(configuration, logger, this.RequestIp, this.Referrer);
this.ITunesSearchEngine = new ITunesSearchEngine(configuration, cacheManager, logger, this.RequestIp, this.Referrer);
DefaultNotFoundImages = defaultNotFoundImages;
BingSearchEngine = new BingImageSearchEngine(configuration, logger, RequestIp, Referrer);
ITunesSearchEngine = new ITunesSearchEngine(configuration, cacheManager, logger, RequestIp, Referrer);
}
public async Task<FileOperationResult<Image>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ArtistImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ArtistImage",
regionUrn: data.Artist.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ArtistImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("ArtistImage",
data.Artist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<Image>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ArtistSecondaryImage(Guid id, int imageId, int? width,
int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: $"ArtistSecondaryThumbnail-{imageId}",
regionUrn: data.Release.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ArtistSecondaryImageAction(id, imageId, etag);
},
etag: etag);
return await GetImageFileOperation($"ArtistSecondaryThumbnail-{imageId}",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistSecondaryImageAction(id, imageId, etag); },
etag);
}
public async Task<FileOperationResult<Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ById(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ImageById",
regionUrn: data.Image.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ImageByIdAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("ImageById",
data.Image.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ImageByIdAction(id, etag); },
etag);
}
public async Task<FileOperationResult<Image>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> CollectionImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "CollectionThumbnail",
regionUrn: data.Collection.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.CollectionImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("CollectionThumbnail",
data.Collection.CacheRegionUrn(id),
id,
width,
height,
async () => { return await CollectionImageAction(id, etag); },
etag);
}
public async Task<OperationResult<bool>> Delete(User user, Guid id)
{
var sw = Stopwatch.StartNew();
var image = this.DbContext.Images
.Include("Release")
.Include("Artist")
.FirstOrDefault(x => x.RoadieId == id);
if (image == null)
{
return new OperationResult<bool>(true, string.Format("Image Not Found [{0}]", id));
}
if (image.ArtistId.HasValue)
{
this.CacheManager.ClearRegion(data.Artist.CacheRegionUrn(image.Artist.RoadieId));
}
if (image.ReleaseId.HasValue)
{
this.CacheManager.ClearRegion(data.Release.CacheRegionUrn(image.Release.RoadieId));
}
this.DbContext.Images.Remove(image);
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(data.Image.CacheRegionUrn(id));
this.Logger.LogInformation($"Deleted Image [{ id }], By User [{ user.ToString() }]");
var image = DbContext.Images
.Include("Release")
.Include("Artist")
.FirstOrDefault(x => x.RoadieId == id);
if (image == null) return new OperationResult<bool>(true, string.Format("Image Not Found [{0}]", id));
if (image.ArtistId.HasValue) CacheManager.ClearRegion(data.Artist.CacheRegionUrn(image.Artist.RoadieId));
if (image.ReleaseId.HasValue) CacheManager.ClearRegion(data.Release.CacheRegionUrn(image.Release.RoadieId));
DbContext.Images.Remove(image);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(data.Image.CacheRegionUrn(id));
Logger.LogInformation($"Deleted Image [{id}], By User [{user}]");
sw.Stop();
return new OperationResult<bool>
{
@ -141,14 +128,15 @@ namespace Roadie.Api.Services
IEnumerable<ImageSearchResult> searchResults = null;
try
{
var manager = new ImageSearchManager(this.Configuration, this.CacheManager, this.Logger);
var manager = new ImageSearchManager(Configuration, CacheManager, Logger);
searchResults = await manager.ImageSearch(query);
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<IEnumerable<ImageSearchResult>>
{
@ -159,60 +147,52 @@ namespace Roadie.Api.Services
};
}
public async Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "LabelThumbnail",
regionUrn: data.Label.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.LabelImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("LabelThumbnail",
data.Label.CacheRegionUrn(id),
id,
width,
height,
async () => { return await LabelImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "PlaylistThumbnail",
regionUrn: data.Playlist.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.PlaylistImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("PlaylistThumbnail",
data.Playlist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await PlaylistImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ReleaseImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ReleaseThumbnail",
regionUrn: data.Release.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ReleaseImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("ReleaseThumbnail",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ReleaseImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ReleaseSecondaryImage(Guid id, int imageId, int? width,
int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: $"ReleaseSecondaryThumbnail-{imageId}",
regionUrn: data.Release.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ReleaseSecondaryImageAction(id, imageId, etag);
},
etag: etag);
return await GetImageFileOperation($"ReleaseSecondaryThumbnail-{imageId}",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ReleaseSecondaryImageAction(id, imageId, etag); },
etag);
}
public async Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10)
@ -224,21 +204,13 @@ namespace Roadie.Api.Services
if (WebHelper.IsStringUrl(query))
{
var s = ImageHelper.ImageSearchResultForImageUrl(query);
if (s != null)
{
result.Add(s);
}
}
var bingResults = await this.BingSearchEngine.PerformImageSearch(query, resultsCount);
if (bingResults != null)
{
result.AddRange(bingResults);
}
var iTunesResults = await this.ITunesSearchEngine.PerformImageSearch(query, resultsCount);
if (iTunesResults != null)
{
result.AddRange(iTunesResults);
if (s != null) result.Add(s);
}
var bingResults = await BingSearchEngine.PerformImageSearch(query, resultsCount);
if (bingResults != null) result.AddRange(bingResults);
var iTunesResults = await ITunesSearchEngine.PerformImageSearch(query, resultsCount);
if (iTunesResults != null) result.AddRange(iTunesResults);
sw.Stop();
return new OperationResult<IEnumerable<ImageSearchResult>>
{
@ -248,66 +220,60 @@ namespace Roadie.Api.Services
};
}
public async Task<FileOperationResult<Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> TrackImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "TrackThumbnail",
regionUrn: data.Track.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.TrackImageAction(id, width, height, etag);
},
etag: etag);
return await GetImageFileOperation("TrackThumbnail",
data.Track.CacheRegionUrn(id),
id,
width,
height,
async () => { return await TrackImageAction(id, width, height, etag); },
etag);
}
public async Task<FileOperationResult<Image>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> UserImage(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "UserById",
regionUrn: ApplicationUser.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.UserImageAction(id, etag);
},
etag: etag);
return await GetImageFileOperation("UserById",
ApplicationUser.CacheRegionUrn(id),
id,
width,
height,
async () => { return await UserImageAction(id, etag); },
etag);
}
private Task<FileOperationResult<Image>> ArtistImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
var artist = this.GetArtist(id);
var artist = GetArtist(id);
if (artist == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Artist Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Artist Not Found [{0}]", id)));
byte[] imageBytes = null;
string artistFolder = null;
try
{
// See if artist images exists in artist folder
artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
artistFolder = artist.ArtistFileFolder(Configuration, Configuration.LibraryFolder);
if (!Directory.Exists(artistFolder))
{
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ artist.ToString() }`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
}
else
{
var artistImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), Library.Enums.ImageType.Artist);
if (artistImages.Any())
{
imageBytes = File.ReadAllBytes(artistImages.First().FullName);
}
var artistImages =
ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.Artist);
if (artistImages.Any()) imageBytes = File.ReadAllBytes(artistImages.First().FullName);
}
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error Reading Folder [{ artistFolder }] For Artist [{ artist.Id }]");
Logger.LogError(ex, $"Error Reading Folder [{artistFolder}] For Artist [{artist.Id}]");
}
imageBytes = imageBytes ?? artist.Thumbnail;
var image = new data.Image
{
@ -315,51 +281,50 @@ namespace Roadie.Api.Services
CreatedDate = artist.CreatedDate,
LastUpdated = artist.LastUpdated
};
if (imageBytes == null || !imageBytes.Any())
{
image = this.DefaultNotFoundImages.Artist;
}
if (imageBytes == null || !imageBytes.Any()) image = DefaultNotFoundImages.Artist;
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Artist Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Artist Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
private Task<FileOperationResult<Image>> ArtistSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
private Task<FileOperationResult<Image>> ArtistSecondaryImageAction(Guid id, int imageId,
EntityTagHeaderValue etag = null)
{
try
{
var artist = this.GetArtist(id);
var artist = GetArtist(id);
if (artist == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Release Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Release Not Found [{0}]", id)));
byte[] imageBytes = null;
string artistFolder = null;
try
{
// See if cover art file exists in release folder
artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
artistFolder = artist.ArtistFileFolder(Configuration, Configuration.LibraryFolder);
if (!Directory.Exists(artistFolder))
{
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ artist }`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
}
else
{
var artistSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), Library.Enums.ImageType.ArtistSecondary).ToArray();
var artistSecondaryImages = ImageHelper
.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary)
.ToArray();
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
{
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
}
}
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error Reading Artist Folder [{ artistFolder }] For Artist `{ artist }`");
Logger.LogError(ex, $"Error Reading Artist Folder [{artistFolder}] For Artist `{artist}`");
}
var image = new data.Image
{
Bytes = imageBytes,
@ -370,8 +335,9 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Release Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
@ -379,11 +345,10 @@ namespace Roadie.Api.Services
{
try
{
var collection = this.GetCollection(id);
var collection = GetCollection(id);
if (collection == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Collection Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Collection Not Found [{0}]", id)));
var image = new data.Image
{
Bytes = collection.Thumbnail,
@ -391,63 +356,57 @@ namespace Roadie.Api.Services
LastUpdated = collection.LastUpdated
};
if (collection.Thumbnail == null || !collection.Thumbnail.Any())
{
image = this.DefaultNotFoundImages.Collection;
}
image = DefaultNotFoundImages.Collection;
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Collection Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Collection Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
private FileOperationResult<Image> GenerateFileOperationResult(Guid id, data.Image image, EntityTagHeaderValue etag = null, string contentType = "image/jpeg")
private FileOperationResult<Image> GenerateFileOperationResult(Guid id, data.Image image,
EntityTagHeaderValue etag = null, string contentType = "image/jpeg")
{
var imageEtag = EtagHelper.GenerateETag(this.HttpEncoder, image.Bytes);
if (EtagHelper.CompareETag(this.HttpEncoder, etag, imageEtag))
{
var imageEtag = EtagHelper.GenerateETag(HttpEncoder, image.Bytes);
if (EtagHelper.CompareETag(HttpEncoder, etag, imageEtag))
return new FileOperationResult<Image>(OperationMessages.NotModified);
}
if (!image?.Bytes?.Any() ?? false)
{
return new FileOperationResult<Image>(string.Format("ImageById Not Set [{0}]", id));
}
return new FileOperationResult<Image>(image?.Bytes?.Any() ?? false ? OperationMessages.OkMessage : OperationMessages.NoImageDataFound)
return new FileOperationResult<Image>(image?.Bytes?.Any() ?? false
? OperationMessages.OkMessage
: OperationMessages.NoImageDataFound)
{
IsSuccess = true,
Data = image.Adapt<Image>(),
ContentType = contentType,
LastModified = (image.LastUpdated ?? image.CreatedDate),
LastModified = image.LastUpdated ?? image.CreatedDate,
ETag = imageEtag
};
}
private async Task<FileOperationResult<Image>> GetImageFileOperation(string type, string regionUrn, Guid id, int? width, int? height, Func<Task<FileOperationResult<Image>>> action, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> GetImageFileOperation(string type, string regionUrn, Guid id,
int? width, int? height, Func<Task<FileOperationResult<Image>>> action, EntityTagHeaderValue etag = null)
{
try
{
var sw = Stopwatch.StartNew();
var result = (await this.CacheManager.GetAsync($"urn:{ type }_by_id_operation:{id}", action, regionUrn)).Adapt<FileOperationResult<Image>>();
if (!result.IsSuccess)
{
return new FileOperationResult<Image>(result.IsNotFoundResult, result.Messages);
}
if (result.ETag == etag)
{
return new FileOperationResult<Image>(OperationMessages.NotModified);
}
var result = (await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}", action, regionUrn))
.Adapt<FileOperationResult<Image>>();
if (!result.IsSuccess) return new FileOperationResult<Image>(result.IsNotFoundResult, result.Messages);
if (result.ETag == etag) return new FileOperationResult<Image>(OperationMessages.NotModified);
if ((width.HasValue || height.HasValue) && result?.Data?.Bytes != null)
{
result.Data.Bytes = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
result.ETag = EtagHelper.GenerateETag(HttpEncoder, result.Data.Bytes);
result.LastModified = DateTime.UtcNow;
if (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height)
{
this.Logger.LogTrace($"{ type }: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
}
if (width.Value != Configuration.ThumbnailImageSize.Width ||
height.Value != Configuration.ThumbnailImageSize.Height)
Logger.LogTrace($"{type}: Resized [{id}], Width [{width.Value}], Height [{height.Value}]");
}
sw.Stop();
return new FileOperationResult<Image>(result.Messages)
{
@ -462,8 +421,9 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"GetImageFileOperation Error, Type [{ type }], id [{id}]");
Logger.LogError(ex, $"GetImageFileOperation Error, Type [{type}], id [{id}]");
}
return new FileOperationResult<Image>("System Error");
}
@ -471,20 +431,20 @@ namespace Roadie.Api.Services
{
try
{
var image = this.DbContext.Images
.Include("Release")
.Include("Artist")
.FirstOrDefault(x => x.RoadieId == id);
var image = DbContext.Images
.Include("Release")
.Include("Artist")
.FirstOrDefault(x => x.RoadieId == id);
if (image == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("ImageById Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("ImageById Not Found [{0}]", id)));
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Image [{ id }]", ex);
Logger.LogError($"Error fetching Image [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
@ -492,27 +452,24 @@ namespace Roadie.Api.Services
{
try
{
var label = this.GetLabel(id);
var label = GetLabel(id);
if (label == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Label Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Label Not Found [{0}]", id)));
var image = new data.Image
{
Bytes = label.Thumbnail,
CreatedDate = label.CreatedDate,
LastUpdated = label.LastUpdated
};
if (label.Thumbnail == null || !label.Thumbnail.Any())
{
image = this.DefaultNotFoundImages.Label;
}
if (label.Thumbnail == null || !label.Thumbnail.Any()) image = DefaultNotFoundImages.Label;
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Label Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Label Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
@ -520,27 +477,24 @@ namespace Roadie.Api.Services
{
try
{
var playlist = this.GetPlaylist(id);
var playlist = GetPlaylist(id);
if (playlist == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Playlist Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Playlist Not Found [{0}]", id)));
var image = new data.Image
{
Bytes = playlist.Thumbnail,
CreatedDate = playlist.CreatedDate,
LastUpdated = playlist.LastUpdated
};
if (playlist.Thumbnail == null || !playlist.Thumbnail.Any())
{
image = this.DefaultNotFoundImages.Playlist;
}
if (playlist.Thumbnail == null || !playlist.Thumbnail.Any()) image = DefaultNotFoundImages.Playlist;
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Playlist Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Playlist Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
@ -548,43 +502,44 @@ namespace Roadie.Api.Services
{
try
{
var release = this.GetRelease(id);
var release = GetRelease(id);
if (release == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Release Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Release Not Found [{0}]", id)));
byte[] imageBytes = null;
string artistFolder = null;
string releaseFolder = null;
try
{
// See if cover art file exists in release folder
artistFolder = release.Artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
artistFolder = release.Artist.ArtistFileFolder(Configuration, Configuration.LibraryFolder);
if (!Directory.Exists(artistFolder))
{
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ release.Artist.ToString() }`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
}
else
{
releaseFolder = release.ReleaseFileFolder(artistFolder);
if (!Directory.Exists(releaseFolder))
{
this.Logger.LogWarning($"Release Folder [{ releaseFolder }], Not Found For Release `{ release.ToString() }`");
Logger.LogWarning($"Release Folder [{releaseFolder}], Not Found For Release `{release}`");
}
else
{
var releaseCoverFiles = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), Library.Enums.ImageType.Release);
var releaseCoverFiles =
ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder),
ImageType.Release);
if (releaseCoverFiles.Any())
{
imageBytes = File.ReadAllBytes(releaseCoverFiles.First().FullName);
}
}
}
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error Reading Release Folder [{ releaseFolder }] Artist Folder [{ artistFolder }] For Artist `{ release.Artist.Id }`");
Logger.LogError(ex,
$"Error Reading Release Folder [{releaseFolder}] Artist Folder [{artistFolder}] For Artist `{release.Artist.Id}`");
}
imageBytes = imageBytes ?? release.Thumbnail;
var image = new data.Image
{
@ -592,60 +547,60 @@ namespace Roadie.Api.Services
CreatedDate = release.CreatedDate,
LastUpdated = release.LastUpdated
};
if (release.Thumbnail == null || !release.Thumbnail.Any())
{
image = this.DefaultNotFoundImages.Release;
}
if (release.Thumbnail == null || !release.Thumbnail.Any()) image = DefaultNotFoundImages.Release;
return Task.FromResult(GenerateFileOperationResult(id, image, etag));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Release Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
private Task<FileOperationResult<Image>> ReleaseSecondaryImageAction(Guid id, int imageId, EntityTagHeaderValue etag = null)
private Task<FileOperationResult<Image>> ReleaseSecondaryImageAction(Guid id, int imageId,
EntityTagHeaderValue etag = null)
{
try
{
var release = this.GetRelease(id);
var release = GetRelease(id);
if (release == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("Release Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("Release Not Found [{0}]", id)));
byte[] imageBytes = null;
string artistFolder = null;
string releaseFolder = null;
try
{
// See if cover art file exists in release folder
artistFolder = release.Artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
artistFolder = release.Artist.ArtistFileFolder(Configuration, Configuration.LibraryFolder);
if (!Directory.Exists(artistFolder))
{
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist `{ release.Artist.ToString() }`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
}
else
{
releaseFolder = release.ReleaseFileFolder(artistFolder);
if (!Directory.Exists(releaseFolder))
{
this.Logger.LogWarning($"Release Folder [{ releaseFolder }], Not Found For Release `{ release.ToString() }`");
Logger.LogWarning($"Release Folder [{releaseFolder}], Not Found For Release `{release}`");
}
else
{
var releaseSecondaryImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), Library.Enums.ImageType.ReleaseSecondary).ToArray();
var releaseSecondaryImages = ImageHelper
.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
.ToArray();
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
{
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
}
}
}
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error Reading Release Folder [{ releaseFolder }] Artist Folder [{ artistFolder }] For Artist `{ release.Artist.Id }`");
Logger.LogError(ex,
$"Error Reading Release Folder [{releaseFolder}] Artist Folder [{artistFolder}] For Artist `{release.Artist.Id}`");
}
var image = new data.Image
{
Bytes = imageBytes,
@ -656,26 +611,25 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Release Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
private async Task<FileOperationResult<Image>> TrackImageAction(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> TrackImageAction(Guid id, int? width, int? height,
EntityTagHeaderValue etag = null)
{
try
{
var track = this.GetTrack(id);
var track = GetTrack(id);
if (track == null)
{
return new FileOperationResult<Image>(true, string.Format("Track Not Found [{0}]", id));
}
var imageBytes = track.Thumbnail;
var trackThumbnailImages = ImageHelper.FindImageTypeInDirectory(new DirectoryInfo(track.PathToTrackThumbnail(this.Configuration, this.Configuration.LibraryFolder)), Library.Enums.ImageType.Track, SearchOption.TopDirectoryOnly);
if (trackThumbnailImages.Any())
{
imageBytes = File.ReadAllBytes(trackThumbnailImages.First().FullName);
}
var trackThumbnailImages = ImageHelper.FindImageTypeInDirectory(
new DirectoryInfo(track.PathToTrackThumbnail(Configuration, Configuration.LibraryFolder)),
ImageType.Track, SearchOption.TopDirectoryOnly);
if (trackThumbnailImages.Any()) imageBytes = File.ReadAllBytes(trackThumbnailImages.First().FullName);
var image = new data.Image
{
Bytes = track.Thumbnail,
@ -683,16 +637,15 @@ namespace Roadie.Api.Services
LastUpdated = track.LastUpdated
};
if (track.Thumbnail == null || !track.Thumbnail.Any())
{
// If no track image is found then return image for release
return await this.ReleaseImage(track.ReleaseMedia.Release.RoadieId, width, height, etag);
}
return await ReleaseImage(track.ReleaseMedia.Release.RoadieId, width, height, etag);
return GenerateFileOperationResult(id, image, etag);
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching Track Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching Track Thumbnail [{id}]", ex);
}
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
@ -700,27 +653,24 @@ namespace Roadie.Api.Services
{
try
{
var user = this.GetUser(id);
var user = GetUser(id);
if (user == null)
{
return Task.FromResult(new FileOperationResult<Image>(true, string.Format("User Not Found [{0}]", id)));
}
return Task.FromResult(new FileOperationResult<Image>(true,
string.Format("User Not Found [{0}]", id)));
var image = new data.Image
{
Bytes = user.Avatar,
CreatedDate = user.CreatedDate.Value,
LastUpdated = user.LastUpdated
};
if (user.Avatar == null || !user.Avatar.Any())
{
image = this.DefaultNotFoundImages.User;
}
if (user.Avatar == null || !user.Avatar.Any()) image = DefaultNotFoundImages.User;
return Task.FromResult(GenerateFileOperationResult(id, image, etag, "image/png"));
}
catch (Exception ex)
{
this.Logger.LogError($"Error fetching User Thumbnail [{ id }]", ex);
Logger.LogError($"Error fetching User Thumbnail [{id}]", ex);
}
return Task.FromResult(new FileOperationResult<Image>(OperationMessages.ErrorOccured));
}
}

View file

@ -11,6 +11,7 @@ using Roadie.Library.Extensions;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Statistics;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
@ -26,54 +27,56 @@ namespace Roadie.Api.Services
{
public class LabelService : ServiceBase, ILabelService
{
private IBookmarkService BookmarkService { get; } = null;
private IBookmarkService BookmarkService { get; }
public LabelService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<LabelService> logger,
ICollectionService collectionService,
IPlaylistService playlistService,
IBookmarkService bookmarkService)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<LabelService> logger,
ICollectionService collectionService,
IPlaylistService playlistService,
IBookmarkService bookmarkService)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
this.BookmarkService = bookmarkService;
BookmarkService = bookmarkService;
}
public async Task<OperationResult<Label>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:label_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var result = await this.CacheManager.GetAsync<OperationResult<Label>>(cacheKey, async () =>
{
return await this.LabelByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
var cacheKey = string.Format("urn:label_by_id_operation:{0}:{1}", id,
includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey,
async () => { return await LabelByIdAction(id, includes); }, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
var userBookmarkResult =
await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
}
result.Data.UserBookmarked =
userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) !=
null;
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
var userCommentReaction =
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Label>(result.Messages)
{
Data = result?.Data,
@ -84,7 +87,8 @@ namespace Roadie.Api.Services
};
}
public Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
public Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request,
bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
@ -94,30 +98,33 @@ namespace Roadie.Api.Services
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue) ? request.FilterValue.ToAlphanumericName() : null;
var result = (from l in this.DbContext.Labels
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
l.Name != null && l.Name.Contains(request.FilterValue) ||
l.AlternateNames != null && l.AlternateNames.Contains(request.FilterValue) ||
l.AlternateNames != null && l.AlternateNames.Contains(normalizedFilterValue)
)))
select new LabelList
{
DatabaseId = l.Id,
Id = l.RoadieId,
Label = new DataToken
{
Text = l.Name,
Value = l.RoadieId.ToString()
},
SortName = l.SortName,
CreatedDate = l.CreatedDate,
LastUpdated = l.LastUpdated,
ArtistCount = l.ArtistCount,
ReleaseCount = l.ReleaseCount,
TrackCount = l.TrackCount,
Thumbnail = this.MakeLabelThumbnailImage(l.RoadieId)
});
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from l in DbContext.Labels
where request.FilterValue.Length == 0 || request.FilterValue.Length > 0 && (
l.Name != null && l.Name.Contains(request.FilterValue) ||
l.AlternateNames != null && l.AlternateNames.Contains(request.FilterValue) ||
l.AlternateNames != null && l.AlternateNames.Contains(normalizedFilterValue)
)
select new LabelList
{
DatabaseId = l.Id,
Id = l.RoadieId,
Label = new DataToken
{
Text = l.Name,
Value = l.RoadieId.ToString()
},
SortName = l.SortName,
CreatedDate = l.CreatedDate,
LastUpdated = l.LastUpdated,
ArtistCount = l.ArtistCount,
ReleaseCount = l.ReleaseCount,
TrackCount = l.TrackCount,
Thumbnail = MakeLabelThumbnailImage(l.RoadieId)
};
LabelList[] rows = null;
var rowCount = result.Count();
if (doRandomize ?? false)
@ -125,17 +132,20 @@ namespace Roadie.Api.Services
var randomLimit = roadieUser?.RandomReleaseLimit ?? 100;
request.Limit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
var sql = "SELECT l.Id FROM `label` l ORDER BY RAND() LIMIT {0}";
rows = (from rdn in this.DbContext.Labels.FromSql(sql, randomLimit)
rows = (from rdn in DbContext.Labels.FromSql(sql, randomLimit)
join rs in result on rdn.Id equals rs.DatabaseId
select rs)
.Take(request.LimitValue)
.ToArray();
.Take(request.LimitValue)
.ToArray();
}
else
{
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } }) : request.OrderValue(null);
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } })
: request.OrderValue();
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<LabelList>
{
@ -149,7 +159,7 @@ namespace Roadie.Api.Services
public async Task<OperationResult<Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl)
{
return await this.SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public async Task<OperationResult<bool>> UpdateLabel(User user, Label model)
@ -157,11 +167,8 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = this.DbContext.Labels.FirstOrDefault(x => x.RoadieId == model.Id);
if (label == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
}
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == model.Id);
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
try
{
var now = DateTime.UtcNow;
@ -185,19 +192,22 @@ namespace Roadie.Api.Services
label.Thumbnail = ImageHelper.ConvertToJpegFormat(labelImage);
// Resize to store in database as thumbnail
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height);
}
label.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(label.CacheRegion);
this.Logger.LogInformation($"UpdateLabel `{ label }` By User `{ user }`");
label.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"UpdateLabel `{label}` By User `{user}`");
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
@ -217,7 +227,8 @@ namespace Roadie.Api.Services
file.CopyTo(ms);
bytes = ms.ToArray();
}
return await this.SaveImageBytes(user, id, bytes);
return await SaveImageBytes(user, id, bytes);
}
private Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null)
@ -225,38 +236,37 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
sw.Start();
var label = this.GetLabel(id);
var label = GetLabel(id);
if (label == null)
{
return Task.FromResult(new OperationResult<Label>(true, string.Format("Label Not Found [{0}]", id)));
}
var result = label.Adapt<Label>();
result.AlternateNames = label.AlternateNames;
result.Tags = label.Tags;
result.URLs = label.URLs;
result.Thumbnail = this.MakeLabelThumbnailImage(label.RoadieId);
result.MediumThumbnail = base.MakeThumbnailImage(id, "label", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
result.Thumbnail = MakeLabelThumbnailImage(label.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(id, "label", Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height);
if (includes != null && includes.Any())
{
if (includes.Contains("stats"))
{
var labelTracks = (from l in this.DbContext.Labels
join rl in this.DbContext.ReleaseLabels on l.Id equals rl.LabelId into rld
from rl in rld.DefaultIfEmpty()
join r in this.DbContext.Releases on rl.ReleaseId equals r.Id
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where (l.Id == label.Id)
select new
{
t.Duration,
t.FileSize
});
var labelTracks = from l in DbContext.Labels
join rl in DbContext.ReleaseLabels on l.Id equals rl.LabelId into rld
from rl in rld.DefaultIfEmpty()
join r in DbContext.Releases on rl.ReleaseId equals r.Id
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where l.Id == label.Id
select new
{
t.Duration,
t.FileSize
};
result.Duration = labelTracks.Sum(x => x.Duration);
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
result.Statistics = new ReleaseGroupingStatistics
{
TrackCount = label.TrackCount,
ArtistCount = label.ArtistCount,
@ -265,25 +275,31 @@ namespace Roadie.Api.Services
FileSize = labelTracks.Sum(x => (long?)x.FileSize).ToFileSize()
};
}
if (includes.Contains("comments"))
{
var labelComments = this.DbContext.Comments.Include(x => x.User).Where(x => x.LabelId == label.Id).OrderByDescending(x => x.CreatedDate).ToArray();
var labelComments = DbContext.Comments.Include(x => x.User).Where(x => x.LabelId == label.Id)
.OrderByDescending(x => x.CreatedDate).ToArray();
if (labelComments.Any())
{
var comments = new List<Comment>();
var commentIds = labelComments.Select(x => x.Id).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
select cr).ToArray();
foreach (var labelComment in labelComments)
{
var comment = labelComment.Adapt<Comment>();
comment.DatabaseId = labelComment.Id;
comment.User = UserList.FromDataUser(labelComment.User, this.MakeUserThumbnailImage(labelComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Like);
comment.User = UserList.FromDataUser(labelComment.User,
MakeUserThumbnailImage(labelComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x =>
x.CommentId == labelComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment);
}
result.Comments = comments;
}
}
@ -298,16 +314,13 @@ namespace Roadie.Api.Services
});
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
private async Task<OperationResult<Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = this.DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
if (label == null)
{
return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
}
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
if (label == null) return new OperationResult<Image>(true, string.Format("Label Not Found [{0}]", id));
try
{
var now = DateTime.UtcNow;
@ -318,24 +331,28 @@ namespace Roadie.Api.Services
label.Thumbnail = ImageHelper.ConvertToJpegFormat(label.Thumbnail);
// Resize to store in database as thumbnail
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
label.Thumbnail = ImageHelper.ResizeImage(label.Thumbnail, Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height);
}
label.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(label.CacheRegion);
this.Logger.LogInformation($"UploadLabelImage `{ label }` By User `{ user }`");
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"UploadLabelImage `{label}` By User `{user}`");
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<Library.Models.Image>
return new OperationResult<Image>
{
IsSuccess = !errors.Any(),
Data = base.MakeThumbnailImage(id, "label", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height, true),
Data = MakeThumbnailImage(id, "label", Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};

View file

@ -3,6 +3,7 @@ using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Models;
using Roadie.Library.Utility;
using System;
@ -15,16 +16,16 @@ using data = Roadie.Library.Data;
namespace Roadie.Api.Services
{
/// <summary>
/// Returns lookups (or dictionaries) of various allowable values for a given Type
/// Returns lookups (or dictionaries) of various allowable values for a given Type
/// </summary>
public class LookupService : ServiceBase, ILookupService
{
public LookupService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlaylistService> logger)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlaylistService> logger)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
}
@ -34,7 +35,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.ArtistType)),
Data = EnumToDataTokens(typeof(ArtistType)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -45,7 +46,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.BandStatus)),
Data = EnumToDataTokens(typeof(BandStatus)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -56,7 +57,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.BookmarkType)),
Data = EnumToDataTokens(typeof(BookmarkType)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -67,7 +68,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.CollectionType)),
Data = EnumToDataTokens(typeof(CollectionType)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -78,7 +79,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.LibraryStatus)),
Data = EnumToDataTokens(typeof(LibraryStatus)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -89,7 +90,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.QueMessageType)),
Data = EnumToDataTokens(typeof(QueMessageType)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -100,7 +101,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.ReleaseType)),
Data = EnumToDataTokens(typeof(ReleaseType)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -111,7 +112,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.RequestStatus)),
Data = EnumToDataTokens(typeof(RequestStatus)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -122,7 +123,7 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
{
Data = this.EnumToDataTokens(typeof(Roadie.Library.Enums.Statuses)),
Data = EnumToDataTokens(typeof(Statuses)),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -132,13 +133,11 @@ namespace Roadie.Api.Services
{
var result = new List<DataToken>();
foreach (var ls in Enum.GetValues(ee))
{
result.Add(new DataToken
{
Text = ls.ToString(),
Value = ((short)ls).ToString()
});
}
return result.OrderBy(x => x.Text);
}
}

View file

@ -23,89 +23,99 @@ namespace Roadie.Api.Services
{
public class PlayActivityService : ServiceBase, IPlayActivityService
{
protected IScrobbleHandler ScrobblerHandler { get; }
protected IHubContext<PlayActivityHub> PlayActivityHub { get; }
protected IScrobbleHandler ScrobblerHandler { get; }
public PlayActivityService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlayActivityService> logger,
IScrobbleHandler scrobbleHandler,
IHubContext<PlayActivityHub> playActivityHub)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlayActivityService> logger,
IScrobbleHandler scrobbleHandler,
IHubContext<PlayActivityHub> playActivityHub)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
this.PlayActivityHub = playActivityHub;
this.ScrobblerHandler = scrobbleHandler;
PlayActivityHub = playActivityHub;
ScrobblerHandler = scrobbleHandler;
}
public Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null)
public Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request,
User roadieUser = null, DateTime? newerThan = null)
{
try
{
var sw = new Stopwatch();
sw.Start();
var result = (from t in this.DbContext.Tracks
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
join trackArtist in this.DbContext.Artists on t.ArtistId equals trackArtist.Id into tas
from trackArtist in tas.DefaultIfEmpty()
join usertrack in this.DbContext.UserTracks on t.Id equals usertrack.TrackId
join u in this.DbContext.Users on usertrack.UserId equals u.Id
join releaseArtist in this.DbContext.Artists on r.ArtistId equals releaseArtist.Id
where (newerThan == null || usertrack.LastPlayed >= newerThan)
where ((roadieUser == null && !(u.IsPrivate ?? false)) || (roadieUser != null && (usertrack != null && usertrack.User.Id == roadieUser.Id)))
where (!request.FilterRatedOnly || (roadieUser == null && t.Rating > 0 || roadieUser != null && usertrack.Rating >0))
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
t.Title != null && t.Title.ToLower().Contains(request.Filter.ToLower()) ||
t.AlternateNames != null && t.AlternateNames.ToLower().Contains(request.Filter.ToLower())
)))
select new PlayActivityList
{
Release = new DataToken
{
Text = r.Title,
Value = r.RoadieId.ToString()
},
Track = TrackList.FromDataTrack(null,
t,
rm.MediaNumber,
r,
releaseArtist,
trackArtist,
this.HttpContext.BaseUrl,
this.MakeTrackThumbnailImage(t.RoadieId),
this.MakeReleaseThumbnailImage(r.RoadieId),
this.MakeArtistThumbnailImage(releaseArtist.RoadieId),
this.MakeArtistThumbnailImage(trackArtist == null ? null : (Guid?)trackArtist.RoadieId)),
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
Artist = new DataToken
{
Text = releaseArtist.Name,
Value = releaseArtist.RoadieId.ToString()
},
TrackArtist = trackArtist == null ? null : new DataToken
{
Text = trackArtist.Name,
Value = trackArtist.RoadieId.ToString()
},
PlayedDateDateTime = usertrack.LastPlayed,
ReleasePlayUrl = $"{ this.HttpContext.BaseUrl }/play/release/{ r.RoadieId}",
Rating = t.Rating,
UserRating = usertrack.Rating,
TrackPlayUrl = $"{ this.HttpContext.BaseUrl }/play/track/{ t.RoadieId}.mp3",
ArtistThumbnail = this.MakeArtistThumbnailImage(trackArtist != null ? trackArtist.RoadieId : releaseArtist.RoadieId),
ReleaseThumbnail = this.MakeReleaseThumbnailImage(r.RoadieId),
UserThumbnail = this.MakeUserThumbnailImage(u.RoadieId)
});
var result = from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join trackArtist in DbContext.Artists on t.ArtistId equals trackArtist.Id into tas
from trackArtist in tas.DefaultIfEmpty()
join usertrack in DbContext.UserTracks on t.Id equals usertrack.TrackId
join u in DbContext.Users on usertrack.UserId equals u.Id
join releaseArtist in DbContext.Artists on r.ArtistId equals releaseArtist.Id
where newerThan == null || usertrack.LastPlayed >= newerThan
where roadieUser == null && !(u.IsPrivate ?? false) || roadieUser != null && usertrack != null &&
usertrack.User.Id == roadieUser.Id
where !request.FilterRatedOnly || roadieUser == null && t.Rating > 0 ||
roadieUser != null && usertrack.Rating > 0
where request.FilterValue.Length == 0 || request.FilterValue.Length > 0 && (
t.Title != null && t.Title.ToLower().Contains(request.Filter.ToLower()) ||
t.AlternateNames != null && t.AlternateNames.ToLower().Contains(request.Filter.ToLower())
)
select new PlayActivityList
{
Release = new DataToken
{
Text = r.Title,
Value = r.RoadieId.ToString()
},
Track = TrackList.FromDataTrack(null,
t,
rm.MediaNumber,
r,
releaseArtist,
trackArtist,
HttpContext.BaseUrl,
MakeTrackThumbnailImage(t.RoadieId),
MakeReleaseThumbnailImage(r.RoadieId),
MakeArtistThumbnailImage(releaseArtist.RoadieId),
MakeArtistThumbnailImage(trackArtist == null ? null : (Guid?)trackArtist.RoadieId)),
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
Artist = new DataToken
{
Text = releaseArtist.Name,
Value = releaseArtist.RoadieId.ToString()
},
TrackArtist = trackArtist == null
? null
: new DataToken
{
Text = trackArtist.Name,
Value = trackArtist.RoadieId.ToString()
},
PlayedDateDateTime = usertrack.LastPlayed,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}",
Rating = t.Rating,
UserRating = usertrack.Rating,
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{t.RoadieId}.mp3",
ArtistThumbnail =
MakeArtistThumbnailImage(
trackArtist != null ? trackArtist.RoadieId : releaseArtist.RoadieId),
ReleaseThumbnail = MakeReleaseThumbnailImage(r.RoadieId),
UserThumbnail = MakeUserThumbnailImage(u.RoadieId)
};
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } }) : request.OrderValue(null);
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
sw.Stop();
@ -120,48 +130,44 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
}
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>());
}
public async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble)
{
var scrobbleResult = await this.ScrobblerHandler.NowPlaying(roadieUser, scrobble);
if (!scrobbleResult.IsSuccess)
{
return scrobbleResult;
}
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble);
if (!scrobbleResult.IsSuccess) return scrobbleResult;
await PublishPlayActivity(roadieUser, scrobble, true);
return scrobbleResult;
}
public async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble)
{
var scrobbleResult = await this.ScrobblerHandler.Scrobble(roadieUser, scrobble);
if(!scrobbleResult.IsSuccess)
{
return scrobbleResult;
}
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble);
if (!scrobbleResult.IsSuccess) return scrobbleResult;
await PublishPlayActivity(roadieUser, scrobble, false);
return scrobbleResult;
}
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
{
// Only broadcast if the user is not public and played duration is more than half of duration
if (!roadieUser.IsPrivate &&
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > (scrobble.TrackDuration.TotalSeconds / 2))
{
// Only broadcast if the user is not public and played duration is more than half of duration
if (!roadieUser.IsPrivate &&
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > scrobble.TrackDuration.TotalSeconds / 2)
{
var sw = Stopwatch.StartNew();
var track = this.DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
var userTrack = this.DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
var userTrack =
DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
var pl = new PlayActivityList
{
Artist = new DataToken
@ -169,49 +175,55 @@ namespace Roadie.Api.Services
Text = track.ReleaseMedia.Release.Artist.Name,
Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString()
},
TrackArtist = track.TrackArtist == null ? null : new DataToken
{
Text = track.TrackArtist.Name,
Value = track.TrackArtist.RoadieId.ToString()
},
TrackArtist = track.TrackArtist == null
? null
: new DataToken
{
Text = track.TrackArtist.Name,
Value = track.TrackArtist.RoadieId.ToString()
},
Release = new DataToken
{
Text = track.ReleaseMedia.Release.Title,
Value = track.ReleaseMedia.Release.RoadieId.ToString()
},
Track = TrackList.FromDataTrack(null,
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
this.HttpContext.BaseUrl,
this.MakeTrackThumbnailImage(track.RoadieId),
this.MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
this.MakeArtistThumbnailImage(track.ReleaseMedia.Release.Artist.RoadieId),
this.MakeArtistThumbnailImage(track.TrackArtist == null ? null : (Guid?)track.TrackArtist.RoadieId)),
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
HttpContext.BaseUrl,
MakeTrackThumbnailImage(track.RoadieId),
MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(track.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(track.TrackArtist == null
? null
: (Guid?)track.TrackArtist.RoadieId)),
User = new DataToken
{
Text = roadieUser.UserName,
Value = roadieUser.UserId.ToString()
},
ArtistThumbnail = this.MakeArtistThumbnailImage(track.TrackArtist != null ? track.TrackArtist.RoadieId : track.ReleaseMedia.Release.Artist.RoadieId),
ArtistThumbnail = MakeArtistThumbnailImage(track.TrackArtist != null
? track.TrackArtist.RoadieId
: track.ReleaseMedia.Release.Artist.RoadieId),
PlayedDateDateTime = scrobble.TimePlayed,
IsNowPlaying = isNowPlaying,
Rating = track.Rating,
ReleasePlayUrl = $"{ this.HttpContext.BaseUrl }/play/release/{ track.ReleaseMedia.Release.RoadieId}",
ReleaseThumbnail = this.MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
TrackPlayUrl = $"{ this.HttpContext.BaseUrl }/play/track/{ track.RoadieId}.mp3",
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}",
ReleaseThumbnail = MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3",
UserRating = userTrack?.Rating,
UserThumbnail = this.MakeUserThumbnailImage(roadieUser.UserId)
UserThumbnail = MakeUserThumbnailImage(roadieUser.UserId)
};
try
{
await this.PlayActivityHub.Clients.All.SendAsync("SendActivity", pl);
await PlayActivityHub.Clients.All.SendAsync("SendActivity", pl);
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
}
}
}

View file

@ -11,6 +11,7 @@ using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists;
using Roadie.Library.Models.Statistics;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
@ -25,18 +26,18 @@ namespace Roadie.Api.Services
{
public class PlaylistService : ServiceBase, IPlaylistService
{
private IBookmarkService BookmarkService { get; } = null;
private IBookmarkService BookmarkService { get; }
public PlaylistService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlaylistService> logger,
IBookmarkService bookmarkService)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<PlaylistService> logger,
IBookmarkService bookmarkService)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
this.BookmarkService = bookmarkService;
BookmarkService = bookmarkService;
}
public async Task<OperationResult<PlaylistList>> AddNewPlaylist(User user, Playlist model)
@ -48,14 +49,15 @@ namespace Roadie.Api.Services
Name = model.Name,
UserId = user.Id
};
this.DbContext.Playlists.Add(playlist);
await this.DbContext.SaveChangesAsync();
var r = await this.AddTracksToPlaylist(playlist, model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id));
DbContext.Playlists.Add(playlist);
await DbContext.SaveChangesAsync();
var r = await AddTracksToPlaylist(playlist,
model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id));
var request = new PagedRequest
{
FilterToPlaylistId = playlist.RoadieId
};
var result = await this.List(request, user);
var result = await List(request, user);
return new OperationResult<PlaylistList>
{
Data = result.Rows.First(),
@ -71,30 +73,28 @@ namespace Roadie.Api.Services
var result = false;
var now = DateTime.UtcNow;
var existingTracksForPlaylist = (from plt in this.DbContext.PlaylistTracks
join t in this.DbContext.Tracks on plt.TrackId equals t.Id
where plt.PlayListId == playlist.Id
select t);
var newTracksForPlaylist = (from t in this.DbContext.Tracks
var existingTracksForPlaylist = from plt in DbContext.PlaylistTracks
join t in DbContext.Tracks on plt.TrackId equals t.Id
where plt.PlayListId == playlist.Id
select t;
var newTracksForPlaylist = (from t in DbContext.Tracks
where (from x in trackIds select x).Contains(t.RoadieId)
where !(from x in existingTracksForPlaylist select x.RoadieId).Contains(t.RoadieId)
select t).ToArray();
foreach (var newTrackForPlaylist in newTracksForPlaylist)
{
this.DbContext.PlaylistTracks.Add(new data.PlaylistTrack
DbContext.PlaylistTracks.Add(new data.PlaylistTrack
{
TrackId = newTrackForPlaylist.Id,
PlayListId = playlist.Id
});
}
playlist.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync();
result = true;
var r = await this.ReorderPlaylist(playlist);
var r = await ReorderPlaylist(playlist);
result = result && r.IsSuccess;
await base.UpdatePlaylistCounts(playlist.Id, now);
await UpdatePlaylistCounts(playlist.Id, now);
sw.Stop();
@ -110,46 +110,45 @@ namespace Roadie.Api.Services
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var result = await this.CacheManager.GetAsync<OperationResult<Playlist>>(cacheKey, async () =>
{
return await this.PlaylistByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id,
includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey,
async () => { return await PlaylistByIdAction(id, includes); }, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
if (result?.Data?.Tracks != null)
{
var user = this.GetUser(roadieUser.UserId);
var user = GetUser(roadieUser.UserId);
foreach (var track in result.Data.Tracks)
{
track.Track.TrackPlayUrl = this.MakeTrackPlayUrl(user, track.Track.DatabaseId, track.Track.Id);
}
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, track.Track.DatabaseId, track.Track.Id);
}
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
var userBookmarkResult =
await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
}
result.Data.UserBookmarked =
userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) !=
null;
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
var userCommentReaction =
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Playlist>(result.Messages)
{
Data = result?.Data,
@ -164,23 +163,21 @@ namespace Roadie.Api.Services
{
var sw = new Stopwatch();
sw.Start();
var playlist = this.DbContext.Playlists.FirstOrDefault(x => x.RoadieId == id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", id));
}
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == id);
if (playlist == null) return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", id));
if (!user.IsAdmin && user.Id != playlist.UserId)
{
this.Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
this.DbContext.Playlists.Remove(playlist);
await this.DbContext.SaveChangesAsync();
this.Logger.LogInformation("User `{0}` deleted Playlist `{1}]`", user, playlist);
this.CacheManager.ClearRegion(playlist.CacheRegion);
DbContext.Playlists.Remove(playlist);
await DbContext.SaveChangesAsync();
Logger.LogInformation("User `{0}` deleted Playlist `{1}]`", user, playlist);
CacheManager.ClearRegion(playlist.CacheRegion);
sw.Stop();
return new OperationResult<bool>
{
@ -190,46 +187,48 @@ namespace Roadie.Api.Services
};
}
public Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null)
public Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request,
User roadieUser = null)
{
var sw = new Stopwatch();
sw.Start();
int[] playlistWithArtistTrackIds = new int[0];
var playlistWithArtistTrackIds = new int[0];
if (request.FilterToArtistId.HasValue)
{
playlistWithArtistTrackIds = (from pl in this.DbContext.Playlists
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
join a in this.DbContext.Artists on r.ArtistId equals a.Id
playlistWithArtistTrackIds = (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where a.RoadieId == request.FilterToArtistId
select pl.Id
).ToArray();
}
int[] playlistReleaseTrackIds = new int[0];
).ToArray();
var playlistReleaseTrackIds = new int[0];
if (request.FilterToReleaseId.HasValue)
{
playlistReleaseTrackIds = (from pl in this.DbContext.Playlists
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
playlistReleaseTrackIds = (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
where r.RoadieId == request.FilterToReleaseId
select pl.Id
).ToArray();
}
).ToArray();
var result = (from pl in this.DbContext.Playlists
join u in this.DbContext.Users on pl.UserId equals u.Id
where (request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId)
where (request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id))
where (request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id))
where ((roadieUser == null && pl.IsPublic) || (roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic))
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (pl.Name != null && pl.Name.Contains(request.FilterValue))))
select PlaylistList.FromDataPlaylist(pl, u, this.MakePlaylistThumbnailImage(pl.RoadieId), this.MakeUserThumbnailImage(u.RoadieId)));
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } }) : request.OrderValue(null);
var result = from pl in DbContext.Playlists
join u in DbContext.Users on pl.UserId equals u.Id
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId ||
pl.IsPublic
where request.FilterValue.Length == 0 || request.FilterValue.Length > 0 && pl.Name != null &&
pl.Name.Contains(request.FilterValue)
select PlaylistList.FromDataPlaylist(pl, u, MakePlaylistThumbnailImage(pl.RoadieId),
MakeUserThumbnailImage(u.RoadieId));
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
sw.Stop();
@ -254,13 +253,15 @@ namespace Roadie.Api.Services
if (playlist != null)
{
var looper = 0;
foreach (var playlistTrack in this.DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id).OrderBy(x => x.CreatedDate))
foreach (var playlistTrack in DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id)
.OrderBy(x => x.CreatedDate))
{
looper++;
playlistTrack.ListNumber = looper;
playlistTrack.LastUpdated = now;
}
await this.DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync();
result = true;
}
@ -276,11 +277,9 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = this.DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
}
try
{
var now = DateTime.UtcNow;
@ -300,19 +299,22 @@ namespace Roadie.Api.Services
playlist.Thumbnail = ImageHelper.ConvertToJpegFormat(playlistImage);
// Resize to store in database as thumbnail
playlist.Thumbnail = ImageHelper.ResizeImage(playlist.Thumbnail, this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
playlist.Thumbnail = ImageHelper.ResizeImage(playlist.Thumbnail,
Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
}
playlist.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(playlist.CacheRegion);
this.Logger.LogInformation($"UpdatePlaylist `{ playlist }` By User `{ user }`");
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(playlist.CacheRegion);
Logger.LogInformation($"UpdatePlaylist `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
@ -329,18 +331,16 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = this.DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
var playlist = DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", request.Id));
}
try
{
var now = DateTime.UtcNow;
playlist.Tracks.Clear();
var tracks = (from t in this.DbContext.Tracks
var tracks = (from t in DbContext.Tracks
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
select t).ToArray();
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
@ -354,18 +354,20 @@ namespace Roadie.Api.Services
TrackId = track.Id
});
}
playlist.LastUpdated = now;
await this.DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync();
// await base.UpdatePlaylistCounts(playlist.Id, now);
this.Logger.LogInformation($"UpdatePlaylistTracks `{ playlist }` By User `{ user }`");
Logger.LogInformation($"UpdatePlaylistTracks `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
@ -382,82 +384,84 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
sw.Start();
var playlist = this.GetPlaylist(id);
var playlist = GetPlaylist(id);
if (playlist == null)
{
return Task.FromResult(new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id)));
}
return Task.FromResult(new OperationResult<Playlist>(true,
string.Format("Playlist Not Found [{0}]", id)));
var result = playlist.Adapt<Playlist>();
result.AlternateNames = playlist.AlternateNames;
result.Tags = playlist.Tags;
result.URLs = playlist.URLs;
var maintainer = this.DbContext.Users.Include(x => x.UserRoles).Include("UserRoles.Role").FirstOrDefault(x => x.Id == playlist.UserId);
result.Maintainer = UserList.FromDataUser(maintainer, this.MakeUserThumbnailImage(maintainer.RoadieId));
result.Thumbnail = this.MakePlaylistThumbnailImage(playlist.RoadieId);
result.MediumThumbnail = base.MakeThumbnailImage(id, "playlist", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
var maintainer = DbContext.Users.Include(x => x.UserRoles).Include("UserRoles.Role")
.FirstOrDefault(x => x.Id == playlist.UserId);
result.Maintainer = UserList.FromDataUser(maintainer, MakeUserThumbnailImage(maintainer.RoadieId));
result.Thumbnail = MakePlaylistThumbnailImage(playlist.RoadieId);
result.MediumThumbnail = MakeThumbnailImage(id, "playlist", Configuration.MediumImageSize.Width,
Configuration.MediumImageSize.Height);
if (includes != null && includes.Any())
{
var playlistTracks = (from pl in this.DbContext.Playlists
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
var playlistTracks = (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
where pl.Id == playlist.Id
select new { t, pltr }).ToArray();
if (includes.Contains("stats"))
{
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
result.Statistics = new ReleaseGroupingStatistics
{
ReleaseCount = result.ReleaseCount,
TrackCount = result.TrackCount,
TrackSize = result.DurationTime,
FileSize = playlistTracks.Sum(x => (long?)x.t.FileSize).ToFileSize()
};
}
if (includes.Contains("tracks"))
{
result.Tracks = (from plt in playlistTracks
join rm in this.DbContext.ReleaseMedias on plt.t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
join releaseArtist in this.DbContext.Artists on r.ArtistId equals releaseArtist.Id
join trackArtist in this.DbContext.Artists on plt.t.ArtistId equals trackArtist.Id into tas
join rm in DbContext.ReleaseMedias on plt.t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join releaseArtist in DbContext.Artists on r.ArtistId equals releaseArtist.Id
join trackArtist in DbContext.Artists on plt.t.ArtistId equals trackArtist.Id into tas
from trackArtist in tas.DefaultIfEmpty()
select new PlaylistTrack
{
ListNumber = plt.pltr.ListNumber,
Track = TrackList.FromDataTrack(null,
plt.t,
rm.MediaNumber,
r,
releaseArtist,
trackArtist,
this.HttpContext.BaseUrl,
this.MakeTrackThumbnailImage(plt.t.RoadieId),
this.MakeReleaseThumbnailImage(r.RoadieId),
this.MakeArtistThumbnailImage(releaseArtist.RoadieId),
this.MakeArtistThumbnailImage(trackArtist == null ? null : (Guid?)trackArtist.RoadieId))
plt.t,
rm.MediaNumber,
r,
releaseArtist,
trackArtist,
HttpContext.BaseUrl,
MakeTrackThumbnailImage(plt.t.RoadieId),
MakeReleaseThumbnailImage(r.RoadieId),
MakeArtistThumbnailImage(releaseArtist.RoadieId),
MakeArtistThumbnailImage(trackArtist == null ? null : (Guid?)trackArtist.RoadieId))
}).ToArray();
}
if (includes.Contains("comments"))
{
var playlistComments = this.DbContext.Comments.Include(x => x.User).Where(x => x.PlaylistId == playlist.Id).OrderByDescending(x => x.CreatedDate).ToArray();
var playlistComments = DbContext.Comments.Include(x => x.User)
.Where(x => x.PlaylistId == playlist.Id).OrderByDescending(x => x.CreatedDate).ToArray();
if (playlistComments.Any())
{
var comments = new List<Comment>();
var commentIds = playlistComments.Select(x => x.Id).ToArray();
var userCommentReactions = (from cr in this.DbContext.CommentReactions
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
select cr).ToArray();
foreach (var playlistComment in playlistComments)
{
var comment = playlistComment.Adapt<Comment>();
comment.DatabaseId = playlistComment.Id;
comment.User = UserList.FromDataUser(playlistComment.User, this.MakeUserThumbnailImage(playlistComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x => x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Like);
comment.User = UserList.FromDataUser(playlistComment.User,
MakeUserThumbnailImage(playlistComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x =>
x.CommentId == playlistComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment);
}
result.Comments = comments;
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@
<PackageReference Include="Hashids.net" Version="1.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.2.5" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.5.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.17" />
</ItemGroup>

File diff suppressed because it is too large Load diff

View file

@ -18,11 +18,11 @@ namespace Roadie.Api.Services
public class StatisticsService : ServiceBase, IStatisticsService
{
public StatisticsService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<StatisticsService> logger)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<StatisticsService> logger)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
}
@ -34,7 +34,7 @@ namespace Roadie.Api.Services
sw.Start();
try
{
using (var conn = new MySqlConnection(this.Configuration.ConnectionString))
using (var conn = new MySqlConnection(Configuration.ConnectionString))
{
conn.Open();
var sql = @"SELECT rm.releaseMediaCount AS releaseMediaCount, COUNT(r.roadieId) AS releaseCount,
@ -75,9 +75,7 @@ namespace Roadie.Api.Services
using (var rdr = await cmd.ExecuteReaderAsync())
{
if (rdr.HasRows)
{
while (rdr.Read())
{
result = new LibraryStats
{
UserCount = SafeParser.ToNumber<int?>(rdr["UserCount"]),
@ -92,13 +90,11 @@ namespace Roadie.Api.Services
TotalTrackDuration = SafeParser.ToNumber<long?>(rdr["TotalTrackDuration"]),
TotalTrackSize = SafeParser.ToNumber<long?>(rdr["TotalTrackSize"])
};
}
}
}
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
}
finally
{
@ -106,17 +102,16 @@ namespace Roadie.Api.Services
}
}
}
var lastScan = this.DbContext.ScanHistories.OrderByDescending(x => x.CreatedDate).FirstOrDefault();
if (lastScan != null)
{
result.LastScan = lastScan.CreatedDate;
}
var lastScan = DbContext.ScanHistories.OrderByDescending(x => x.CreatedDate).FirstOrDefault();
if (lastScan != null) result.LastScan = lastScan.CreatedDate;
sw.Stop();
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
}
return new OperationResult<LibraryStats>
{
IsSuccess = result != null,
@ -132,7 +127,7 @@ namespace Roadie.Api.Services
var result = new List<DateAndCount>();
using (var conn = new MySqlConnection(this.Configuration.ConnectionString))
using (var conn = new MySqlConnection(Configuration.ConnectionString))
{
conn.Open();
var sql = @"SELECT DATE_FORMAT(createdDate, '%Y-%m-%d') as date, count(1) as count
@ -146,21 +141,17 @@ namespace Roadie.Api.Services
using (var rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
while (rdr.Read())
{
result.Add(new DateAndCount
{
Date = SafeParser.ToString(rdr["date"]),
Count = SafeParser.ToNumber<int?>(rdr["count"])
});
}
}
}
}
catch (Exception ex)
{
this.Logger.LogError(ex);
Logger.LogError(ex);
}
finally
{

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,12 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Roadie.Library.Identity;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Api.Services
@ -15,7 +17,7 @@ namespace Roadie.Api.Services
public TokenService(IConfiguration configuration)
{
this._configuration = configuration;
_configuration = configuration;
}
public async Task<string> GenerateToken(ApplicationUser user, UserManager<ApplicationUser> userManager)
@ -27,7 +29,7 @@ namespace Roadie.Api.Services
var tokenHandler = new JwtSecurityTokenHandler();
var claims = new Claim[]
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
new Claim("roadie_id", user.RoadieId.ToString()),
@ -38,17 +40,19 @@ namespace Roadie.Api.Services
}.Union(userRoles);
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 securityKey =
new SymmetricSecurityKey(
Encoding.Default.GetBytes(_configuration.GetValue<string>("Tokens:PrivateKey")));
var signingCredentials = new SigningCredentials(securityKey, 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")
);
expires: utcNow.AddSeconds(_configuration.GetValue<int>("Tokens:Lifetime")),
audience: _configuration.GetValue<string>("Tokens:Audience"),
issuer: _configuration.GetValue<string>("Tokens:Issuer")
);
return new JwtSecurityTokenHandler().WriteToken(jwt);
}

File diff suppressed because it is too large Load diff

View file

@ -7,11 +7,12 @@ using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.MetaData.LastFm;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Statistics;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
@ -33,17 +34,18 @@ namespace Roadie.Api.Services
private UserManager<ApplicationUser> UserManager { get; }
public UserService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<ArtistService> logger,
UserManager<ApplicationUser> userManager
)
IHttpEncoder httpEncoder,
IHttpContext httpContext,
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<ArtistService> logger,
UserManager<ApplicationUser> userManager
)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
this.UserManager = userManager;
this.LastFmHelper = new LastFmHelper(this.Configuration, this.CacheManager, this.Logger, context, httpEncoder); ;
UserManager = userManager;
LastFmHelper = new LastFmHelper(Configuration, CacheManager, Logger, context, httpEncoder);
;
}
public async Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes)
@ -54,21 +56,18 @@ namespace Roadie.Api.Services
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:user_by_id_operation:{0}", id);
var result = await this.CacheManager.GetAsync<OperationResult<User>>(cacheKey, async () =>
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
tsw.Restart();
var rr = await this.UserByIdAction(id, includes);
var rr = await UserByIdAction(id, includes);
tsw.Stop();
timings.Add("UserByIdAction", tsw.ElapsedMilliseconds);
return rr;
}, ApplicationUser.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null)
{
result.Data.Avatar = this.MakeUserThumbnailImage(id);
}
if (result?.Data != null) result.Data.Avatar = MakeUserThumbnailImage(id);
timings.Add("operation", sw.ElapsedMilliseconds);
this.Logger.LogDebug("ById Timings: id [{0}]", id);
Logger.LogDebug("ById Timings: id [{0}]", id);
return new OperationResult<User>(result.Messages)
{
Data = result?.Data,
@ -84,43 +83,48 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var result = (from u in this.DbContext.Users
let lastActivity = (from ut in this.DbContext.UserTracks
where ut.UserId == u.Id
select ut.LastPlayed).Max()
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (u.UserName.Contains(request.FilterValue))))
select new UserList
{
DatabaseId = u.Id,
Id = u.RoadieId,
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
IsEditor = u.UserRoles.Any(x => x.Role.Name == "Editor"),
IsPrivate = u.IsPrivate,
Thumbnail = this.MakeUserThumbnailImage(u.RoadieId),
CreatedDate = u.CreatedDate,
LastUpdated = u.LastUpdated,
RegisteredDate = u.RegisteredOn,
LastLoginDate = u.LastLogin,
LastApiAccessDate = u.LastApiAccess,
LastActivity = lastActivity
});
var result = from u in DbContext.Users
let lastActivity = (from ut in DbContext.UserTracks
where ut.UserId == u.Id
select ut.LastPlayed).Max()
where request.FilterValue.Length == 0 ||
request.FilterValue.Length > 0 && u.UserName.Contains(request.FilterValue)
select new UserList
{
DatabaseId = u.Id,
Id = u.RoadieId,
User = new models.DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
IsEditor = u.UserRoles.Any(x => x.Role.Name == "Editor"),
IsPrivate = u.IsPrivate,
Thumbnail = MakeUserThumbnailImage(u.RoadieId),
CreatedDate = u.CreatedDate,
LastUpdated = u.LastUpdated,
RegisteredDate = u.RegisteredOn,
LastLoginDate = u.LastLogin,
LastApiAccessDate = u.LastApiAccess,
LastActivity = lastActivity
};
UserList[] rows = null;
var rowCount = result.Count();
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "User.Text", "ASC" } }) : request.OrderValue(null);
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "User.Text", "ASC" } })
: request.OrderValue();
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
if (rows.Any())
{
foreach (var row in rows)
{
var userArtists = this.DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == row.DatabaseId).ToArray();
var userReleases = this.DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == row.DatabaseId).ToArray();
var userTracks = this.DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == row.DatabaseId).ToArray();
var userArtists = DbContext.UserArtists.Include(x => x.Artist)
.Where(x => x.UserId == row.DatabaseId).ToArray();
var userReleases = DbContext.UserReleases.Include(x => x.Release)
.Where(x => x.UserId == row.DatabaseId).ToArray();
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == row.DatabaseId)
.ToArray();
row.Statistics = new UserStatistics
{
@ -136,7 +140,7 @@ namespace Roadie.Api.Services
DislikedTracks = userTracks.Where(x => x.IsDisliked ?? false).Count()
};
}
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<UserList>
{
@ -150,19 +154,13 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var artist = this.GetArtist(artistId);
if (artist == null)
{
return new OperationResult<bool>(true, $"Invalid Artist [{ artistId }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Artist, artist.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var artist = GetArtist(artistId);
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist [{artistId}]");
var result = await SetBookmark(user, BookmarkType.Artist, artist.Id, isBookmarked);
this.CacheManager.ClearRegion(artist.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
return new OperationResult<bool>
{
@ -173,49 +171,35 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleArtistDisliked(artistId, user, isDisliked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleArtistDisliked(artistId, user, isDisliked);
}
public async Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleArtistFavorite(artistId, user, isFavorite);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleArtistFavorite(artistId, user, isFavorite);
}
public async Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<short>(true, $"Invalid User [{ roadieUser }]");
}
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<short>(true, $"Invalid User [{roadieUser}]");
return await base.SetArtistRating(artistId, user, rating);
}
public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser,
bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var collection = this.GetCollection(collectionId);
if (collection == null)
{
return new OperationResult<bool>(true, $"Invalid Collection [{ collectionId }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Collection, collection.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var collection = GetCollection(collectionId);
if (collection == null) return new OperationResult<bool>(true, $"Invalid Collection [{collectionId}]");
var result = await SetBookmark(user, BookmarkType.Collection, collection.Id, isBookmarked);
this.CacheManager.ClearRegion(collection.CacheRegion);
CacheManager.ClearRegion(collection.CacheRegion);
return new OperationResult<bool>
{
@ -226,19 +210,13 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var label = this.GetLabel(labelId);
if (label == null)
{
return new OperationResult<bool>(true, $"Invalid Label [{ labelId }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Label, label.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var label = GetLabel(labelId);
if (label == null) return new OperationResult<bool>(true, $"Invalid Label [{labelId}]");
var result = await SetBookmark(user, BookmarkType.Label, label.Id, isBookmarked);
this.CacheManager.ClearRegion(label.CacheRegion);
CacheManager.ClearRegion(label.CacheRegion);
return new OperationResult<bool>
{
@ -247,21 +225,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser,
bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var playlist = this.GetPlaylist(playlistId);
if (playlist == null)
{
return new OperationResult<bool>(true, $"Invalid Playlist [{ playlistId }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Playlist, playlist.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var playlist = GetPlaylist(playlistId);
if (playlist == null) return new OperationResult<bool>(true, $"Invalid Playlist [{playlistId}]");
var result = await SetBookmark(user, BookmarkType.Playlist, playlist.Id, isBookmarked);
this.CacheManager.ClearRegion(playlist.CacheRegion);
CacheManager.ClearRegion(playlist.CacheRegion);
return new OperationResult<bool>
{
@ -272,19 +245,13 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var release = this.GetRelease(releaseid);
if (release == null)
{
return new OperationResult<bool>(true, $"Invalid Release [{ releaseid }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Release, release.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var release = GetRelease(releaseid);
if (release == null) return new OperationResult<bool>(true, $"Invalid Release [{releaseid}]");
var result = await SetBookmark(user, BookmarkType.Release, release.Id, isBookmarked);
this.CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
return new OperationResult<bool>
{
@ -295,49 +262,34 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleReleaseDisliked(releaseId, user, isDisliked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleReleaseDisliked(releaseId, user, isDisliked);
}
public async Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleReleaseFavorite(releaseId, user, isFavorite);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleReleaseFavorite(releaseId, user, isFavorite);
}
public async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<short>(true, $"Invalid User [{ roadieUser }]");
}
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<short>(true, $"Invalid User [{roadieUser}]");
return await base.SetReleaseRating(releaseId, user, rating);
}
public async Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
var track = this.GetTrack(trackId);
if (track == null)
{
return new OperationResult<bool>(true, $"Invalid Track [{ trackId }]");
}
var result = await this.SetBookmark(user, Library.Enums.BookmarkType.Track, track.Id, isBookmarked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
var track = GetTrack(trackId);
if (track == null) return new OperationResult<bool>(true, $"Invalid Track [{trackId}]");
var result = await SetBookmark(user, BookmarkType.Track, track.Id, isBookmarked);
this.CacheManager.ClearRegion(track.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
return new OperationResult<bool>
{
@ -348,137 +300,88 @@ namespace Roadie.Api.Services
public async Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleTrackDisliked(trackId, user, isDisliked);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleTrackDisliked(trackId, user, isDisliked);
}
public async Task<OperationResult<bool>> SetTrackFavorite(Guid trackId, User roadieUser, bool isFavorite)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.ToggleTrackFavorite(trackId, user, isFavorite);
var user = GetUser(roadieUser.UserId);
if (user == null) return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
return await ToggleTrackFavorite(trackId, user, isFavorite);
}
public async Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating)
{
var timings = new Dictionary<string, long>();
var sw = Stopwatch.StartNew();
var user = this.GetUser(roadieUser.UserId);
var user = GetUser(roadieUser.UserId);
sw.Stop();
timings.Add("GetUser", sw.ElapsedMilliseconds);
if (user == null)
{
return new OperationResult<short>(true, $"Invalid User [{ roadieUser }]");
}
if (user == null) return new OperationResult<short>(true, $"Invalid User [{roadieUser}]");
sw.Start();
var result = await base.SetTrackRating(trackId, user, rating);
sw.Stop();
timings.Add("SetTrackRating", sw.ElapsedMilliseconds);
result.AdditionalData.Add("Timing", sw.ElapsedMilliseconds);
this.Logger.LogInformation($"User `{ roadieUser }` set rating [{ rating }] on TrackId [{ trackId }]. Result [{ JsonConvert.SerializeObject(result) }]");
Logger.LogInformation(
$"User `{roadieUser}` set rating [{rating}] on TrackId [{trackId}]. Result [{JsonConvert.SerializeObject(result)}]");
return result;
}
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(ApplicationUser user, string token)
public async Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName,
string token)
{
var lastFmSessionKeyResult = await this.LastFmHelper.GetSessionKeyForUserToken(token);
if(!lastFmSessionKeyResult.IsSuccess)
{
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{ token }]");
}
// Check concurrency stamp
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
}
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
user.LastUpdated = DateTime.UtcNow;
user.ConcurrencyStamp = Guid.NewGuid().ToString();
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
this.Logger.LogInformation($"User `{ user }` Updated LastFm SessionKey");
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token)
{
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
if (user == null)
{
return new OperationResult<bool>(true, $"User Not Found [{ userId }]");
}
if (integrationName == "lastfm")
{
return await this.UpdateLastFMSessionKey(user, token);
}
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
if (user == null) return new OperationResult<bool>(true, $"User Not Found [{userId}]");
if (integrationName == "lastfm") return await UpdateLastFMSessionKey(user, token);
throw new NotImplementedException();
}
public async Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel)
{
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
if (user == null)
{
return new OperationResult<bool>(true, string.Format("User Not Found [{0}]", userBeingUpdatedModel.UserId));
}
return new OperationResult<bool>(true,
string.Format("User Not Found [{0}]", userBeingUpdatedModel.UserId));
if (user.Id != userPerformingUpdate.Id && !userPerformingUpdate.IsAdmin)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("Access Denied") }
};
}
// Check concurrency stamp
if (user.ConcurrencyStamp != userBeingUpdatedModel.ConcurrencyStamp)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
}
// Check that username (if changed) doesn't already exist
if (user.UserName != userBeingUpdatedModel.UserName)
{
var userByUsername = this.DbContext.Users.FirstOrDefault(x => x.NormalizedUserName == userBeingUpdatedModel.UserName.ToUpper());
var userByUsername = DbContext.Users.FirstOrDefault(x =>
x.NormalizedUserName == userBeingUpdatedModel.UserName.ToUpper());
if (userByUsername != null)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("Username already in use") }
};
}
}
// Check that email (if changed) doesn't already exist
if (user.Email != userBeingUpdatedModel.Email)
{
var userByEmail = this.DbContext.Users.FirstOrDefault(x => x.NormalizedEmail == userBeingUpdatedModel.Email.ToUpper());
var userByEmail =
DbContext.Users.FirstOrDefault(x => x.NormalizedEmail == userBeingUpdatedModel.Email.ToUpper());
if (userByEmail != null)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("Email already in use") }
};
}
}
user.UserName = userBeingUpdatedModel.UserName;
user.NormalizedUserName = userBeingUpdatedModel.UserName.ToUpper();
user.Email = userBeingUpdatedModel.Email;
@ -504,35 +407,36 @@ namespace Roadie.Api.Services
{
var imageData = ImageHelper.ImageDataFromUrl(userBeingUpdatedModel.AvatarData);
if (imageData != null)
{
user.Avatar = ImageHelper.ResizeImage(imageData, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
}
user.Avatar = ImageHelper.ResizeImage(imageData, Configuration.ThumbnailImageSize.Width,
Configuration.ThumbnailImageSize.Height);
}
await this.DbContext.SaveChangesAsync();
if (!string.IsNullOrEmpty(userBeingUpdatedModel.Password) && !string.IsNullOrEmpty(userBeingUpdatedModel.PasswordConfirmation))
await DbContext.SaveChangesAsync();
if (!string.IsNullOrEmpty(userBeingUpdatedModel.Password) &&
!string.IsNullOrEmpty(userBeingUpdatedModel.PasswordConfirmation))
{
if (userBeingUpdatedModel.Password != userBeingUpdatedModel.PasswordConfirmation)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("Password does not match confirmation") }
};
}
string resetToken = await UserManager.GeneratePasswordResetTokenAsync(user);
var identityResult = await UserManager.ResetPasswordAsync(user, resetToken, userBeingUpdatedModel.Password);
var resetToken = await UserManager.GeneratePasswordResetTokenAsync(user);
var identityResult =
await UserManager.ResetPasswordAsync(user, resetToken, userBeingUpdatedModel.Password);
if (!identityResult.Succeeded)
{
return new OperationResult<bool>
{
Errors = identityResult.Errors != null ? identityResult.Errors.Select(x => new Exception($"Code [{ x.Code }], Description [{ x.Description }]")) : new List<Exception> { new Exception("Unable to reset password") }
Errors = identityResult.Errors != null
? identityResult.Errors.Select(x =>
new Exception($"Code [{x.Code}], Description [{x.Description}]"))
: new List<Exception> { new Exception("Unable to reset password") }
};
}
}
this.CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
this.Logger.LogInformation($"User `{ userPerformingUpdate }` modifed user `{ userBeingUpdatedModel }`");
Logger.LogInformation($"User `{userPerformingUpdate}` modifed user `{userBeingUpdatedModel}`");
return new OperationResult<bool>
{
@ -541,18 +445,19 @@ namespace Roadie.Api.Services
};
}
private async Task<OperationResult<bool>> SetBookmark(ApplicationUser user, Library.Enums.BookmarkType bookmarktype, int bookmarkTargetId, bool isBookmarked)
private async Task<OperationResult<bool>> SetBookmark(ApplicationUser user, BookmarkType bookmarktype,
int bookmarkTargetId, bool isBookmarked)
{
var bookmark = this.DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
x.BookmarkType == bookmarktype &&
x.UserId == user.Id);
var bookmark = DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
x.BookmarkType == bookmarktype &&
x.UserId == user.Id);
if (!isBookmarked)
{
// Remove bookmark
if (bookmark != null)
{
this.DbContext.Bookmarks.Remove(bookmark);
await this.DbContext.SaveChangesAsync();
DbContext.Bookmarks.Remove(bookmark);
await DbContext.SaveChangesAsync();
}
}
else
@ -560,19 +465,46 @@ namespace Roadie.Api.Services
// Add bookmark
if (bookmark == null)
{
this.DbContext.Bookmarks.Add(new data.Bookmark
DbContext.Bookmarks.Add(new data.Bookmark
{
UserId = user.Id,
BookmarkTargetId = bookmarkTargetId,
BookmarkType = bookmarktype,
CreatedDate = DateTime.UtcNow,
Status = Library.Enums.Statuses.Ok
Status = Statuses.Ok
});
await this.DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync();
}
}
this.CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(ApplicationUser user, string token)
{
var lastFmSessionKeyResult = await LastFmHelper.GetSessionKeyForUserToken(token);
if (!lastFmSessionKeyResult.IsSuccess)
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{token}]");
// Check concurrency stamp
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
user.LastUpdated = DateTime.UtcNow;
user.ConcurrencyStamp = Guid.NewGuid().ToString();
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
Logger.LogInformation($"User `{user}` Updated LastFm SessionKey");
return new OperationResult<bool>
{
@ -583,83 +515,98 @@ namespace Roadie.Api.Services
private Task<OperationResult<User>> UserByIdAction(Guid id, IEnumerable<string> includes)
{
var user = this.GetUser(id);
var user = GetUser(id);
if (user == null)
{
return Task.FromResult(new OperationResult<User>(true, string.Format("User Not Found [{0}]", id)));
}
var model = user.Adapt<User>();
if (includes != null && includes.Any())
{
if (includes.Contains("stats"))
{
var userArtists = this.DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
var userReleases = this.DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
var userTracks = this.DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
var userArtists =
DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ??
new data.UserArtist[0];
var userReleases =
DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ??
new data.UserRelease[0];
var userTracks =
DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ??
new data.UserTrack[0];
var mostPlayedArtist = (from a in this.DbContext.Artists
join r in this.DbContext.Releases on a.Id equals r.ArtistId
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
join ut in this.DbContext.UserTracks on t.Id equals ut.TrackId
var mostPlayedArtist = (from a in DbContext.Artists
join r in DbContext.Releases on a.Id equals r.ArtistId
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
where ut.UserId == user.Id
select new { a, ut.PlayedCount })
.GroupBy(a => a.a)
.Select(x => new
{
Artist = x.Key,
Played = x.Sum(t => t.PlayedCount)
})
.OrderByDescending(x => x.Played)
.FirstOrDefault();
.GroupBy(a => a.a)
.Select(x => new
{
Artist = x.Key,
Played = x.Sum(t => t.PlayedCount)
})
.OrderByDescending(x => x.Played)
.FirstOrDefault();
var mostPlayedReleaseId = (from r in this.DbContext.Releases
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
join ut in this.DbContext.UserTracks on t.Id equals ut.TrackId
var mostPlayedReleaseId = (from r in DbContext.Releases
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
where ut.UserId == user.Id
select new { r, ut.PlayedCount })
.GroupBy(r => r.r)
.Select(x => new
{
Release = x.Key,
Played = x.Sum(t => t.PlayedCount)
})
.OrderByDescending(x => x.Played)
.Select(x => x.Release.RoadieId)
.FirstOrDefault();
.GroupBy(r => r.r)
.Select(x => new
{
Release = x.Key,
Played = x.Sum(t => t.PlayedCount)
})
.OrderByDescending(x => x.Played)
.Select(x => x.Release.RoadieId)
.FirstOrDefault();
var mostPlayedRelease = this.GetRelease(mostPlayedReleaseId);
var mostPlayedRelease = GetRelease(mostPlayedReleaseId);
var mostPlayedTrackUserTrack = userTracks
.OrderByDescending(x => x.PlayedCount)
.FirstOrDefault();
var mostPlayedTrack = mostPlayedTrackUserTrack == null ? null : this.DbContext.Tracks
.Include(x => x.TrackArtist)
.Include(x => x.ReleaseMedia)
.Include("ReleaseMedia.Release")
.Include("ReleaseMedia.Release.Artist")
.FirstOrDefault(x => x.Id == mostPlayedTrackUserTrack.TrackId);
.OrderByDescending(x => x.PlayedCount)
.FirstOrDefault();
var mostPlayedTrack = mostPlayedTrackUserTrack == null
? null
: DbContext.Tracks
.Include(x => x.TrackArtist)
.Include(x => x.ReleaseMedia)
.Include("ReleaseMedia.Release")
.Include("ReleaseMedia.Release.Artist")
.FirstOrDefault(x => x.Id == mostPlayedTrackUserTrack.TrackId);
model.Statistics = new UserStatistics
{
MostPlayedArtist = mostPlayedArtist == null ? null : models.ArtistList.FromDataArtist(mostPlayedArtist.Artist, this.MakeArtistThumbnailImage(mostPlayedArtist.Artist.RoadieId)),
MostPlayedRelease = mostPlayedRelease == null ? null : models.Releases.ReleaseList.FromDataRelease(mostPlayedRelease,
mostPlayedRelease.Artist,
this.HttpContext.BaseUrl,
this.MakeArtistThumbnailImage(mostPlayedRelease.Artist.RoadieId),
this.MakeReleaseThumbnailImage(mostPlayedRelease.RoadieId)),
MostPlayedTrack = mostPlayedTrack == null ? null : TrackList.FromDataTrack(this.MakeTrackPlayUrl(user, mostPlayedTrack.Id, mostPlayedTrack.RoadieId),
mostPlayedTrack,
mostPlayedTrack.ReleaseMedia.MediaNumber,
mostPlayedTrack.ReleaseMedia.Release,
mostPlayedTrack.ReleaseMedia.Release.Artist,
mostPlayedTrack.TrackArtist,
this.HttpContext.BaseUrl,
this.MakeTrackThumbnailImage(mostPlayedTrack.RoadieId),
this.MakeReleaseThumbnailImage(mostPlayedTrack.ReleaseMedia.Release.RoadieId),
this.MakeArtistThumbnailImage(mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
this.MakeArtistThumbnailImage(mostPlayedTrack.TrackArtist == null ? null : (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
MostPlayedArtist = mostPlayedArtist == null
? null
: models.ArtistList.FromDataArtist(mostPlayedArtist.Artist,
MakeArtistThumbnailImage(mostPlayedArtist.Artist.RoadieId)),
MostPlayedRelease = mostPlayedRelease == null
? null
: ReleaseList.FromDataRelease(mostPlayedRelease,
mostPlayedRelease.Artist,
HttpContext.BaseUrl,
MakeArtistThumbnailImage(mostPlayedRelease.Artist.RoadieId),
MakeReleaseThumbnailImage(mostPlayedRelease.RoadieId)),
MostPlayedTrack = mostPlayedTrack == null
? null
: models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, mostPlayedTrack.Id, mostPlayedTrack.RoadieId),
mostPlayedTrack,
mostPlayedTrack.ReleaseMedia.MediaNumber,
mostPlayedTrack.ReleaseMedia.Release,
mostPlayedTrack.ReleaseMedia.Release.Artist,
mostPlayedTrack.TrackArtist,
HttpContext.BaseUrl,
MakeTrackThumbnailImage(mostPlayedTrack.RoadieId),
MakeReleaseThumbnailImage(mostPlayedTrack.ReleaseMedia.Release.RoadieId),
MakeArtistThumbnailImage(mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
MakeArtistThumbnailImage(mostPlayedTrack.TrackArtist == null
? null
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
RatedArtists = userArtists.Where(x => x.Rating > 0).Count(),
FavoritedArtists = userArtists.Where(x => x.IsFavorite ?? false).Count(),
DislikedArtists = userArtists.Where(x => x.IsDisliked ?? false).Count(),
@ -672,7 +619,6 @@ namespace Roadie.Api.Services
DislikedTracks = userTracks.Where(x => x.IsDisliked ?? false).Count()
};
}
}
return Task.FromResult(new OperationResult<User>
{

View file

@ -29,11 +29,11 @@
<PackageReference Include="Microsoft.AspNetCore.OData" Version="7.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
<PackageReference Include="Serilog.Exceptions" Version="5.2.0" />
<PackageReference Include="Serilog.Exceptions" Version="5.3.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.RollingFileAlternate" Version="2.0.9" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.4.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.5.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.17" />
</ItemGroup>

View file

@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{1BA7
roadie.sql = roadie.sql
Upgrade0001.sql = Upgrade0001.sql
Upgrade0002.sql = Upgrade0002.sql
Upgrade0003.sql = Upgrade0003.sql
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Services", "Roadie.Api.Services\Roadie.Api.Services.csproj", "{7B37031E-F2AE-4BE2-9F6F-005CA7A6FDF1}"

View file

@ -0,0 +1,11 @@
-- Create collection missing table for < 1.0.2.0 database
CREATE TABLE `collectionMissing` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`collectionId` int(11) NOT NULL,
`isArtistFound` tinyint(1) DEFAULT NULL,
`position` int(11) NOT NULL,
`artist` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
`release` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `ix_collection_collectionId` (`collectionId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View file

@ -1,7 +1,7 @@
-- ///
-- Roadie version 1.0.1.0 new database script, if upgrading skip this and run Upgrade*.sql scripts from your version to current.
-- Roadie version 1.0.2.0 new database script, if upgrading skip this and run Upgrade*.sql scripts from your version to current.
-- ///
--
-- MySQL dump 10.17 Distrib 10.3.16-MariaDB, for Linux (x86_64)
--
-- Host: localhost Database: roadie_dev
@ -186,6 +186,23 @@ CREATE TABLE `collection` (
KEY `maintainerId` (`maintainerId`),
KEY `ix_collection_roadieId` (`roadieId`),
CONSTRAINT `collection_ibfk_1` FOREIGN KEY (`maintainerId`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `collectionMissing`
--
DROP TABLE IF EXISTS `collectionMissing`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `collectionMissing` (
`collectionId` int(11) NOT NULL,
`isArtistFound` tinyint(1) DEFAULT NULL,
`position` int(11) NOT NULL,
`artist` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
`release` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
KEY `ix_collection_collectionId` (`collectionId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@ -212,7 +229,7 @@ CREATE TABLE `collectionrelease` (
KEY `ix_collectionrelease_roadieId` (`roadieId`),
CONSTRAINT `collectionrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `collectionrelease_ibfk_2` FOREIGN KEY (`collectionId`) REFERENCES `collection` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@ -256,7 +273,7 @@ CREATE TABLE `comment` (
CONSTRAINT `commentrelease_ibfk_1` FOREIGN KEY (`releaseId`) REFERENCES `release` (`id`) ON DELETE CASCADE,
CONSTRAINT `commenttrack_ibfk_1` FOREIGN KEY (`trackId`) REFERENCES `track` (`id`) ON DELETE CASCADE,
CONSTRAINT `commentuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@ -282,7 +299,7 @@ CREATE TABLE `commentReaction` (
KEY `commentReactioncomment_ibfk_1` (`commentId`),
CONSTRAINT `commentReactioncomment_ibfk_1` FOREIGN KEY (`commentId`) REFERENCES `comment` (`id`) ON DELETE CASCADE,
CONSTRAINT `commentReactionuser_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
@ -1014,4 +1031,4 @@ SET character_set_client = @saved_cs_client;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2019-06-25 15:15:52
-- Dump completed on 2019-06-30 8:12:31