Media poster methods added
This commit is contained in:
@@ -24,6 +24,7 @@ public class MediaPhotoRequest : MediaPhoto
|
||||
item.MediaId = MediaId;
|
||||
item.Image = Image;
|
||||
item.MimeType = MimeType;
|
||||
item.UploadDate = DateTime.Now;
|
||||
}
|
||||
|
||||
public void UpdateMediaPhotoImageBackground(MediaPhotoImageBackground item)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace WatchIt.Common.Model.Media;
|
||||
|
||||
public class MediaPosterImage
|
||||
public abstract class MediaPoster
|
||||
{
|
||||
[JsonPropertyName("image")]
|
||||
public required byte[] Image { get; set; }
|
||||
@@ -0,0 +1,19 @@
|
||||
using WatchIt.Database.Model.Media;
|
||||
|
||||
namespace WatchIt.Common.Model.Media;
|
||||
|
||||
public class MediaPosterRequest : MediaPoster
|
||||
{
|
||||
public MediaPosterImage CreateMediaPosterImage() => new MediaPosterImage
|
||||
{
|
||||
Image = Image,
|
||||
MimeType = MimeType,
|
||||
};
|
||||
|
||||
public void UpdateMediaPosterImage(MediaPosterImage item)
|
||||
{
|
||||
item.Image = Image;
|
||||
item.MimeType = MimeType;
|
||||
item.UploadDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using WatchIt.Database.Model.Media;
|
||||
|
||||
namespace WatchIt.Common.Model.Media;
|
||||
|
||||
public class MediaPosterResponse : MediaPoster
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[JsonPropertyName("upload_date")]
|
||||
public DateTime UploadDate { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region CONSTRUCTORS
|
||||
|
||||
[JsonConstructor]
|
||||
public MediaPosterResponse() {}
|
||||
|
||||
[SetsRequiredMembers]
|
||||
public MediaPosterResponse(MediaPosterImage mediaPhotoImage)
|
||||
{
|
||||
Id = mediaPhotoImage.Id;
|
||||
Image = mediaPhotoImage.Image;
|
||||
MimeType = mediaPhotoImage.MimeType;
|
||||
UploadDate = mediaPhotoImage.UploadDate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -7,7 +7,7 @@ public class HttpResponse
|
||||
{
|
||||
#region FIELDS
|
||||
|
||||
private HttpResponseMessage _message;
|
||||
private readonly HttpResponseMessage _message;
|
||||
|
||||
private Action? _2XXAction;
|
||||
private Action? _400Action;
|
||||
@@ -32,37 +32,37 @@ public class HttpResponse
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
public HttpResponse RegisterActionFor2XXSuccess(Action action)
|
||||
public HttpResponse RegisterActionFor2XXSuccess(Action? action)
|
||||
{
|
||||
_2XXAction = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse RegisterActionFor2XXSuccess<T>(Action<T> action)
|
||||
public HttpResponse RegisterActionFor2XXSuccess<T>(Action<T>? action)
|
||||
{
|
||||
_2XXAction = () => Invoke(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse RegisterActionFor400BadRequest(Action<IDictionary<string, string[]>> action)
|
||||
public HttpResponse RegisterActionFor400BadRequest(Action<IDictionary<string, string[]>>? action)
|
||||
{
|
||||
_400Action = () => Invoke(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse RegisterActionFor401Unauthorized(Action action)
|
||||
public HttpResponse RegisterActionFor401Unauthorized(Action? action)
|
||||
{
|
||||
_401Action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse RegisterActionFor403Forbidden(Action action)
|
||||
public HttpResponse RegisterActionFor403Forbidden(Action? action)
|
||||
{
|
||||
_403Action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpResponse RegisterActionFor404NotFound(Action action)
|
||||
public HttpResponse RegisterActionFor404NotFound(Action? action)
|
||||
{
|
||||
_404Action = action;
|
||||
return this;
|
||||
@@ -86,21 +86,21 @@ public class HttpResponse
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private async void Invoke<T>(Action<T> action)
|
||||
private async void Invoke<T>(Action<T>? action)
|
||||
{
|
||||
Stream streamData = await _message.Content.ReadAsStreamAsync();
|
||||
T? data = await JsonSerializer.DeserializeAsync<T>(streamData);
|
||||
action.Invoke(data!);
|
||||
action?.Invoke(data!);
|
||||
}
|
||||
|
||||
private async void Invoke(Action<IDictionary<string, string[]>> action)
|
||||
private async void Invoke(Action<IDictionary<string, string[]>>? action)
|
||||
{
|
||||
Stream streamData = await _message.Content.ReadAsStreamAsync();
|
||||
ValidationProblemDetails? data = await JsonSerializer.DeserializeAsync<ValidationProblemDetails>(streamData, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
});
|
||||
action.Invoke(data!.Errors);
|
||||
action?.Invoke(data!.Errors);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -7,7 +7,7 @@ public class MediaPosterImage
|
||||
public Guid Id { get; set; }
|
||||
public required byte[] Image { get; set; }
|
||||
public required string MimeType { get; set; }
|
||||
public required DateTime UploadDate { get; set; }
|
||||
public DateTime UploadDate { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using WatchIt.Common.Model.Genres;
|
||||
@@ -18,7 +19,7 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
public async Task<ActionResult> GetGenres([FromRoute]long id) => await mediaControllerService.GetGenres(id);
|
||||
|
||||
[HttpPost("{id}/genres/{genre_id}")]
|
||||
[Authorize]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||
@@ -26,7 +27,7 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
public async Task<ActionResult> PostGenre([FromRoute]long id, [FromRoute(Name = "genre_id")]short genreId) => await mediaControllerService.PostGenre(id, genreId);
|
||||
|
||||
[HttpDelete("{id}/genres/{genre_id}")]
|
||||
[Authorize]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||
@@ -39,6 +40,28 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GetMediaRandomBackgroundPhoto([FromRoute]long id) => await mediaControllerService.GetMediaRandomBackgroundPhoto(id);
|
||||
|
||||
[HttpGet("{id}/poster")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(MediaPosterResponse), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> GetPoster([FromRoute] long id) => await mediaControllerService.GetPoster(id);
|
||||
|
||||
[HttpPut("{id}/poster")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||
public async Task<ActionResult> PutPoster([FromRoute]long id, [FromBody]MediaPosterRequest body) => await mediaControllerService.PutPoster(id, body);
|
||||
|
||||
[HttpDelete("{id}/poster")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||
public async Task<ActionResult> DeletePoster([FromRoute]long id) => await mediaControllerService.DeletePoster(id);
|
||||
|
||||
[HttpGet("photos/{photo_id}")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status200OK)]
|
||||
@@ -57,7 +80,7 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
public async Task<ActionResult> GetRandomBackgroundPhoto() => await mediaControllerService.GetRandomBackgroundPhoto();
|
||||
|
||||
[HttpPost("photos")]
|
||||
[Authorize]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
@@ -65,7 +88,7 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
public async Task<ActionResult> PostPhoto([FromBody]MediaPhotoRequest body) => await mediaControllerService.PostPhoto(body);
|
||||
|
||||
[HttpPut("photos/{photo_id}")]
|
||||
[Authorize]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
@@ -74,7 +97,7 @@ public class MediaController(IMediaControllerService mediaControllerService)
|
||||
public async Task<ActionResult> PutPhoto([FromRoute(Name = "photo_id")]Guid photoId, [FromBody]MediaPhotoRequest body) => await mediaControllerService.PutPhoto(photoId, body);
|
||||
|
||||
[HttpDelete("photos/{photo_id}")]
|
||||
[Authorize]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||
|
||||
@@ -12,6 +12,9 @@ public interface IMediaControllerService
|
||||
Task<RequestResult> GetPhotos(MediaPhotoQueryParameters query);
|
||||
Task<RequestResult> GetRandomBackgroundPhoto();
|
||||
Task<RequestResult> GetMediaRandomBackgroundPhoto(long id);
|
||||
Task<RequestResult> GetPoster(long id);
|
||||
Task<RequestResult> PutPoster(long id, MediaPosterRequest data);
|
||||
Task<RequestResult> DeletePoster(long id);
|
||||
Task<RequestResult> PostPhoto(MediaPhotoRequest data);
|
||||
Task<RequestResult> PutPhoto(Guid photoId, MediaPhotoRequest data);
|
||||
Task<RequestResult> DeletePhoto(Guid photoId);
|
||||
|
||||
@@ -114,6 +114,76 @@ public class MediaControllerService(DatabaseContext database, IUserService userS
|
||||
return Task.FromResult<RequestResult>(RequestResult.Ok(data));
|
||||
}
|
||||
|
||||
public async Task<RequestResult> GetPoster(long id)
|
||||
{
|
||||
Database.Model.Media.Media? media = await database.Media.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (media is null)
|
||||
{
|
||||
return RequestResult.BadRequest();
|
||||
}
|
||||
|
||||
MediaPosterImage? poster = media.MediaPosterImage;
|
||||
if (poster is null)
|
||||
{
|
||||
return RequestResult.NotFound();
|
||||
}
|
||||
|
||||
MediaPosterResponse data = new MediaPosterResponse(poster);
|
||||
return RequestResult.Ok(data);
|
||||
}
|
||||
|
||||
public async Task<RequestResult> PutPoster(long id, MediaPosterRequest data)
|
||||
{
|
||||
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||
if (!validator.IsValid)
|
||||
{
|
||||
return RequestResult.Forbidden();
|
||||
}
|
||||
|
||||
Database.Model.Media.Media? media = await database.Media.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (media is null)
|
||||
{
|
||||
return RequestResult.BadRequest();
|
||||
}
|
||||
|
||||
if (media.MediaPosterImage is null)
|
||||
{
|
||||
MediaPosterImage image = data.CreateMediaPosterImage();
|
||||
await database.MediaPosterImages.AddAsync(image);
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
media.MediaPosterImageId = image.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.UpdateMediaPosterImage(media.MediaPosterImage);
|
||||
}
|
||||
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
return RequestResult.Ok();
|
||||
}
|
||||
|
||||
public async Task<RequestResult> DeletePoster(long id)
|
||||
{
|
||||
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||
if (!validator.IsValid)
|
||||
{
|
||||
return RequestResult.Forbidden();
|
||||
}
|
||||
|
||||
Database.Model.Media.Media? media = await database.Media.FirstOrDefaultAsync(x => x.Id == id);
|
||||
|
||||
if (media?.MediaPosterImage != null)
|
||||
{
|
||||
database.MediaPosterImages.Attach(media.MediaPosterImage);
|
||||
database.MediaPosterImages.Remove(media.MediaPosterImage);
|
||||
await database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return RequestResult.NoContent();
|
||||
}
|
||||
|
||||
public async Task<RequestResult> PostPhoto(MediaPhotoRequest data)
|
||||
{
|
||||
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using FluentValidation;
|
||||
using WatchIt.Common.Model.Media;
|
||||
using WatchIt.Database;
|
||||
|
||||
namespace WatchIt.WebAPI.Validators.Media;
|
||||
|
||||
public class MediaPosterRequestValidator : AbstractValidator<MediaPosterRequest>
|
||||
{
|
||||
public MediaPosterRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Image).NotEmpty();
|
||||
RuleFor(x => x.MimeType).Matches(@"\w+/.+").WithMessage("Incorrect mimetype");
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,10 @@ using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Website.Services.Utility.Tokens;
|
||||
using WatchIt.Website.Services.WebAPI.Accounts;
|
||||
|
||||
namespace WatchIt.Website.Services.Utility.Tokens;
|
||||
namespace WatchIt.Website.Services.Utility.Authentication;
|
||||
|
||||
public class JWTAuthenticationStateProvider : AuthenticationStateProvider
|
||||
{
|
||||
@@ -111,13 +112,20 @@ public class JWTAuthenticationStateProvider : AuthenticationStateProvider
|
||||
|
||||
private async Task<string?> Refresh(string refreshToken)
|
||||
{
|
||||
AuthenticateResponse response = null;
|
||||
AuthenticateResponse? response = null;
|
||||
|
||||
await _accountsService.AuthenticateRefresh((data) => response = data);
|
||||
|
||||
if (response is not null)
|
||||
{
|
||||
await _tokensService.SaveAuthenticationData(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _tokensService.RemoveAuthenticationData();
|
||||
}
|
||||
|
||||
return response.AccessToken;
|
||||
return response?.AccessToken;
|
||||
}
|
||||
|
||||
private static IEnumerable<Claim> GetClaimsFromToken(string token)
|
||||
|
||||
@@ -7,6 +7,9 @@ public class Media
|
||||
public string PostGenre { get; set; }
|
||||
public string DeleteGenre { get; set; }
|
||||
public string GetPhotoMediaRandomBackground { get; set; }
|
||||
public string GetPoster { get; set; }
|
||||
public string PutPoster { get; set; }
|
||||
public string DeletePoster { get; set; }
|
||||
public string GetPhoto { get; set; }
|
||||
public string GetPhotos { get; set; }
|
||||
public string GetPhotoRandomBackground { get; set; }
|
||||
|
||||
@@ -8,4 +8,7 @@ public interface IMediaWebAPIService
|
||||
Task GetGenres(long mediaId, Action<IEnumerable<GenreResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
Task PostGenre(long mediaId, long genreId, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null, Action? notFoundAction = null);
|
||||
Task GetPhotoRandomBackground(Action<MediaPhotoResponse>? successAction = null, Action? notFoundAction = null);
|
||||
Task GetPoster(long mediaId, Action<MediaPosterResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? notFoundAction = null);
|
||||
Task PutPoster(long mediaId, MediaPosterRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null);
|
||||
Task DeletePoster(long mediaId, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null);
|
||||
}
|
||||
@@ -49,6 +49,49 @@ public class MediaWebAPIService(IHttpClientService httpClientService, IConfigura
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task GetPoster(long mediaId, Action<MediaPosterResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? notFoundAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Media.GetPoster, mediaId);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor400BadRequest(badRequestAction)
|
||||
.RegisterActionFor404NotFound(notFoundAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task PutPoster(long mediaId, MediaPosterRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Media.PutPoster, mediaId);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Get, url)
|
||||
{
|
||||
Body = data
|
||||
};
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor400BadRequest(badRequestAction)
|
||||
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||
.RegisterActionFor403Forbidden(forbiddenAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task DeletePoster(long mediaId, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Media.DeletePoster, mediaId);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Delete, url);
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||
.RegisterActionFor403Forbidden(forbiddenAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
"PostGenre": "/{0}/genres/{1}",
|
||||
"DeleteGenre": "/{0}/genres/{1}",
|
||||
"GetPhotoMediaRandomBackground": "/{0}/photos/random_background",
|
||||
"GetPoster": "/{0}/poster",
|
||||
"PutPoster": "/{0}/poster",
|
||||
"DeletePoster": "/{0}/poster",
|
||||
"GetPhoto": "/photos/{0}",
|
||||
"GetPhotos": "/photos",
|
||||
"GetPhotoRandomBackground": "/photos/random_background",
|
||||
|
||||
Reference in New Issue
Block a user