mirror of
https://github.com/sphildreth/roadie
synced 2024-11-22 20:23:16 +00:00
Profile edit work
This commit is contained in:
parent
3728a27c6f
commit
711f98b419
14 changed files with 331 additions and 86 deletions
|
@ -22,11 +22,11 @@ namespace Roadie.Api.Controllers
|
|||
[AllowAnonymous]
|
||||
public class AccountController : ControllerBase
|
||||
{
|
||||
private readonly IConfiguration configuration;
|
||||
private readonly ILogger<AccountController> logger;
|
||||
private readonly SignInManager<ApplicationUser> signInManager;
|
||||
private readonly ITokenService tokenService;
|
||||
private readonly UserManager<ApplicationUser> userManager;
|
||||
private readonly IConfiguration Configuration;
|
||||
private readonly ILogger<AccountController> Logger;
|
||||
private readonly SignInManager<ApplicationUser> SignInManager;
|
||||
private readonly ITokenService TokenService;
|
||||
private readonly UserManager<ApplicationUser> UserManager;
|
||||
private IRoadieSettings RoadieSettings { get; }
|
||||
private ICacheManager CacheManager { get; }
|
||||
private IAdminService AdminService { get; }
|
||||
|
@ -40,11 +40,11 @@ namespace Roadie.Api.Controllers
|
|||
ITokenService tokenService,
|
||||
ICacheManager cacheManager)
|
||||
{
|
||||
this.userManager = userManager;
|
||||
this.signInManager = signInManager;
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.tokenService = tokenService;
|
||||
this.UserManager = userManager;
|
||||
this.SignInManager = signInManager;
|
||||
this.Configuration = configuration;
|
||||
this.Logger = logger;
|
||||
this.TokenService = tokenService;
|
||||
this.CacheManager = cacheManager;
|
||||
|
||||
this.RoadieSettings = new RoadieSettings();
|
||||
|
@ -61,19 +61,19 @@ namespace Roadie.Api.Controllers
|
|||
try
|
||||
{
|
||||
// Login user
|
||||
var loginResult = await signInManager.PasswordSignInAsync(model.Username, model.Password, isPersistent: false, lockoutOnFailure: false);
|
||||
var loginResult = await SignInManager.PasswordSignInAsync(model.Username, model.Password, isPersistent: false, lockoutOnFailure: false);
|
||||
if (!loginResult.Succeeded)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
var user = await userManager.FindByNameAsync(model.Username);
|
||||
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}]");
|
||||
await UserManager.UpdateAsync(user);
|
||||
var t = await this.TokenService.GenerateToken(user, this.UserManager);
|
||||
this.Logger.LogInformation($"Successfully authenticated User [{ model.Username}]");
|
||||
this.CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
var avatarUrl = $"{this.Request.Scheme}://{this.Request.Host}/images/user/{ user.RoadieId }/{ this.RoadieSettings.ThumbnailImageSize.Width }/{ this.RoadieSettings.ThumbnailImageSize.Height }";
|
||||
return Ok(new
|
||||
|
@ -89,7 +89,7 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.logger.LogError(ex, "Eror in CreateToken");
|
||||
this.Logger.LogError(ex, "Eror in CreateToken");
|
||||
return BadRequest();
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
if (!String.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
var user = await userManager.FindByNameAsync(username);
|
||||
return Ok(await this.tokenService.GenerateToken(user, this.userManager));
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
return Ok(await this.TokenService.GenerateToken(user, this.UserManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -126,19 +126,20 @@ namespace Roadie.Api.Controllers
|
|||
var user = new ApplicationUser
|
||||
{
|
||||
UserName = registerModel.Username,
|
||||
RegisteredOn = DateTime.UtcNow,
|
||||
Email = registerModel.Email
|
||||
};
|
||||
|
||||
var identityResult = await this.userManager.CreateAsync(user, registerModel.Password);
|
||||
var identityResult = await this.UserManager.CreateAsync(user, registerModel.Password);
|
||||
if (identityResult.Succeeded)
|
||||
{
|
||||
if(user.Id == 1)
|
||||
{
|
||||
await this.AdminService.DoInitialSetup(user, this.userManager);
|
||||
await this.AdminService.DoInitialSetup(user, this.UserManager);
|
||||
}
|
||||
await signInManager.SignInAsync(user, isPersistent: false);
|
||||
var t = await this.tokenService.GenerateToken(user, this.userManager);
|
||||
this.logger.LogInformation($"Successfully authenticated User [{ registerModel.Username}]");
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
var t = await this.TokenService.GenerateToken(user, this.UserManager);
|
||||
this.Logger.LogInformation($"Successfully created and authenticated User [{ registerModel.Username}]");
|
||||
this.CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
var avatarUrl = $"{this.Request.Scheme}://{this.Request.Host}/images/user/{ user.RoadieId }/{ this.RoadieSettings.ThumbnailImageSize.Width }/{ this.RoadieSettings.ThumbnailImageSize.Height }";
|
||||
return Ok(new
|
||||
|
@ -172,12 +173,12 @@ namespace Roadie.Api.Controllers
|
|||
CreatedDate = DateTime.UtcNow
|
||||
};
|
||||
|
||||
var identityResult = await this.userManager.ResetPasswordAsync(user, resetPasswordModel.Token, resetPasswordModel.Password);
|
||||
var identityResult = await this.UserManager.ResetPasswordAsync(user, resetPasswordModel.Token, resetPasswordModel.Password);
|
||||
if (identityResult.Succeeded)
|
||||
{
|
||||
this.CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
await signInManager.SignInAsync(user, isPersistent: false);
|
||||
return Ok(this.tokenService.GenerateToken(user, this.userManager));
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
return Ok(this.TokenService.GenerateToken(user, this.UserManager));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using Roadie.Api.Services;
|
|||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
@ -21,41 +22,73 @@ namespace Roadie.Api.Controllers
|
|||
public class UserController : EntityControllerBase
|
||||
{
|
||||
private IUserService UserService { get; }
|
||||
private readonly ITokenService TokenService;
|
||||
|
||||
public UserController(IUserService userService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
|
||||
public UserController(IUserService userService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, ITokenService tokenService, UserManager<ApplicationUser> userManager)
|
||||
: base(cacheManager, configuration, userManager)
|
||||
{
|
||||
this.Logger = logger.CreateLogger("RoadieApi.Controllers.LabelController");
|
||||
this.Logger = logger.CreateLogger("RoadieApi.Controllers.UserController");
|
||||
this.UserService = userService;
|
||||
this.TokenService = tokenService;
|
||||
}
|
||||
|
||||
//[EnableQuery]
|
||||
//public IActionResult Get()
|
||||
//{
|
||||
// return Ok(this._RoadieDbContext.Labels.ProjectToType<models.Label>());
|
||||
//}
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id)
|
||||
{
|
||||
var user = await this.CurrentUserModel();
|
||||
var result = await this.CacheManager.GetAsync($"urn:user_model_by_id:{ id }", async () =>
|
||||
{
|
||||
return await this.UserService.ById(user, id);
|
||||
}, ControllerCacheRegionUrn);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
//[HttpGet("{id}")]
|
||||
//[ProducesResponseType(200)]
|
||||
//[ProducesResponseType(404)]
|
||||
//public IActionResult Get(Guid id)
|
||||
//{
|
||||
// var key = id.ToString();
|
||||
// var result = this._cacheManager.Get<models.Label>(key, () =>
|
||||
// {
|
||||
// var d = this._RoadieDbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
// if (d != null)
|
||||
// {
|
||||
// return d.Adapt<models.Label>();
|
||||
// }
|
||||
// return null;
|
||||
// }, key);
|
||||
// if (result == null)
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// return Ok(result);
|
||||
//}
|
||||
[HttpPost("profile/edit")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> UpdateProfile(User model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var user = await this.CurrentUserModel();
|
||||
var result = await this.UserService.UpdateProfile(user, model);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
this.CacheManager.ClearRegion(ControllerCacheRegionUrn);
|
||||
var modelUser = await UserManager.FindByNameAsync(model.UserName);
|
||||
var t = await this.TokenService.GenerateToken(modelUser, this.UserManager);
|
||||
this.CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
var avatarUrl = $"{this.Request.Scheme}://{this.Request.Host}/images/user/{ modelUser.RoadieId }/{ this.RoadieSettings.ThumbnailImageSize.Width }/{ this.RoadieSettings.ThumbnailImageSize.Height }";
|
||||
return Ok(new
|
||||
{
|
||||
IsSuccess = true,
|
||||
Username = modelUser.UserName,
|
||||
modelUser.Email,
|
||||
modelUser.LastLogin,
|
||||
avatarUrl,
|
||||
Token = t,
|
||||
modelUser.Timeformat,
|
||||
modelUser.Timezone
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("setArtistRating/{releaseId}/{rating}")]
|
||||
|
|
|
@ -109,9 +109,9 @@ namespace Roadie.Api.ModelBinding
|
|||
|
||||
var model = new SubsonicRequest
|
||||
{
|
||||
AlbumCount = SafeParser.ToNumber<int?>(modelDictionary["albumCount"]) ?? 20,
|
||||
AlbumCount = SafeParser.ToNumber<short?>(modelDictionary["albumCount"]) ?? 20,
|
||||
AlbumOffset = SafeParser.ToNumber<int?>(modelDictionary["albumOffset"]),
|
||||
ArtistCount = SafeParser.ToNumber<int?>(modelDictionary["artistCount"]) ?? 20,
|
||||
ArtistCount = SafeParser.ToNumber<short?>(modelDictionary["artistCount"]) ?? 20,
|
||||
ArtistName = SafeParser.ToString(modelDictionary["artist"]),
|
||||
ArtistOffset = SafeParser.ToNumber<int?>(modelDictionary["artistOffset"]),
|
||||
c = SafeParser.ToString(modelDictionary["c"]),
|
||||
|
@ -127,8 +127,8 @@ namespace Roadie.Api.ModelBinding
|
|||
p = SafeParser.ToString(modelDictionary["p"]),
|
||||
Query = SafeParser.ToString(modelDictionary["query"]),
|
||||
s = SafeParser.ToString(modelDictionary["s"]),
|
||||
Size = SafeParser.ToNumber<int?>(modelDictionary["size"]),
|
||||
SongCount = SafeParser.ToNumber<int?>(modelDictionary["songCount"]) ?? 20,
|
||||
Size = SafeParser.ToNumber<short?>(modelDictionary["size"]),
|
||||
SongCount = SafeParser.ToNumber<short?>(modelDictionary["songCount"]) ?? 20,
|
||||
SongOffset = SafeParser.ToNumber<int?>(modelDictionary["songOffset"]),
|
||||
t = SafeParser.ToString(modelDictionary["t"]),
|
||||
ToYear = SafeParser.ToNumber<int?>(modelDictionary["toYear"]),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
|
@ -8,6 +9,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IUserService
|
||||
{
|
||||
Task<OperationResult<User>> ById(User user, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
|
||||
|
||||
Task<PagedResult<UserList>> List(PagedRequest request);
|
||||
|
||||
Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked);
|
||||
|
@ -31,5 +36,6 @@ namespace Roadie.Api.Services
|
|||
Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating);
|
||||
|
||||
}
|
||||
}
|
|
@ -172,7 +172,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
BookmarkTargetId = track.Id,
|
||||
BookmarkType = Library.Enums.BookmarkType.Track,
|
||||
UserId = roadieUser.Id,
|
||||
UserId = roadieUser.Id.Value,
|
||||
Comment = comment,
|
||||
Position = position
|
||||
};
|
||||
|
@ -1691,7 +1691,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
var chatMessage = new data.ChatMessage
|
||||
{
|
||||
UserId = roadieUser.Id,
|
||||
UserId = roadieUser.Id.Value,
|
||||
Message = request.Message
|
||||
};
|
||||
this.DbContext.ChatMessages.Add(chatMessage);
|
||||
|
@ -1817,7 +1817,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
// Indexes for "Music" Artists alphabetically
|
||||
pagedRequest.SkipValue = 0;
|
||||
pagedRequest.Limit = int.MaxValue;
|
||||
pagedRequest.Limit = short.MaxValue;
|
||||
pagedRequest.Sort = "Artist.Text";
|
||||
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||
request: pagedRequest,
|
||||
|
@ -1898,7 +1898,7 @@ namespace Roadie.Api.Services
|
|||
// Indexes for Artists alphabetically
|
||||
var pagedRequest = request.PagedRequest;
|
||||
pagedRequest.SkipValue = 0;
|
||||
pagedRequest.Limit = int.MaxValue;
|
||||
pagedRequest.Limit = short.MaxValue;
|
||||
pagedRequest.Sort = "Artist.Text";
|
||||
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||
request: pagedRequest,
|
||||
|
|
|
@ -29,11 +29,12 @@ namespace Roadie.Api.Services
|
|||
|
||||
var claims = new Claim[]
|
||||
{
|
||||
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())
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
|
||||
new Claim("roadie_id", user.RoadieId.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);
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Mapster;
|
||||
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.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Statistics;
|
||||
|
@ -32,6 +34,142 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<OperationResult<User>> ById(User user, Guid id)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
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 () =>
|
||||
{
|
||||
tsw.Restart();
|
||||
var rr = await this.UserByIdAction(id);
|
||||
tsw.Stop();
|
||||
timings.Add("UserByIdAction", tsw.ElapsedMilliseconds);
|
||||
return rr;
|
||||
|
||||
}, ApplicationUser.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null)
|
||||
{
|
||||
result.Data.Avatar = this.MakeUserThumbnailImage(id);
|
||||
}
|
||||
timings.Add("operation", sw.ElapsedMilliseconds);
|
||||
this.Logger.LogDebug("ById Timings: id [{0}]", id);
|
||||
return new OperationResult<User>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
Errors = result?.Errors,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel)
|
||||
{
|
||||
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
|
||||
if (user == null)
|
||||
{
|
||||
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());
|
||||
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());
|
||||
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;
|
||||
user.NormalizedEmail = userBeingUpdatedModel.Email.ToUpper();
|
||||
user.ApiToken = userBeingUpdatedModel.ApiToken;
|
||||
user.Timezone = userBeingUpdatedModel.Timezone;
|
||||
user.Timeformat = userBeingUpdatedModel.Timeformat;
|
||||
user.PlayerTrackLimit = userBeingUpdatedModel.PlayerTrackLimit;
|
||||
user.RandomReleaseLimit = userBeingUpdatedModel.RandomReleaseLimit;
|
||||
user.RecentlyPlayedLimit = userBeingUpdatedModel.RecentlyPlayedLimit;
|
||||
user.Profile = userBeingUpdatedModel.Profile;
|
||||
user.DoUseHtmlPlayer = userBeingUpdatedModel.DoUseHtmlPlayer;
|
||||
user.IsPrivate = userBeingUpdatedModel.IsPrivate;
|
||||
user.LastUpdated = DateTime.UtcNow;
|
||||
user.FtpUrl = userBeingUpdatedModel.FtpUrl;
|
||||
user.FtpDirectory = userBeingUpdatedModel.FtpDirectory;
|
||||
user.FtpUsername = userBeingUpdatedModel.FtpUsername;
|
||||
user.FtpPassword = EncryptionHelper.Encrypt(userBeingUpdatedModel.FtpPassword, user.RoadieId.ToString());
|
||||
user.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
|
||||
if(!string.IsNullOrEmpty(userBeingUpdatedModel.AvatarData))
|
||||
{
|
||||
var imageData = ImageHelper.ImageDataFromUrl(userBeingUpdatedModel.AvatarData);
|
||||
if(imageData != null)
|
||||
{
|
||||
user.Avatar = ImageHelper.ResizeImage(imageData, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
|
||||
}
|
||||
}
|
||||
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
this.CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
|
||||
|
||||
this.Logger.LogInformation($"User `{ userPerformingUpdate }` modifed user `{ userBeingUpdatedModel }`");
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<User>> UserByIdAction(Guid id)
|
||||
{
|
||||
var user = this.GetUser(id);
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<User>(true, string.Format("User Not Found [{0}]", id));
|
||||
}
|
||||
return new OperationResult<User>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = user.Adapt<User>()
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<UserList>> List(PagedRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace Roadie.Library.Engines
|
|||
sw.Stop();
|
||||
if (artist == null || !artist.IsValid)
|
||||
{
|
||||
this.Logger.LogInformation("ArtistFactory: Artist Not Found By Name [{0}]", ArtistName);
|
||||
this.Logger.LogInformation("ArtistLookupEngine: Artist Not Found By Name [{0}]", ArtistName);
|
||||
if (doFindIfNotInDatabase)
|
||||
{
|
||||
OperationResult<Artist> ArtistSearch = null;
|
||||
|
|
|
@ -93,5 +93,19 @@ namespace Roadie.Library.Imaging
|
|||
return outStream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ImageDataFromUrl(string imageUrl)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(imageUrl))
|
||||
{
|
||||
var dataString = imageUrl.Trim().Replace('-', '+')
|
||||
.Replace("data:image/jpeg;base64,", "")
|
||||
.Replace("data:image/gif;base64,", "")
|
||||
.Replace("data:image/png;base64,", "");
|
||||
return Convert.FromBase64String(dataString);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -30,8 +30,8 @@ namespace Roadie.Library.Models.Pagination
|
|||
}
|
||||
public string Sort { get; set; }
|
||||
public string Order { get; set; }
|
||||
public int? Limit { get; set; } = 10;
|
||||
public int LimitValue
|
||||
public short? Limit { get; set; } = 10;
|
||||
public short LimitValue
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Roadie.Library.Models.Playlists
|
|||
public DataToken Playlist { get; set; }
|
||||
public DataToken User { get; set; }
|
||||
public Image Thumbnail { get; set; }
|
||||
public int? PlaylistCount { get; set; }
|
||||
public short? PlaylistCount { get; set; }
|
||||
public Image UserThumbnail { get; set; }
|
||||
public bool IsPublic { get; set; }
|
||||
public decimal? Duration { get; set; }
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
{
|
||||
public const string ArtistIdIdentifier = "A:";
|
||||
public const string CollectionIdentifier = "C:";
|
||||
public const int MaxPageSize = 100;
|
||||
public const short MaxPageSize = 100;
|
||||
public const string PlaylistdIdentifier = "P:";
|
||||
public const string ReleaseIdIdentifier = "R:";
|
||||
public const string TrackIdIdentifier = "T:";
|
||||
|
@ -199,7 +199,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
/// <summary>
|
||||
/// Maximum number of albums to return.
|
||||
/// </summary>
|
||||
public int? AlbumCount { get; set; }
|
||||
public short? AlbumCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Search result offset for albums. Used for paging.
|
||||
|
@ -209,7 +209,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
/// <summary>
|
||||
/// Maximum number of artists to return.
|
||||
/// </summary>
|
||||
public int? ArtistCount { get; set; }
|
||||
public short? ArtistCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Search result offset for artists. Used for paging.
|
||||
|
@ -313,12 +313,12 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
/// <see>Various *Count properties depending on objects being searched and client version.</see>
|
||||
/// <remark>Something this value is posted as 'count' versus 'size'</remark>
|
||||
/// </summary>
|
||||
public int? Size { get; set; }
|
||||
public short? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of songs to return.
|
||||
/// </summary>
|
||||
public int? SongCount { get; set; }
|
||||
public short? SongCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Search result offset for songs. Used for paging.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Mapster;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Roadie.Library.Models.Users
|
||||
{
|
||||
|
@ -8,16 +9,67 @@ namespace Roadie.Library.Models.Users
|
|||
{
|
||||
public const string ActionKeyUserRated = "__userrated__";
|
||||
|
||||
public bool IsEditor { get; set; }
|
||||
[MaxLength(100)]
|
||||
public string ApiToken { get; set; }
|
||||
|
||||
public Image Avatar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Posted image from a client of selected new base64 encoded avatar for the user
|
||||
/// </summary>
|
||||
public string AvatarData { get; set; }
|
||||
|
||||
public bool DoUseHtmlPlayer { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
[DataType(DataType.EmailAddress)]
|
||||
public string Email { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string FtpDirectory { get; set; }
|
||||
|
||||
[MaxLength(500)]
|
||||
public string FtpPassword { get; set; }
|
||||
|
||||
[MaxLength(250)]
|
||||
public string FtpUrl { get; set; }
|
||||
|
||||
[MaxLength(50)]
|
||||
public string FtpUsername { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string ConcurrencyStamp { get; set; }
|
||||
|
||||
public int? Id { get; set; }
|
||||
public bool IsAdmin { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public bool IsEditor { get; set; }
|
||||
public bool IsPrivate { get; set; }
|
||||
|
||||
public short? PlayerTrackLimit { get; set; }
|
||||
|
||||
[MaxLength(65535)]
|
||||
public string Profile { get; set; }
|
||||
|
||||
public short? RandomReleaseLimit { get; set; }
|
||||
|
||||
public short? RecentlyPlayedLimit { get; set; }
|
||||
|
||||
[StringLength(50)]
|
||||
[Required]
|
||||
public string Timeformat { get; set; }
|
||||
|
||||
[MaxLength(50)]
|
||||
[Required]
|
||||
public string Timezone { get; set; }
|
||||
|
||||
[AdaptMember("RoadieId")]
|
||||
public Guid UserId { get; set; }
|
||||
public int Id { get; set; }
|
||||
public int? PlayerTrackLimit { get; set; }
|
||||
public int? RecentlyPlayedLimit { get; set; }
|
||||
public int? RandomReleaseLimit { get; set; }
|
||||
public bool IsPrivate { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string UserName { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace Roadie.Library.Processors
|
|||
{ "processedFiles", processedFiles },
|
||||
{ "newArtists", this.ArtistLookupEngine.AddedArtistIds.Count() },
|
||||
{ "newReleases", this.ReleaseLookupEngine.AddedReleaseIds.Count() },
|
||||
{ "newTracks", this.ReleaseLookupEngine.AddedTrackIds.Count() }
|
||||
{ "newTracks", this.ReleaseFactory.AddedTrackIds.Count() }
|
||||
},
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue