Work for roadie-vuejs

This commit is contained in:
Steven Hildreth 2018-11-30 21:22:35 -06:00
parent 30b5bf0beb
commit 1ca2d2e063
11 changed files with 263 additions and 87 deletions

View file

@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Models;
using Roadie.Api.Services;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using System;
using System.Linq;
@ -25,6 +26,7 @@ namespace Roadie.Api.Controllers
private readonly SignInManager<ApplicationUser> signInManager;
private readonly ITokenService tokenService;
private readonly UserManager<ApplicationUser> userManager;
private IRoadieSettings RoadieSettings { get; }
public AccountController(
UserManager<ApplicationUser> userManager,
@ -38,6 +40,10 @@ namespace Roadie.Api.Controllers
this.configuration = configuration;
this.logger = logger;
this.tokenService = tokenService;
this.RoadieSettings = new RoadieSettings();
configuration.GetSection("RoadieSettings").Bind(this.RoadieSettings);
}
[HttpPost]
@ -57,15 +63,18 @@ namespace Roadie.Api.Controllers
var user = await userManager.FindByNameAsync(model.Username);
var now = DateTime.UtcNow;
user.LastLogin = now;
user.LastApiAccess = now;
user.LastUpdated = now;
await userManager.UpdateAsync(user);
var t = await this.tokenService.GenerateToken(user, this.userManager);
this.logger.LogInformation($"Successfully authenticated User [{ model.Username}]");
var avatarUrl = $"{this.Request.Scheme}://{this.Request.Host}/images/user/{ user.RoadieId }/{ this.RoadieSettings.ThumbnailImageSize.Width }/{ this.RoadieSettings.ThumbnailImageSize.Height }";
return Ok(new
{
Id = user.RoadieId,
Username = user.UserName,
user.Email,
user.LastLogin,
avatarUrl = avatarUrl,
Token = t
});
}

View file

@ -55,10 +55,11 @@ namespace Roadie.Api.Controllers
[HttpGet]
[ProducesResponseType(200)]
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc, bool? doRandomize = false)
{
var result = await this.ReleaseService.List(user: await this.CurrentUserModel(),
request: request);
request: request,
doRandomize: doRandomize ?? false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);

View file

@ -7,6 +7,7 @@ using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
@ -16,7 +17,7 @@ namespace Roadie.Api.Controllers
[Produces("application/json")]
[Route("users")]
[ApiController]
// [Authorize]
[Authorize]
public class UserController : EntityControllerBase
{
private IUserService UserService { get; }
@ -57,6 +58,44 @@ namespace Roadie.Api.Controllers
//}
[HttpPost("setArtistRating/{releaseId}/{rating}")]
[ProducesResponseType(200)]
public async Task<IActionResult> SetArtistRating(Guid releaseId, short rating)
{
var result = await this.UserService.SetArtistRating(releaseId, await this.CurrentUserModel(), rating);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("setReleaseRating/{releaseId}/{rating}")]
[ProducesResponseType(200)]
public async Task<IActionResult> SetReleaseRating(Guid releaseId, short rating)
{
var result = await this.UserService.SetReleaseRating(releaseId, await this.CurrentUserModel(), rating);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("setTrackRating/{releaseId}/{rating}")]
[ProducesResponseType(200)]
public async Task<IActionResult> SetTrackRating(Guid releaseId, short rating)
{
var result = await this.UserService.SetTrackRating(releaseId, await this.CurrentUserModel(), rating);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet]
[ProducesResponseType(200)]
public async Task<IActionResult> List([FromQuery]PagedRequest request)

View file

@ -1,5 +1,8 @@
using Roadie.Library.Models.Pagination;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
using System;
using System.Threading.Tasks;
namespace Roadie.Api.Services
@ -7,5 +10,8 @@ namespace Roadie.Api.Services
public interface IUserService
{
Task<PagedResult<UserList>> List(PagedRequest request);
Task<OperationResult<bool>> SetReleaseRating(Guid releaseId, User roadieUser, short rating);
Task<OperationResult<bool>> SetArtistRating(Guid artistId, User roadieUser, short rating);
Task<OperationResult<bool>> SetTrackRating(Guid trackId, User roadieUser, short rating);
}
}

View file

@ -134,7 +134,8 @@ namespace Roadie.Api.Services
favoriteReleaseIds = (from a in this.DbContext.Releases
join ur in this.DbContext.UserReleases on a.Id equals ur.ReleaseId
where ur.IsFavorite ?? false
select a.Id
where (roadieUser == null || ur.UserId == roadieUser.Id)
select a.Id
).ToArray();
}
int[] genreReleaseIds = new int[0];
@ -160,6 +161,9 @@ namespace Roadie.Api.Services
request.Order = "ASC";
}
}
//
// TODO list should honor disliked artist and albums
//
var result = (from r in this.DbContext.Releases.Include("Artist")
join a in this.DbContext.Artists on r.ArtistId equals a.Id
where (request.FilterMinimumRating == null || r.Rating >= request.FilterMinimumRating.Value)
@ -322,6 +326,10 @@ namespace Roadie.Api.Services
// }
// }
//}
if(request.FilterFavoriteOnly)
{
rows = rows.OrderBy(x => x.UserRating.Rating).ToArray();
}
sw.Stop();
return new Library.Models.Pagination.PagedResult<ReleaseList>
{

View file

@ -1,6 +1,7 @@
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
@ -11,6 +12,7 @@ using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Api.Services
@ -217,6 +219,136 @@ namespace Roadie.Api.Services
}, ApplicationUser.CacheRegionUrn(id.Value));
}
protected async Task<OperationResult<bool>> SetArtistRating(Guid artistId, ApplicationUser user, short rating)
{
var artist = this.GetArtist(artistId);
if (artist == null)
{
return new OperationResult<bool>(true, $"Invalid Artist Id [{ artistId }]");
}
var userArtist = user.ArtistRatings.FirstOrDefault(x => x.ArtistId == artist.Id);
if (userArtist == null)
{
userArtist = new data.UserArtist
{
Rating = rating,
UserId = user.Id,
ArtistId = artist.Id
};
this.DbContext.UserArtists.Add(userArtist);
}
else
{
userArtist.Rating = rating;
userArtist.LastUpdated = DateTime.UtcNow;
}
await this.DbContext.SaveChangesAsync();
var sql = "UPDATE `artist` set lastUpdated = UTC_DATE(), rating = (SELECT cast(avg(ur.rating) as signed) " +
"FROM `userartist` ur " +
"where artistId = {0}) " +
"WHERE id = {0};";
await this.DbContext.Database.ExecuteSqlCommandAsync(sql, artist.Id);
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(artist.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
protected async Task<OperationResult<bool>> SetReleaseRating(Guid releaseId, ApplicationUser user, short rating)
{
var release = this.GetRelease(releaseId);
if (release == null)
{
return new OperationResult<bool>(true, $"Invalid Release Id [{ releaseId }]");
}
var userRelease = user.ReleaseRatings.FirstOrDefault(x => x.ReleaseId == release.Id);
var now = DateTime.UtcNow;
if (userRelease == null)
{
userRelease = new data.UserRelease
{
Rating = rating,
UserId = user.Id,
ReleaseId = release.Id
};
this.DbContext.UserReleases.Add(userRelease);
}
else
{
userRelease.Rating = rating;
userRelease.LastUpdated = now;
}
await this.DbContext.SaveChangesAsync();
var sql = "UPDATE `release` set lastUpdated = UTC_DATE(), rating = (SELECT cast(avg(ur.rating) as signed) " +
"FROM `userrelease` ur " +
"where releaseId = {0}) " +
"WHERE id = {0};";
await this.DbContext.Database.ExecuteSqlCommandAsync(sql, release.Id);
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(release.CacheRegion);
this.CacheManager.ClearRegion(release.Artist.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
protected async Task<OperationResult<bool>> SetTrackRating(Guid trackId, ApplicationUser user, short rating)
{
var track = this.GetTrack(trackId);
if (track == null)
{
return new OperationResult<bool>(true, $"Invalid Track Id [{ trackId }]");
}
var userTrack = user.TrackRatings.FirstOrDefault(x => x.TrackId == track.Id);
if (userTrack == null)
{
userTrack = new data.UserTrack
{
Rating = rating,
UserId = user.Id,
TrackId = track.Id
};
this.DbContext.UserTracks.Add(userTrack);
}
else
{
userTrack.Rating = rating;
userTrack.LastUpdated = DateTime.UtcNow;
}
await this.DbContext.SaveChangesAsync();
var sql = "UPDATE `track` set lastUpdated = UTC_DATE(), rating = (SELECT cast(avg(ur.rating) as signed) " +
"FROM `usertrack` ur " +
"where trackId = {0}) " +
"WHERE id = {0};";
await this.DbContext.Database.ExecuteSqlCommandAsync(sql, track.Id);
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(track.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
protected Image MakeArtistThumbnailImage(Guid id)
{
return MakeThumbnailImage(id, "artist");

View file

@ -1942,111 +1942,45 @@ namespace Roadie.Api.Services
return this.MusicFolders().First(x => x.id == 2);
}
private async Task<subsonic.SubsonicOperationResult<bool>> SetArtistRating(Guid artistId, ApplicationUser user, short rating)
private new async Task<subsonic.SubsonicOperationResult<bool>> SetArtistRating(Guid artistId, ApplicationUser user, short rating)
{
var artist = this.GetArtist(artistId);
if (artist == null)
var r = await base.SetArtistRating(artistId, user, rating);
if(r.IsNotFoundResult)
{
return new subsonic.SubsonicOperationResult<bool>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Artist Id [{ artistId }]");
}
var userArtist = user.ArtistRatings.FirstOrDefault(x => x.ArtistId == artist.Id);
if (userArtist == null)
{
userArtist = new data.UserArtist
{
Rating = rating,
UserId = user.Id,
ArtistId = artist.Id
};
this.DbContext.UserArtists.Add(userArtist);
}
else
{
userArtist.Rating = rating;
userArtist.LastUpdated = DateTime.UtcNow;
}
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(artist.CacheRegion);
return new subsonic.SubsonicOperationResult<bool>
{
IsSuccess = true,
Data = true
IsSuccess = r.IsSuccess,
Data = r.IsSuccess
};
}
private async Task<subsonic.SubsonicOperationResult<bool>> SetReleaseRating(Guid releaseId, ApplicationUser user, short rating)
private new async Task<subsonic.SubsonicOperationResult<bool>> SetReleaseRating(Guid releaseId, ApplicationUser user, short rating)
{
var release = this.GetRelease(releaseId);
if (release == null)
var r = await base.SetReleaseRating(releaseId, user, rating);
if (r.IsNotFoundResult)
{
return new subsonic.SubsonicOperationResult<bool>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release Id [{ releaseId }]");
}
var userRelease = user.ReleaseRatings.FirstOrDefault(x => x.ReleaseId == release.Id);
if (userRelease == null)
{
userRelease = new data.UserRelease
{
Rating = rating,
UserId = user.Id,
ReleaseId = release.Id
};
this.DbContext.UserReleases.Add(userRelease);
}
else
{
userRelease.Rating = rating;
userRelease.LastUpdated = DateTime.UtcNow;
}
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(release.CacheRegion);
this.CacheManager.ClearRegion(release.Artist.CacheRegion);
return new subsonic.SubsonicOperationResult<bool>
{
IsSuccess = true,
Data = true
IsSuccess = r.IsSuccess,
Data = r.IsSuccess
};
}
private async Task<subsonic.SubsonicOperationResult<bool>> SetTrackRating(Guid trackId, ApplicationUser user, short rating)
private new async Task<subsonic.SubsonicOperationResult<bool>> SetTrackRating(Guid trackId, ApplicationUser user, short rating)
{
var track = this.GetTrack(trackId);
if (track == null)
var r = await base.SetTrackRating(trackId, user, rating);
if (r.IsNotFoundResult)
{
return new subsonic.SubsonicOperationResult<bool>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Track Id [{ trackId }]");
}
var userTrack = user.TrackRatings.FirstOrDefault(x => x.TrackId == track.Id);
if (userTrack == null)
{
userTrack = new data.UserTrack
{
Rating = rating,
UserId = user.Id,
TrackId = track.Id
};
this.DbContext.UserTracks.Add(userTrack);
}
else
{
userTrack.Rating = rating;
userTrack.LastUpdated = DateTime.UtcNow;
}
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(user.CacheRegion);
this.CacheManager.ClearRegion(track.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
return new subsonic.SubsonicOperationResult<bool>
{
IsSuccess = true,
Data = true
IsSuccess = r.IsSuccess,
Data = r.IsSuccess
};
}

View file

@ -31,6 +31,7 @@ namespace Roadie.Api.Services
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, utcNow.ToString())
}.Union(userRoles);

View file

@ -1,8 +1,10 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Statistics;
@ -150,5 +152,35 @@ namespace Roadie.Api.Services
Rows = rows
};
}
public async Task<OperationResult<bool>> SetArtistRating(Guid artistId, User roadieUser, short rating)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.SetArtistRating(artistId, user, rating);
}
public async Task<OperationResult<bool>> SetReleaseRating(Guid releaseId, User roadieUser, short rating)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.SetReleaseRating(releaseId, user, rating);
}
public async Task<OperationResult<bool>> SetTrackRating(Guid trackId, User roadieUser, short rating)
{
var user = this.GetUser(roadieUser.UserId);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{ roadieUser }]");
}
return await base.SetTrackRating(trackId, user, rating);
}
}
}

View file

@ -165,6 +165,7 @@ namespace Roadie.Api
config.TokenValidationParameters = new TokenValidationParameters()
{
IssuerSigningKey = securityKey,
ValidateAudience = true,
ValidAudience = this._configuration["Tokens:Audience"],
ValidateIssuer = true,

View file

@ -1,6 +1,7 @@
using Mapster;
using Newtonsoft.Json;
using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
@ -47,5 +48,17 @@ namespace Roadie.Library.Models.Releases
public DataToken Genre { get; set; }
public DateTime? LastPlayed { get; set; }
public int? Duration { get; set; }
public string DurationTime
{
get
{
if(!this.Duration.HasValue)
{
return "--:--";
}
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"hh\:mm\:ss");
}
}
}
}