basics
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WatchIt.Common.Query;
|
||||||
|
|
||||||
namespace WatchIt.Common.Model.Genres;
|
namespace WatchIt.Common.Model.Genres;
|
||||||
|
|
||||||
|
|||||||
18
WatchIt.Common/WatchIt.Common.Model/Media/MediaPhoto.cs
Normal file
18
WatchIt.Common/WatchIt.Common.Model/Media/MediaPhoto.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhoto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("media_id")]
|
||||||
|
public required long MediaId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("image")]
|
||||||
|
public required byte[] Image { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("mime_type")]
|
||||||
|
public required string MimeType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("background")]
|
||||||
|
public MediaPhotoBackground? Background { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoBackground
|
||||||
|
{
|
||||||
|
[JsonPropertyName("is_universal_background")]
|
||||||
|
public required bool IsUniversalBackground { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("first_gradient_color")]
|
||||||
|
public required byte[] FirstGradientColor { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("second_gradient_color")]
|
||||||
|
public required byte[] SecondGradientColor { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WatchIt.Common.Query;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoQueryParameters : QueryParameters<MediaPhotoResponse>
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
[FromQuery(Name = "mime_type")]
|
||||||
|
public string? MimeType { get; set; }
|
||||||
|
|
||||||
|
[FromQuery(Name = "is_background")]
|
||||||
|
public bool? IsBackground { get; set; }
|
||||||
|
|
||||||
|
[FromQuery(Name = "is_universal_background")]
|
||||||
|
public bool? IsUniversalBackground { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public override bool IsMeetingConditions(MediaPhotoResponse item) =>
|
||||||
|
(
|
||||||
|
TestString(item.MimeType, MimeType)
|
||||||
|
&&
|
||||||
|
TestBoolean(item.Background is not null, IsBackground)
|
||||||
|
&&
|
||||||
|
TestBoolean(item.Background!.IsUniversalBackground, IsUniversalBackground)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using WatchIt.Database.Model.Media;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoRequest : MediaPhoto
|
||||||
|
{
|
||||||
|
public MediaPhotoImage CreateMediaPhotoImage() => new MediaPhotoImage
|
||||||
|
{
|
||||||
|
MediaId = MediaId,
|
||||||
|
Image = Image,
|
||||||
|
MimeType = MimeType
|
||||||
|
};
|
||||||
|
|
||||||
|
public MediaPhotoImageBackground? CreateMediaPhotoImageBackground(Guid mediaPhotoImageId) => Background is null ? null : new MediaPhotoImageBackground
|
||||||
|
{
|
||||||
|
Id = mediaPhotoImageId,
|
||||||
|
IsUniversalBackground = Background.IsUniversalBackground,
|
||||||
|
FirstGradientColor = Background.FirstGradientColor,
|
||||||
|
SecondGradientColor = Background.SecondGradientColor
|
||||||
|
};
|
||||||
|
|
||||||
|
public void UpdateMediaPhotoImage(MediaPhotoImage item)
|
||||||
|
{
|
||||||
|
item.MediaId = MediaId;
|
||||||
|
item.Image = Image;
|
||||||
|
item.MimeType = MimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMediaPhotoImageBackground(MediaPhotoImageBackground item)
|
||||||
|
{
|
||||||
|
if (Background is not null)
|
||||||
|
{
|
||||||
|
item.IsUniversalBackground = Background.IsUniversalBackground;
|
||||||
|
item.FirstGradientColor = Background.FirstGradientColor;
|
||||||
|
item.SecondGradientColor = Background.SecondGradientColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using WatchIt.Database.Model.Media;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoResponse : MediaPhoto
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("upload_date")]
|
||||||
|
public DateTime UploadDate { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region CONSTRUCTORS
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public MediaPhotoResponse() {}
|
||||||
|
|
||||||
|
[SetsRequiredMembers]
|
||||||
|
public MediaPhotoResponse(MediaPhotoImage mediaPhotoImage)
|
||||||
|
{
|
||||||
|
Id = mediaPhotoImage.Id;
|
||||||
|
MediaId = mediaPhotoImage.MediaId;
|
||||||
|
Image = mediaPhotoImage.Image;
|
||||||
|
MimeType = mediaPhotoImage.MimeType;
|
||||||
|
UploadDate = mediaPhotoImage.UploadDate;
|
||||||
|
|
||||||
|
if (mediaPhotoImage.MediaPhotoImageBackground is not null)
|
||||||
|
{
|
||||||
|
Background = new MediaPhotoBackground
|
||||||
|
{
|
||||||
|
IsUniversalBackground = mediaPhotoImage.MediaPhotoImageBackground.IsUniversalBackground,
|
||||||
|
FirstGradientColor = mediaPhotoImage.MediaPhotoImageBackground.FirstGradientColor,
|
||||||
|
SecondGradientColor = mediaPhotoImage.MediaPhotoImageBackground.SecondGradientColor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WatchIt.Common.Query;
|
||||||
|
|
||||||
namespace WatchIt.Common.Model.Movies;
|
namespace WatchIt.Common.Model.Movies;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ public class MovieRequest : Movie
|
|||||||
{
|
{
|
||||||
#region PUBLIC METHODS
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
public Media CreateMedia() => new Media
|
public Database.Model.Media.Media CreateMedia() => new Database.Model.Media.Media
|
||||||
{
|
{
|
||||||
Title = Title,
|
Title = Title,
|
||||||
OriginalTitle = OriginalTitle,
|
OriginalTitle = OriginalTitle,
|
||||||
@@ -21,7 +21,7 @@ public class MovieRequest : Movie
|
|||||||
Budget = Budget,
|
Budget = Budget,
|
||||||
};
|
};
|
||||||
|
|
||||||
public void UpdateMedia(Media media)
|
public void UpdateMedia(Database.Model.Media.Media media)
|
||||||
{
|
{
|
||||||
media.Title = Title;
|
media.Title = Title;
|
||||||
media.OriginalTitle = OriginalTitle;
|
media.OriginalTitle = OriginalTitle;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\WatchIt.Database\WatchIt.Database.Model\WatchIt.Database.Model\WatchIt.Database.Model.csproj" />
|
<ProjectReference Include="..\..\WatchIt.Database\WatchIt.Database.Model\WatchIt.Database.Model\WatchIt.Database.Model.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Common.Query\WatchIt.Common.Query.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace WatchIt.Common.Model;
|
namespace WatchIt.Common.Query;
|
||||||
|
|
||||||
public abstract class QueryParameters<T> where T : class
|
public abstract class QueryParameters
|
||||||
{
|
{
|
||||||
#region PROPERTIES
|
#region PROPERTIES
|
||||||
|
|
||||||
@@ -22,9 +23,93 @@ public abstract class QueryParameters<T> where T : class
|
|||||||
public int? After { get; set; }
|
public int? After { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
List<string> queries = new List<string>();
|
||||||
|
PropertyInfo[] properties = this.GetType().GetProperties();
|
||||||
|
foreach (PropertyInfo property in properties)
|
||||||
|
{
|
||||||
|
object? value = property.GetValue(this);
|
||||||
|
FromQueryAttribute? attribute = property.GetCustomAttributes<FromQueryAttribute>(true).FirstOrDefault();
|
||||||
|
if (value is not null && attribute is not null)
|
||||||
|
{
|
||||||
|
string query = $"{attribute.Name}={value}";
|
||||||
|
queries.Add(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"?{string.Join('&', queries)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
protected static bool TestBoolean(bool property, bool? query) =>
|
||||||
|
(
|
||||||
|
query is null
|
||||||
|
||
|
||||||
|
property == query
|
||||||
|
);
|
||||||
|
|
||||||
|
protected static bool TestString(string? property, string? regexQuery) =>
|
||||||
|
(
|
||||||
|
string.IsNullOrEmpty(regexQuery)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
!string.IsNullOrEmpty(property)
|
||||||
|
&&
|
||||||
|
new Regex(regexQuery).IsMatch(property)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
protected static bool TestComparable(IComparable? property, IComparable? exact, IComparable? from, IComparable? to) =>
|
||||||
|
(
|
||||||
|
(
|
||||||
|
exact is null
|
||||||
|
||
|
||||||
|
(
|
||||||
|
property is not null
|
||||||
|
&&
|
||||||
|
property.CompareTo(exact) == 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
from is null
|
||||||
|
||
|
||||||
|
(
|
||||||
|
property is not null
|
||||||
|
&&
|
||||||
|
property.CompareTo(from) > 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
(
|
||||||
|
to is null
|
||||||
|
||
|
||||||
|
(
|
||||||
|
property is not null
|
||||||
|
&&
|
||||||
|
property.CompareTo(to) < 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class QueryParameters<T> : QueryParameters where T : class
|
||||||
|
{
|
||||||
#region PUBLIC METHODS
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
public abstract bool IsMeetingConditions(T item);
|
public abstract bool IsMeetingConditions(T item);
|
||||||
@@ -65,54 +150,4 @@ public abstract class QueryParameters<T> where T : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region PRIVATE METHODS
|
|
||||||
|
|
||||||
protected bool TestString(string? property, string? regexQuery) =>
|
|
||||||
(
|
|
||||||
string.IsNullOrEmpty(regexQuery)
|
|
||||||
||
|
|
||||||
(
|
|
||||||
!string.IsNullOrEmpty(property)
|
|
||||||
&&
|
|
||||||
new Regex(regexQuery).IsMatch(property)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
protected bool TestComparable(IComparable? property, IComparable? exact, IComparable? from, IComparable? to) =>
|
|
||||||
(
|
|
||||||
(
|
|
||||||
exact is null
|
|
||||||
||
|
|
||||||
(
|
|
||||||
property is not null
|
|
||||||
&&
|
|
||||||
property.CompareTo(exact) == 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
&&
|
|
||||||
(
|
|
||||||
from is null
|
|
||||||
||
|
|
||||||
(
|
|
||||||
property is not null
|
|
||||||
&&
|
|
||||||
property.CompareTo(from) > 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
&&
|
|
||||||
(
|
|
||||||
to is null
|
|
||||||
||
|
|
||||||
(
|
|
||||||
property is not null
|
|
||||||
&&
|
|
||||||
property.CompareTo(to) < 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Services.HttpClient;
|
||||||
|
|
||||||
|
public class HttpClientService(System.Net.Http.HttpClient httpClient) : IHttpClientService
|
||||||
|
{
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public async Task<HttpResponse> SendRequestAsync(HttpRequest request)
|
||||||
|
{
|
||||||
|
HttpMethod method = request.MethodType switch
|
||||||
|
{
|
||||||
|
HttpMethodType.Get => HttpMethod.Get,
|
||||||
|
HttpMethodType.Post => HttpMethod.Post,
|
||||||
|
HttpMethodType.Put => HttpMethod.Put,
|
||||||
|
HttpMethodType.Patch => HttpMethod.Patch,
|
||||||
|
HttpMethodType.Delete => HttpMethod.Delete,
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequestMessage httpRequest = new HttpRequestMessage(method, request.FullUrl);
|
||||||
|
|
||||||
|
if (request.Body is not null)
|
||||||
|
{
|
||||||
|
string json = JsonSerializer.Serialize(request.Body);
|
||||||
|
HttpContent content = new StringContent(json);
|
||||||
|
content.Headers.ContentType!.MediaType = "application/json";
|
||||||
|
httpRequest.Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, string> header in request.Headers)
|
||||||
|
{
|
||||||
|
httpRequest.Headers.Add(header.Key, header.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponseMessage response = await httpClient.SendAsync(httpRequest);
|
||||||
|
|
||||||
|
return new HttpResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace WatchIt.Common.Services.HttpClient;
|
||||||
|
|
||||||
|
public enum HttpMethodType
|
||||||
|
{
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Patch,
|
||||||
|
Delete
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using WatchIt.Common.Query;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Services.HttpClient;
|
||||||
|
|
||||||
|
public class HttpRequest
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
public required HttpMethodType MethodType { get; set; }
|
||||||
|
public required string Url { get; set; }
|
||||||
|
public QueryParameters? Query { get; set; }
|
||||||
|
public object? Body { get; set; }
|
||||||
|
public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
public string FullUrl => $"{Url}{(Query is not null ? Query.ToString() : string.Empty)}";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region CONSTRUCTORS
|
||||||
|
|
||||||
|
[SetsRequiredMembers]
|
||||||
|
public HttpRequest(HttpMethodType methodType, string url)
|
||||||
|
{
|
||||||
|
MethodType = methodType;
|
||||||
|
Url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Services.HttpClient;
|
||||||
|
|
||||||
|
public class HttpResponse
|
||||||
|
{
|
||||||
|
#region FIELDS
|
||||||
|
|
||||||
|
private HttpResponseMessage _message;
|
||||||
|
|
||||||
|
private Action? _2XXAction;
|
||||||
|
private Action? _400Action;
|
||||||
|
private Action? _401Action;
|
||||||
|
private Action? _403Action;
|
||||||
|
private Action? _404Action;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region CONSTRUCTORS
|
||||||
|
|
||||||
|
internal HttpResponse(HttpResponseMessage message)
|
||||||
|
{
|
||||||
|
_message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor2XXSuccess(Action action)
|
||||||
|
{
|
||||||
|
_2XXAction = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor2XXSuccess<T>(Action<T> action)
|
||||||
|
{
|
||||||
|
_2XXAction = () => Invoke(action);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor400BadRequest(Action<IDictionary<string, string[]>> action)
|
||||||
|
{
|
||||||
|
_400Action = () => Invoke(action);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor401Unauthorized(Action action)
|
||||||
|
{
|
||||||
|
_401Action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor403Forbidden(Action action)
|
||||||
|
{
|
||||||
|
_403Action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse RegisterActionFor404NotFound(Action action)
|
||||||
|
{
|
||||||
|
_404Action = action;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExecuteAction()
|
||||||
|
{
|
||||||
|
switch ((int)_message.StatusCode)
|
||||||
|
{
|
||||||
|
case >= 200 and <= 299: _2XXAction?.Invoke(); break;
|
||||||
|
case 400: _400Action?.Invoke(); break;
|
||||||
|
case 401: _401Action?.Invoke(); break;
|
||||||
|
case 403: _403Action?.Invoke(); break;
|
||||||
|
case 404: _404Action?.Invoke(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
private async void Invoke<T>(Action<T> action)
|
||||||
|
{
|
||||||
|
Stream streamData = await _message.Content.ReadAsStreamAsync();
|
||||||
|
T? data = await JsonSerializer.DeserializeAsync<T>(streamData);
|
||||||
|
action.Invoke(data!);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace WatchIt.Common.Services.HttpClient;
|
||||||
|
|
||||||
|
public interface IHttpClientService
|
||||||
|
{
|
||||||
|
Task<HttpResponse> SendRequestAsync(HttpRequest request);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\WatchIt.Common.Query\WatchIt.Common.Query.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
using WatchIt.Database.Model.Media;
|
||||||
|
|
||||||
|
namespace WatchIt.Database.Model.Configuration.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoImageBackgroundConfiguration : IEntityTypeConfiguration<MediaPhotoImageBackground>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<MediaPhotoImageBackground> builder)
|
||||||
|
{
|
||||||
|
builder.HasKey(x => x.Id);
|
||||||
|
builder.HasIndex(x => x.Id)
|
||||||
|
.IsUnique();
|
||||||
|
builder.Property(x => x.Id)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(x => x.IsUniversalBackground)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
builder.Property(x => x.FirstGradientColor)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3);
|
||||||
|
|
||||||
|
builder.Property(x => x.SecondGradientColor)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,12 +33,8 @@ public class MediaPhotoImageConfiguration : IEntityTypeConfiguration<MediaPhotoI
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasDefaultValueSql("now()");
|
.HasDefaultValueSql("now()");
|
||||||
|
|
||||||
builder.Property(x => x.IsMediaBackground)
|
builder.HasOne(x => x.MediaPhotoImageBackground)
|
||||||
.IsRequired()
|
.WithOne(x => x.MediaPhotoImage)
|
||||||
.HasDefaultValue(false);
|
.HasForeignKey<MediaPhotoImageBackground>();
|
||||||
|
|
||||||
builder.Property(x => x.IsUniversalBackground)
|
|
||||||
.IsRequired()
|
|
||||||
.HasDefaultValue(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ public class MediaPhotoImage
|
|||||||
public required byte[] Image { get; set; }
|
public required byte[] Image { get; set; }
|
||||||
public required string MimeType { get; set; }
|
public required string MimeType { get; set; }
|
||||||
public DateTime UploadDate { get; set; }
|
public DateTime UploadDate { get; set; }
|
||||||
public bool IsMediaBackground { get; set; }
|
|
||||||
public bool IsUniversalBackground { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -19,6 +17,7 @@ public class MediaPhotoImage
|
|||||||
#region NAVIGATION
|
#region NAVIGATION
|
||||||
|
|
||||||
public virtual Media Media { get; set; } = null!;
|
public virtual Media Media { get; set; } = null!;
|
||||||
|
public virtual MediaPhotoImageBackground? MediaPhotoImageBackground { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace WatchIt.Database.Model.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoImageBackground
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
public required bool IsUniversalBackground { get; set; }
|
||||||
|
public required byte[] FirstGradientColor { get; set; }
|
||||||
|
public required byte[] SecondGradientColor { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region NAVIGATION
|
||||||
|
|
||||||
|
public virtual MediaPhotoImage MediaPhotoImage { get; set; } = null!;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -51,6 +51,7 @@ public class DatabaseContext : DbContext
|
|||||||
public virtual DbSet<MediaSeriesEpisode> MediaSeriesEpisodes { get; set; }
|
public virtual DbSet<MediaSeriesEpisode> MediaSeriesEpisodes { get; set; }
|
||||||
public virtual DbSet<MediaPosterImage> MediaPosterImages { get; set; }
|
public virtual DbSet<MediaPosterImage> MediaPosterImages { get; set; }
|
||||||
public virtual DbSet<MediaPhotoImage> MediaPhotoImages { get; set; }
|
public virtual DbSet<MediaPhotoImage> MediaPhotoImages { get; set; }
|
||||||
|
public virtual DbSet<MediaPhotoImageBackground> MediaPhotoImageBackgrounds { get; set; }
|
||||||
public virtual DbSet<MediaGenre> MediaGenres { get; set; }
|
public virtual DbSet<MediaGenre> MediaGenres { get; set; }
|
||||||
public virtual DbSet<MediaProductionCountry> MediaProductionCountries { get; set; }
|
public virtual DbSet<MediaProductionCountry> MediaProductionCountries { get; set; }
|
||||||
|
|
||||||
|
|||||||
1397
WatchIt.Database/WatchIt.Database/Migrations/20240603125708_Initial.Designer.cs
generated
Normal file
1397
WatchIt.Database/WatchIt.Database/Migrations/20240603125708_Initial.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace WatchIt.Database.Migrations
|
namespace WatchIt.Database.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class _0001_Initial : Migration
|
public partial class Initial : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
@@ -62,13 +62,27 @@ namespace WatchIt.Database.Migrations
|
|||||||
Id = table.Column<short>(type: "smallint", nullable: false)
|
Id = table.Column<short>(type: "smallint", nullable: false)
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||||
Description = table.Column<string>(type: "text", nullable: true)
|
Description = table.Column<string>(type: "character varying(1000)", maxLength: 1000, nullable: true)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_Genres", x => x.Id);
|
table.PrimaryKey("PK_Genres", x => x.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "MediaPhotoImageBackgrounds",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
IsUniversalBackground = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
||||||
|
FirstGradientColor = table.Column<byte[]>(type: "bytea", maxLength: 3, nullable: false),
|
||||||
|
SecondGradientColor = table.Column<byte[]>(type: "bytea", maxLength: 3, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_MediaPhotoImageBackgrounds", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "MediaPosterImages",
|
name: "MediaPosterImages",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
@@ -226,12 +240,22 @@ namespace WatchIt.Database.Migrations
|
|||||||
Image = table.Column<byte[]>(type: "bytea", maxLength: -1, nullable: false),
|
Image = table.Column<byte[]>(type: "bytea", maxLength: -1, nullable: false),
|
||||||
MimeType = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
MimeType = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
|
||||||
UploadDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
UploadDate = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
||||||
IsMediaBackground = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false),
|
MediaPhotoImageBackgroundId = table.Column<Guid>(type: "uuid", nullable: true)
|
||||||
IsUniversalBackground = table.Column<bool>(type: "boolean", nullable: false, defaultValue: false)
|
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_MediaPhotoImages", x => x.Id);
|
table.PrimaryKey("PK_MediaPhotoImages", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_Id",
|
||||||
|
column: x => x.Id,
|
||||||
|
principalTable: "MediaPhotoImageBackgrounds",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_MediaPhotoImage~",
|
||||||
|
column: x => x.MediaPhotoImageBackgroundId,
|
||||||
|
principalTable: "MediaPhotoImageBackgrounds",
|
||||||
|
principalColumn: "Id");
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_MediaPhotoImages_Media_MediaId",
|
name: "FK_MediaPhotoImages_Media_MediaId",
|
||||||
column: x => x.MediaId,
|
column: x => x.MediaId,
|
||||||
@@ -241,7 +265,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
});
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "MediaProductionCountrys",
|
name: "MediaProductionCountries",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
{
|
{
|
||||||
MediaId = table.Column<long>(type: "bigint", nullable: false),
|
MediaId = table.Column<long>(type: "bigint", nullable: false),
|
||||||
@@ -249,15 +273,15 @@ namespace WatchIt.Database.Migrations
|
|||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
table.PrimaryKey("PK_MediaProductionCountrys", x => new { x.CountryId, x.MediaId });
|
table.PrimaryKey("PK_MediaProductionCountries", x => new { x.CountryId, x.MediaId });
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_MediaProductionCountrys_Countries_CountryId",
|
name: "FK_MediaProductionCountries_Countries_CountryId",
|
||||||
column: x => x.CountryId,
|
column: x => x.CountryId,
|
||||||
principalTable: "Countries",
|
principalTable: "Countries",
|
||||||
principalColumn: "Id",
|
principalColumn: "Id",
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
table.ForeignKey(
|
table.ForeignKey(
|
||||||
name: "FK_MediaProductionCountrys_Media_MediaId",
|
name: "FK_MediaProductionCountries_Media_MediaId",
|
||||||
column: x => x.MediaId,
|
column: x => x.MediaId,
|
||||||
principalTable: "Media",
|
principalTable: "Media",
|
||||||
principalColumn: "Id",
|
principalColumn: "Id",
|
||||||
@@ -620,7 +644,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
migrationBuilder.InsertData(
|
migrationBuilder.InsertData(
|
||||||
table: "Accounts",
|
table: "Accounts",
|
||||||
columns: new[] { "Id", "BackgroundPictureId", "Description", "Email", "GenderId", "IsAdmin", "LeftSalt", "Password", "ProfilePictureId", "RightSalt", "Username" },
|
columns: new[] { "Id", "BackgroundPictureId", "Description", "Email", "GenderId", "IsAdmin", "LeftSalt", "Password", "ProfilePictureId", "RightSalt", "Username" },
|
||||||
values: new object[] { 1L, null, null, "root@watch.it", null, true, "qE]Q^g%tU\"6Uu^GfE:V:", new byte[] { 165, 250, 135, 31, 187, 161, 15, 246, 18, 232, 64, 25, 37, 173, 91, 111, 140, 177, 183, 84, 254, 177, 15, 235, 119, 219, 29, 169, 32, 108, 187, 121, 204, 51, 213, 28, 141, 89, 91, 226, 0, 23, 7, 91, 139, 230, 151, 104, 62, 91, 59, 6, 207, 26, 200, 141, 104, 5, 151, 201, 243, 163, 28, 248 }, null, "T7j)~.#%~ZtOFUZFK,K+", "root" });
|
values: new object[] { 1L, null, null, "root@watch.it", null, true, "Y&%]J>6Nc3&5~UUXnNxq", new byte[] { 68, 170, 8, 113, 134, 47, 98, 43, 96, 183, 126, 130, 204, 45, 4, 113, 81, 200, 244, 26, 54, 88, 161, 246, 84, 93, 159, 219, 12, 143, 128, 160, 198, 194, 47, 133, 216, 242, 158, 184, 43, 38, 134, 132, 175, 179, 42, 40, 0, 143, 111, 252, 156, 215, 17, 185, 12, 109, 119, 214, 211, 167, 32, 121 }, null, "MV1jo~o3Oa^;NWb\\Q)t_", "root" });
|
||||||
|
|
||||||
migrationBuilder.InsertData(
|
migrationBuilder.InsertData(
|
||||||
table: "Countries",
|
table: "Countries",
|
||||||
@@ -752,6 +776,12 @@ namespace WatchIt.Database.Migrations
|
|||||||
column: "Id",
|
column: "Id",
|
||||||
unique: true);
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MediaPhotoImageBackgrounds_Id",
|
||||||
|
table: "MediaPhotoImageBackgrounds",
|
||||||
|
column: "Id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_MediaPhotoImages_Id",
|
name: "IX_MediaPhotoImages_Id",
|
||||||
table: "MediaPhotoImages",
|
table: "MediaPhotoImages",
|
||||||
@@ -763,6 +793,11 @@ namespace WatchIt.Database.Migrations
|
|||||||
table: "MediaPhotoImages",
|
table: "MediaPhotoImages",
|
||||||
column: "MediaId");
|
column: "MediaId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MediaPhotoImages_MediaPhotoImageBackgroundId",
|
||||||
|
table: "MediaPhotoImages",
|
||||||
|
column: "MediaPhotoImageBackgroundId");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_MediaPosterImages_Id",
|
name: "IX_MediaPosterImages_Id",
|
||||||
table: "MediaPosterImages",
|
table: "MediaPosterImages",
|
||||||
@@ -770,8 +805,8 @@ namespace WatchIt.Database.Migrations
|
|||||||
unique: true);
|
unique: true);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_MediaProductionCountrys_MediaId",
|
name: "IX_MediaProductionCountries_MediaId",
|
||||||
table: "MediaProductionCountrys",
|
table: "MediaProductionCountries",
|
||||||
column: "MediaId");
|
column: "MediaId");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
@@ -995,7 +1030,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
name: "MediaMovies");
|
name: "MediaMovies");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "MediaProductionCountrys");
|
name: "MediaProductionCountries");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "RatingsMedia");
|
name: "RatingsMedia");
|
||||||
@@ -1057,6 +1092,9 @@ namespace WatchIt.Database.Migrations
|
|||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "MediaSeries");
|
name: "MediaSeries");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "MediaPhotoImageBackgrounds");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Genders");
|
name: "Genders");
|
||||||
|
|
||||||
@@ -12,15 +12,15 @@ using WatchIt.Database;
|
|||||||
namespace WatchIt.Database.Migrations
|
namespace WatchIt.Database.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(DatabaseContext))]
|
[DbContext(typeof(DatabaseContext))]
|
||||||
[Migration("20240418190404_0001_Initial")]
|
[Migration("20240603131015_Fix")]
|
||||||
partial class _0001_Initial
|
partial class Fix
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "8.0.4")
|
.HasAnnotation("ProductVersion", "8.0.5")
|
||||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||||
.HasAnnotation("Proxies:CheckEquality", false)
|
.HasAnnotation("Proxies:CheckEquality", false)
|
||||||
.HasAnnotation("Proxies:LazyLoading", true)
|
.HasAnnotation("Proxies:LazyLoading", true)
|
||||||
@@ -111,9 +111,9 @@ namespace WatchIt.Database.Migrations
|
|||||||
Email = "root@watch.it",
|
Email = "root@watch.it",
|
||||||
IsAdmin = true,
|
IsAdmin = true,
|
||||||
LastActive = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
LastActive = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||||
LeftSalt = "qE]Q^g%tU\"6Uu^GfE:V:",
|
LeftSalt = "@(0PF{b6Ot?HO*:yF5`L",
|
||||||
Password = new byte[] { 165, 250, 135, 31, 187, 161, 15, 246, 18, 232, 64, 25, 37, 173, 91, 111, 140, 177, 183, 84, 254, 177, 15, 235, 119, 219, 29, 169, 32, 108, 187, 121, 204, 51, 213, 28, 141, 89, 91, 226, 0, 23, 7, 91, 139, 230, 151, 104, 62, 91, 59, 6, 207, 26, 200, 141, 104, 5, 151, 201, 243, 163, 28, 248 },
|
Password = new byte[] { 254, 122, 19, 59, 187, 100, 174, 87, 55, 108, 14, 10, 123, 186, 129, 243, 145, 136, 152, 220, 72, 170, 196, 93, 54, 88, 192, 115, 128, 76, 133, 9, 181, 99, 181, 8, 102, 123, 197, 251, 85, 167, 146, 28, 116, 249, 118, 87, 146, 8, 194, 238, 127, 19, 33, 28, 14, 222, 218, 170, 74, 40, 223, 232 },
|
||||||
RightSalt = "T7j)~.#%~ZtOFUZFK,K+",
|
RightSalt = "=pt,3T0#CfC1[}Zfp{/u",
|
||||||
Username = "root"
|
Username = "root"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -253,7 +253,8 @@ namespace WatchIt.Database.Migrations
|
|||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<short>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<short>("Id"));
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("character varying(1000)");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
@@ -378,16 +379,6 @@ namespace WatchIt.Database.Migrations
|
|||||||
.HasMaxLength(-1)
|
.HasMaxLength(-1)
|
||||||
.HasColumnType("bytea");
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
b.Property<bool>("IsMediaBackground")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasDefaultValue(false);
|
|
||||||
|
|
||||||
b.Property<bool>("IsUniversalBackground")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasDefaultValue(false);
|
|
||||||
|
|
||||||
b.Property<long>("MediaId")
|
b.Property<long>("MediaId")
|
||||||
.HasColumnType("bigint");
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
@@ -411,6 +402,34 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.ToTable("MediaPhotoImages");
|
b.ToTable("MediaPhotoImages");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImageBackground", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<byte[]>("FirstGradientColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3)
|
||||||
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
|
b.Property<bool>("IsUniversalBackground")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<byte[]>("SecondGradientColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3)
|
||||||
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Id")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("MediaPhotoImageBackgrounds");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@@ -452,7 +471,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
|
|
||||||
b.HasIndex("MediaId");
|
b.HasIndex("MediaId");
|
||||||
|
|
||||||
b.ToTable("MediaProductionCountrys");
|
b.ToTable("MediaProductionCountries");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b =>
|
||||||
@@ -1016,6 +1035,17 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.Navigation("Media");
|
b.Navigation("Media");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImageBackground", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "MediaPhotoImage")
|
||||||
|
.WithOne("MediaPhotoImageBackground")
|
||||||
|
.HasForeignKey("WatchIt.Database.Model.Media.MediaPhotoImageBackground", "Id")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("MediaPhotoImage");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("WatchIt.Database.Model.Common.Country", "Country")
|
b.HasOne("WatchIt.Database.Model.Common.Country", "Country")
|
||||||
@@ -1302,6 +1332,11 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.Navigation("ViewCountsMedia");
|
b.Navigation("ViewCountsMedia");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("MediaPhotoImageBackground");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Media")
|
b.Navigation("Media")
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace WatchIt.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Fix : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_Id",
|
||||||
|
table: "MediaPhotoImages");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_MediaPhotoImage~",
|
||||||
|
table: "MediaPhotoImages");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_MediaPhotoImages_MediaPhotoImageBackgroundId",
|
||||||
|
table: "MediaPhotoImages");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MediaPhotoImageBackgroundId",
|
||||||
|
table: "MediaPhotoImages");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Accounts",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: 1L,
|
||||||
|
columns: new[] { "LeftSalt", "Password", "RightSalt" },
|
||||||
|
values: new object[] { "@(0PF{b6Ot?HO*:yF5`L", new byte[] { 254, 122, 19, 59, 187, 100, 174, 87, 55, 108, 14, 10, 123, 186, 129, 243, 145, 136, 152, 220, 72, 170, 196, 93, 54, 88, 192, 115, 128, 76, 133, 9, 181, 99, 181, 8, 102, 123, 197, 251, 85, 167, 146, 28, 116, 249, 118, 87, 146, 8, 194, 238, 127, 19, 33, 28, 14, 222, 218, 170, 74, 40, 223, 232 }, "=pt,3T0#CfC1[}Zfp{/u" });
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MediaPhotoImageBackgrounds_MediaPhotoImages_Id",
|
||||||
|
table: "MediaPhotoImageBackgrounds",
|
||||||
|
column: "Id",
|
||||||
|
principalTable: "MediaPhotoImages",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_MediaPhotoImageBackgrounds_MediaPhotoImages_Id",
|
||||||
|
table: "MediaPhotoImageBackgrounds");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "MediaPhotoImageBackgroundId",
|
||||||
|
table: "MediaPhotoImages",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "Accounts",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: 1L,
|
||||||
|
columns: new[] { "LeftSalt", "Password", "RightSalt" },
|
||||||
|
values: new object[] { "Y&%]J>6Nc3&5~UUXnNxq", new byte[] { 68, 170, 8, 113, 134, 47, 98, 43, 96, 183, 126, 130, 204, 45, 4, 113, 81, 200, 244, 26, 54, 88, 161, 246, 84, 93, 159, 219, 12, 143, 128, 160, 198, 194, 47, 133, 216, 242, 158, 184, 43, 38, 134, 132, 175, 179, 42, 40, 0, 143, 111, 252, 156, 215, 17, 185, 12, 109, 119, 214, 211, 167, 32, 121 }, "MV1jo~o3Oa^;NWb\\Q)t_" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_MediaPhotoImages_MediaPhotoImageBackgroundId",
|
||||||
|
table: "MediaPhotoImages",
|
||||||
|
column: "MediaPhotoImageBackgroundId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_Id",
|
||||||
|
table: "MediaPhotoImages",
|
||||||
|
column: "Id",
|
||||||
|
principalTable: "MediaPhotoImageBackgrounds",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_MediaPhotoImages_MediaPhotoImageBackgrounds_MediaPhotoImage~",
|
||||||
|
table: "MediaPhotoImages",
|
||||||
|
column: "MediaPhotoImageBackgroundId",
|
||||||
|
principalTable: "MediaPhotoImageBackgrounds",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "8.0.4")
|
.HasAnnotation("ProductVersion", "8.0.5")
|
||||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||||
.HasAnnotation("Proxies:CheckEquality", false)
|
.HasAnnotation("Proxies:CheckEquality", false)
|
||||||
.HasAnnotation("Proxies:LazyLoading", true)
|
.HasAnnotation("Proxies:LazyLoading", true)
|
||||||
@@ -108,9 +108,9 @@ namespace WatchIt.Database.Migrations
|
|||||||
Email = "root@watch.it",
|
Email = "root@watch.it",
|
||||||
IsAdmin = true,
|
IsAdmin = true,
|
||||||
LastActive = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
LastActive = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||||
LeftSalt = "qE]Q^g%tU\"6Uu^GfE:V:",
|
LeftSalt = "@(0PF{b6Ot?HO*:yF5`L",
|
||||||
Password = new byte[] { 165, 250, 135, 31, 187, 161, 15, 246, 18, 232, 64, 25, 37, 173, 91, 111, 140, 177, 183, 84, 254, 177, 15, 235, 119, 219, 29, 169, 32, 108, 187, 121, 204, 51, 213, 28, 141, 89, 91, 226, 0, 23, 7, 91, 139, 230, 151, 104, 62, 91, 59, 6, 207, 26, 200, 141, 104, 5, 151, 201, 243, 163, 28, 248 },
|
Password = new byte[] { 254, 122, 19, 59, 187, 100, 174, 87, 55, 108, 14, 10, 123, 186, 129, 243, 145, 136, 152, 220, 72, 170, 196, 93, 54, 88, 192, 115, 128, 76, 133, 9, 181, 99, 181, 8, 102, 123, 197, 251, 85, 167, 146, 28, 116, 249, 118, 87, 146, 8, 194, 238, 127, 19, 33, 28, 14, 222, 218, 170, 74, 40, 223, 232 },
|
||||||
RightSalt = "T7j)~.#%~ZtOFUZFK,K+",
|
RightSalt = "=pt,3T0#CfC1[}Zfp{/u",
|
||||||
Username = "root"
|
Username = "root"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -250,7 +250,8 @@ namespace WatchIt.Database.Migrations
|
|||||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<short>("Id"));
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<short>("Id"));
|
||||||
|
|
||||||
b.Property<string>("Description")
|
b.Property<string>("Description")
|
||||||
.HasColumnType("text");
|
.HasMaxLength(1000)
|
||||||
|
.HasColumnType("character varying(1000)");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
@@ -375,16 +376,6 @@ namespace WatchIt.Database.Migrations
|
|||||||
.HasMaxLength(-1)
|
.HasMaxLength(-1)
|
||||||
.HasColumnType("bytea");
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
b.Property<bool>("IsMediaBackground")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasDefaultValue(false);
|
|
||||||
|
|
||||||
b.Property<bool>("IsUniversalBackground")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasDefaultValue(false);
|
|
||||||
|
|
||||||
b.Property<long>("MediaId")
|
b.Property<long>("MediaId")
|
||||||
.HasColumnType("bigint");
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
@@ -408,6 +399,34 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.ToTable("MediaPhotoImages");
|
b.ToTable("MediaPhotoImages");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImageBackground", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<byte[]>("FirstGradientColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3)
|
||||||
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
|
b.Property<bool>("IsUniversalBackground")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<byte[]>("SecondGradientColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(3)
|
||||||
|
.HasColumnType("bytea");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Id")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("MediaPhotoImageBackgrounds");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
@@ -449,7 +468,7 @@ namespace WatchIt.Database.Migrations
|
|||||||
|
|
||||||
b.HasIndex("MediaId");
|
b.HasIndex("MediaId");
|
||||||
|
|
||||||
b.ToTable("MediaProductionCountrys");
|
b.ToTable("MediaProductionCountries");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaSeries", b =>
|
||||||
@@ -1013,6 +1032,17 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.Navigation("Media");
|
b.Navigation("Media");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImageBackground", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("WatchIt.Database.Model.Media.MediaPhotoImage", "MediaPhotoImage")
|
||||||
|
.WithOne("MediaPhotoImageBackground")
|
||||||
|
.HasForeignKey("WatchIt.Database.Model.Media.MediaPhotoImageBackground", "Id")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("MediaPhotoImage");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaProductionCountry", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("WatchIt.Database.Model.Common.Country", "Country")
|
b.HasOne("WatchIt.Database.Model.Common.Country", "Country")
|
||||||
@@ -1299,6 +1329,11 @@ namespace WatchIt.Database.Migrations
|
|||||||
b.Navigation("ViewCountsMedia");
|
b.Navigation("ViewCountsMedia");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPhotoImage", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("MediaPhotoImageBackground");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
modelBuilder.Entity("WatchIt.Database.Model.Media.MediaPosterImage", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Media")
|
b.Navigation("Media")
|
||||||
|
|||||||
@@ -7,20 +7,20 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
||||||
<PackageReference Include="SimpleToolkit.Extensions" Version="1.7.5" />
|
<PackageReference Include="SimpleToolkit.Extensions" Version="1.7.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
83
WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MediaController.cs
Normal file
83
WatchIt.WebAPI/WatchIt.WebAPI.Controllers/MediaController.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using WatchIt.Common.Model.Genres;
|
||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
using WatchIt.WebAPI.Services.Controllers.Media;
|
||||||
|
|
||||||
|
namespace WatchIt.WebAPI.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("media")]
|
||||||
|
public class MediaController(IMediaControllerService mediaControllerService)
|
||||||
|
{
|
||||||
|
[HttpGet("{id}/genres")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<GenreResponse>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetGenres([FromRoute]long id) => await mediaControllerService.GetGenres(id);
|
||||||
|
|
||||||
|
[HttpPost("{id}/genres/{genre_id}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
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]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> DeleteGenre([FromRoute]long id, [FromRoute(Name = "genre_id")]short genreId) => await mediaControllerService.DeleteGenre(id, genreId);
|
||||||
|
|
||||||
|
[HttpGet("{id}/photos/random_background")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetMediaRandomBackgroundPhoto([FromRoute]long id) => await mediaControllerService.GetMediaRandomBackgroundPhoto(id);
|
||||||
|
|
||||||
|
[HttpGet("photos/{photo_id}")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetPhoto([FromRoute(Name = "photo_id")] Guid photoId) => await mediaControllerService.GetPhoto(photoId);
|
||||||
|
|
||||||
|
[HttpGet("photos")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<MediaPhotoResponse>), StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> GetPhotos(MediaPhotoQueryParameters query) => await mediaControllerService.GetPhotos(query);
|
||||||
|
|
||||||
|
[HttpGet("photos/random_background")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetRandomBackgroundPhoto() => await mediaControllerService.GetRandomBackgroundPhoto();
|
||||||
|
|
||||||
|
[HttpPost("photos")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(MediaPhotoResponse), StatusCodes.Status201Created)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<ActionResult> PostPhoto([FromBody]MediaPhotoRequest body) => await mediaControllerService.PostPhoto(body);
|
||||||
|
|
||||||
|
[HttpPut("photos/{photo_id}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> PutPhoto([FromRoute(Name = "photo_id")]Guid photoId, [FromBody]MediaPhotoRequest body) => await mediaControllerService.PutPhoto(photoId, body);
|
||||||
|
|
||||||
|
[HttpDelete("photos/{photo_id}")]
|
||||||
|
[Authorize]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> DeletePhoto([FromRoute(Name = "photo_id")]Guid photoId) => await mediaControllerService.DeletePhoto(photoId);
|
||||||
|
}
|
||||||
@@ -36,33 +36,11 @@ public class MoviesController(IMoviesControllerService moviesControllerService)
|
|||||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
public async Task<ActionResult> Put([FromRoute]long id, [FromBody]MovieRequest body) => await moviesControllerService.Put(id, body);
|
public async Task<ActionResult> Put([FromRoute]long id, [FromBody]MovieRequest body) => await moviesControllerService.Put(id, body);
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
||||||
public async Task<ActionResult> Delete([FromRoute]long id) => await moviesControllerService.Delete(id);
|
public async Task<ActionResult> Delete([FromRoute] long id) => await moviesControllerService.Delete(id);
|
||||||
|
|
||||||
[HttpGet("{id}/genres")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
[ProducesResponseType(typeof(IEnumerable<GenreResponse>), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ActionResult> GetGenres([FromRoute]long id) => await moviesControllerService.GetGenres(id);
|
|
||||||
|
|
||||||
[HttpPost("{id}/genres/{genre_id}")]
|
|
||||||
[Authorize]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ActionResult> PostGenre([FromRoute]long id, [FromRoute(Name = "genre_id")]short genreId) => await moviesControllerService.PostGenre(id, genreId);
|
|
||||||
|
|
||||||
[HttpDelete("{id}/genres/{genre_id}")]
|
|
||||||
[Authorize]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
|
|
||||||
[ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ActionResult> DeleteGenre([FromRoute]long id, [FromRoute(Name = "genre_id")]short genreId) => await moviesControllerService.DeleteGenre(id, genreId);
|
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
<ProjectReference Include="..\..\WatchIt.Common\WatchIt.Common.Model\WatchIt.Common.Model.csproj" />
|
<ProjectReference Include="..\..\WatchIt.Common\WatchIt.Common.Model\WatchIt.Common.Model.csproj" />
|
||||||
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Accounts\WatchIt.WebAPI.Services.Controllers.Accounts.csproj" />
|
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Accounts\WatchIt.WebAPI.Services.Controllers.Accounts.csproj" />
|
||||||
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Genres\WatchIt.WebAPI.Services.Controllers.Genres.csproj" />
|
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Genres\WatchIt.WebAPI.Services.Controllers.Genres.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Media\WatchIt.WebAPI.Services.Controllers.Media.csproj" />
|
||||||
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Movies\WatchIt.WebAPI.Services.Controllers.Movies.csproj" />
|
<ProjectReference Include="..\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Movies\WatchIt.WebAPI.Services.Controllers.Movies.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
using WatchIt.WebAPI.Services.Controllers.Common;
|
||||||
|
|
||||||
|
namespace WatchIt.WebAPI.Services.Controllers.Media;
|
||||||
|
|
||||||
|
public interface IMediaControllerService
|
||||||
|
{
|
||||||
|
Task<RequestResult> GetGenres(long mediaId);
|
||||||
|
Task<RequestResult> PostGenre(long mediaId, short genreId);
|
||||||
|
Task<RequestResult> DeleteGenre(long mediaId, short genreId);
|
||||||
|
Task<RequestResult> GetPhoto(Guid id);
|
||||||
|
Task<RequestResult> GetPhotos(MediaPhotoQueryParameters query);
|
||||||
|
Task<RequestResult> GetRandomBackgroundPhoto();
|
||||||
|
Task<RequestResult> GetMediaRandomBackgroundPhoto(long id);
|
||||||
|
Task<RequestResult> PostPhoto(MediaPhotoRequest data);
|
||||||
|
Task<RequestResult> PutPhoto(Guid photoId, MediaPhotoRequest data);
|
||||||
|
Task<RequestResult> DeletePhoto(Guid photoId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SimpleToolkit.Extensions;
|
||||||
|
using WatchIt.Common.Model.Genres;
|
||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
using WatchIt.Database;
|
||||||
|
using WatchIt.Database.Model.Media;
|
||||||
|
using WatchIt.WebAPI.Services.Controllers.Common;
|
||||||
|
using WatchIt.WebAPI.Services.Utility.User;
|
||||||
|
|
||||||
|
namespace WatchIt.WebAPI.Services.Controllers.Media;
|
||||||
|
|
||||||
|
public class MediaControllerService(DatabaseContext database, IUserService userService) : IMediaControllerService
|
||||||
|
{
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public async Task<RequestResult> GetGenres(long mediaId)
|
||||||
|
{
|
||||||
|
MediaMovie? item = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == mediaId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<GenreResponse> genres = item.Media.MediaGenres.Select(x => new GenreResponse(x.Genre));
|
||||||
|
return RequestResult.Ok(genres);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> PostGenre(long mediaId, short genreId)
|
||||||
|
{
|
||||||
|
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||||
|
if (!validator.IsValid)
|
||||||
|
{
|
||||||
|
return RequestResult.Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
Database.Model.Media.Media? mediaItem = await database.Media.FirstOrDefaultAsync(x => x.Id == mediaId);
|
||||||
|
Database.Model.Common.Genre? genreItem = await database.Genres.FirstOrDefaultAsync(x => x.Id == genreId);
|
||||||
|
if (mediaItem is null || genreItem is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
await database.MediaGenres.AddAsync(new MediaGenre
|
||||||
|
{
|
||||||
|
GenreId = genreId,
|
||||||
|
MediaId = mediaId,
|
||||||
|
});
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RequestResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> DeleteGenre(long mediaId, short genreId)
|
||||||
|
{
|
||||||
|
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||||
|
if (!validator.IsValid)
|
||||||
|
{
|
||||||
|
return RequestResult.Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaGenre? item = await database.MediaGenres.FirstOrDefaultAsync(x => x.MediaId == mediaId && x.GenreId == genreId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
database.MediaGenres.Attach(item);
|
||||||
|
database.MediaGenres.Remove(item);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RequestResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> GetPhoto(Guid id)
|
||||||
|
{
|
||||||
|
MediaPhotoImage? item = await database.MediaPhotoImages.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoResponse data = new MediaPhotoResponse(item);
|
||||||
|
return RequestResult.Ok(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> GetPhotos(MediaPhotoQueryParameters query)
|
||||||
|
{
|
||||||
|
IEnumerable<MediaPhotoResponse> data = await database.MediaPhotoImages.Select(x => new MediaPhotoResponse(x)).ToListAsync();
|
||||||
|
data = query.PrepareData(data);
|
||||||
|
return RequestResult.Ok(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<RequestResult> GetRandomBackgroundPhoto()
|
||||||
|
{
|
||||||
|
MediaPhotoImage? image = database.MediaPhotoImages.Where(x => x.MediaPhotoImageBackground != null && x.MediaPhotoImageBackground.IsUniversalBackground).Random();
|
||||||
|
if (image is null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RequestResult>(RequestResult.NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoResponse data = new MediaPhotoResponse(image);
|
||||||
|
return Task.FromResult<RequestResult>(RequestResult.Ok(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<RequestResult> GetMediaRandomBackgroundPhoto(long id)
|
||||||
|
{
|
||||||
|
MediaPhotoImage? image = database.MediaPhotoImages.Where(x => x.MediaId == id && x.MediaPhotoImageBackground != null).Random();
|
||||||
|
if (image is null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<RequestResult>(RequestResult.NotFound());
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoResponse data = new MediaPhotoResponse(image);
|
||||||
|
return Task.FromResult<RequestResult>(RequestResult.Ok(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> PostPhoto(MediaPhotoRequest data)
|
||||||
|
{
|
||||||
|
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||||
|
if (!validator.IsValid)
|
||||||
|
{
|
||||||
|
return RequestResult.Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoImage item = data.CreateMediaPhotoImage();
|
||||||
|
await database.MediaPhotoImages.AddAsync(item);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
MediaPhotoImageBackground? background = data.CreateMediaPhotoImageBackground(item.Id);
|
||||||
|
if (background is not null)
|
||||||
|
{
|
||||||
|
await database.MediaPhotoImageBackgrounds.AddAsync(background);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return RequestResult.Created($"photos/{item.Id}", new MediaPhotoResponse(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> PutPhoto(Guid photoId, MediaPhotoRequest data)
|
||||||
|
{
|
||||||
|
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||||
|
if (!validator.IsValid)
|
||||||
|
{
|
||||||
|
return RequestResult.Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoImage? item = await database.MediaPhotoImages.FirstOrDefaultAsync(x => x.Id == photoId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
data.UpdateMediaPhotoImage(item);
|
||||||
|
if (item.MediaPhotoImageBackground is null && data.Background is not null)
|
||||||
|
{
|
||||||
|
MediaPhotoImageBackground background = data.CreateMediaPhotoImageBackground(item.Id)!;
|
||||||
|
await database.MediaPhotoImageBackgrounds.AddAsync(background);
|
||||||
|
}
|
||||||
|
else if (item.MediaPhotoImageBackground is not null && data.Background is null)
|
||||||
|
{
|
||||||
|
database.MediaPhotoImageBackgrounds.Attach(item.MediaPhotoImageBackground);
|
||||||
|
database.MediaPhotoImageBackgrounds.Remove(item.MediaPhotoImageBackground);
|
||||||
|
}
|
||||||
|
else if (item.MediaPhotoImageBackground is not null && data.Background is not null)
|
||||||
|
{
|
||||||
|
data.UpdateMediaPhotoImageBackground(item.MediaPhotoImageBackground);
|
||||||
|
}
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RequestResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> DeletePhoto(Guid photoId)
|
||||||
|
{
|
||||||
|
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
||||||
|
if (!validator.IsValid)
|
||||||
|
{
|
||||||
|
return RequestResult.Forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaPhotoImage? item = await database.MediaPhotoImages.FirstOrDefaultAsync(x => x.Id == photoId);
|
||||||
|
if (item is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.MediaPhotoImageBackground is not null)
|
||||||
|
{
|
||||||
|
database.MediaPhotoImageBackgrounds.Attach(item.MediaPhotoImageBackground);
|
||||||
|
database.MediaPhotoImageBackgrounds.Remove(item.MediaPhotoImageBackground);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
database.MediaPhotoImages.Attach(item);
|
||||||
|
database.MediaPhotoImages.Remove(item);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return RequestResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Common\WatchIt.Common.Model\WatchIt.Common.Model.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Database\WatchIt.Database.Model\WatchIt.Database.Model\WatchIt.Database.Model.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Database\WatchIt.Database\WatchIt.Database.csproj" />
|
||||||
|
<ProjectReference Include="..\..\WatchIt.WebAPI.Services.Utility\WatchIt.WebAPI.Services.Utility.User\WatchIt.WebAPI.Services.Utility.User.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.WebAPI.Services.Controllers.Common\WatchIt.WebAPI.Services.Controllers.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SimpleToolkit.Extensions" Version="1.7.7" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -10,7 +10,4 @@ public interface IMoviesControllerService
|
|||||||
Task<RequestResult> Post(MovieRequest data);
|
Task<RequestResult> Post(MovieRequest data);
|
||||||
Task<RequestResult> Put(long id, MovieRequest data);
|
Task<RequestResult> Put(long id, MovieRequest data);
|
||||||
Task<RequestResult> Delete(long id);
|
Task<RequestResult> Delete(long id);
|
||||||
Task<RequestResult> GetGenres(long movieId);
|
|
||||||
Task<RequestResult> PostGenre(long movieId, short genreId);
|
|
||||||
Task<RequestResult> DeleteGenre(long movieId, short genreId);
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using WatchIt.Common.Model.Genres;
|
|
||||||
using WatchIt.Common.Model.Movies;
|
using WatchIt.Common.Model.Movies;
|
||||||
using WatchIt.Database;
|
using WatchIt.Database;
|
||||||
using WatchIt.Database.Model.Media;
|
using WatchIt.Database.Model.Media;
|
||||||
using WatchIt.WebAPI.Services.Controllers.Common;
|
using WatchIt.WebAPI.Services.Controllers.Common;
|
||||||
using WatchIt.WebAPI.Services.Utility.User;
|
using WatchIt.WebAPI.Services.Utility.User;
|
||||||
using Genre = WatchIt.Database.Model.Common.Genre;
|
|
||||||
|
|
||||||
namespace WatchIt.WebAPI.Services.Controllers.Movies;
|
namespace WatchIt.WebAPI.Services.Controllers.Movies;
|
||||||
|
|
||||||
@@ -110,62 +108,5 @@ public class MoviesControllerService(DatabaseContext database, IUserService user
|
|||||||
return RequestResult.Ok();
|
return RequestResult.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RequestResult> GetGenres(long movieId)
|
|
||||||
{
|
|
||||||
MediaMovie? item = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == movieId);
|
|
||||||
if (item is null)
|
|
||||||
{
|
|
||||||
return RequestResult.NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<GenreResponse> genres = item.Media.MediaGenres.Select(x => new GenreResponse(x.Genre));
|
|
||||||
return RequestResult.Ok(genres);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<RequestResult> PostGenre(long movieId, short genreId)
|
|
||||||
{
|
|
||||||
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
|
||||||
if (!validator.IsValid)
|
|
||||||
{
|
|
||||||
return RequestResult.Forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaMovie? movieItem = await database.MediaMovies.FirstOrDefaultAsync(x => x.Id == movieId);
|
|
||||||
Genre? genreItem = await database.Genres.FirstOrDefaultAsync(x => x.Id == genreId);
|
|
||||||
if (movieItem is null || genreItem is null)
|
|
||||||
{
|
|
||||||
return RequestResult.NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
await database.MediaGenres.AddAsync(new MediaGenre
|
|
||||||
{
|
|
||||||
GenreId = genreId,
|
|
||||||
MediaId = movieId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return RequestResult.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<RequestResult> DeleteGenre(long movieId, short genreId)
|
|
||||||
{
|
|
||||||
UserValidator validator = userService.GetValidator().MustBeAdmin();
|
|
||||||
if (!validator.IsValid)
|
|
||||||
{
|
|
||||||
return RequestResult.Forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaGenre? item = await database.MediaGenres.FirstOrDefaultAsync(x => x.MediaId == movieId && x.GenreId == genreId);
|
|
||||||
if (item is null)
|
|
||||||
{
|
|
||||||
return RequestResult.NotFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
database.MediaGenres.Attach(item);
|
|
||||||
database.MediaGenres.Remove(item);
|
|
||||||
await database.SaveChangesAsync();
|
|
||||||
|
|
||||||
return RequestResult.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
|
||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
using WatchIt.Database;
|
||||||
|
|
||||||
|
namespace WatchIt.WebAPI.Validators.Media;
|
||||||
|
|
||||||
|
public class MediaPhotoRequestValidator : AbstractValidator<MediaPhotoRequest>
|
||||||
|
{
|
||||||
|
public MediaPhotoRequestValidator(DatabaseContext database)
|
||||||
|
{
|
||||||
|
RuleFor(x => x.MediaId).MustBeIn(database.Media, x => x.Id).WithMessage("Media does not exists");
|
||||||
|
RuleFor(x => x.Image).NotEmpty();
|
||||||
|
RuleFor(x => x.MimeType).Matches(@"\w+/.+").WithMessage("Incorrect mimetype");
|
||||||
|
When(x => x.Background is not null, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Background!.FirstGradientColor).Must(x => x.Length == 3).WithMessage("First gradient color has to be 3 byte long");
|
||||||
|
RuleFor(x => x.Background!.SecondGradientColor).Must(x => x.Length == 3).WithMessage("Second gradient color has to be 3 byte long");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ using Microsoft.IdentityModel.Tokens;
|
|||||||
using WatchIt.Database;
|
using WatchIt.Database;
|
||||||
using WatchIt.WebAPI.Services.Controllers.Accounts;
|
using WatchIt.WebAPI.Services.Controllers.Accounts;
|
||||||
using WatchIt.WebAPI.Services.Controllers.Genres;
|
using WatchIt.WebAPI.Services.Controllers.Genres;
|
||||||
|
using WatchIt.WebAPI.Services.Controllers.Media;
|
||||||
using WatchIt.WebAPI.Services.Controllers.Movies;
|
using WatchIt.WebAPI.Services.Controllers.Movies;
|
||||||
using WatchIt.WebAPI.Services.Utility.Configuration;
|
using WatchIt.WebAPI.Services.Utility.Configuration;
|
||||||
using WatchIt.WebAPI.Services.Utility.Tokens;
|
using WatchIt.WebAPI.Services.Utility.Tokens;
|
||||||
@@ -141,6 +142,7 @@ public static class Program
|
|||||||
builder.Services.AddSingleton<IAccountsControllerService, AccountsControllerService>();
|
builder.Services.AddSingleton<IAccountsControllerService, AccountsControllerService>();
|
||||||
builder.Services.AddSingleton<IGenresControllerService, GenresControllerService>();
|
builder.Services.AddSingleton<IGenresControllerService, GenresControllerService>();
|
||||||
builder.Services.AddSingleton<IMoviesControllerService, MoviesControllerService>();
|
builder.Services.AddSingleton<IMoviesControllerService, MoviesControllerService>();
|
||||||
|
builder.Services.AddSingleton<IMediaControllerService, MediaControllerService>();
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
|
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
|
||||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
|
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
|
||||||
|
public class ConfigurationService(IConfiguration configuration) : IConfigurationService
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
public ConfigurationData Data => configuration.Get<ConfigurationData>()!;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
|
||||||
|
public interface IConfigurationService
|
||||||
|
{
|
||||||
|
ConfigurationData Data { get; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Accounts
|
||||||
|
{
|
||||||
|
public string Base { get; set; }
|
||||||
|
public string Register { get; set; }
|
||||||
|
public string Authenticate { get; set; }
|
||||||
|
public string AuthenticateRefresh { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class ConfigurationData
|
||||||
|
{
|
||||||
|
public Logging Logging { get; set; }
|
||||||
|
public string AllowedHosts { get; set; }
|
||||||
|
public Endpoints Endpoints { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Endpoints
|
||||||
|
{
|
||||||
|
public string Base { get; set; }
|
||||||
|
public Accounts Accounts { get; set; }
|
||||||
|
public Genres Genres { get; set; }
|
||||||
|
public Movies Movies { get; set; }
|
||||||
|
public Media Media { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Genres
|
||||||
|
{
|
||||||
|
public string Base { get; set; }
|
||||||
|
public string GetAll { get; set; }
|
||||||
|
public string Get { get; set; }
|
||||||
|
public string Post { get; set; }
|
||||||
|
public string Put { get; set; }
|
||||||
|
public string Delete { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class LogLevel
|
||||||
|
{
|
||||||
|
public string Default { get; set; }
|
||||||
|
public string Microsoft_AspNetCore { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Logging
|
||||||
|
{
|
||||||
|
public LogLevel LogLevel { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Media
|
||||||
|
{
|
||||||
|
public string Base { get; set; }
|
||||||
|
public string GetGenres { get; set; }
|
||||||
|
public string PostGenre { get; set; }
|
||||||
|
public string DeleteGenre { get; set; }
|
||||||
|
public string GetPhotoMediaRandomBackground { get; set; }
|
||||||
|
public string GetPhoto { get; set; }
|
||||||
|
public string GetPhotos { get; set; }
|
||||||
|
public string GetPhotoRandomBackground { get; set; }
|
||||||
|
public string PostPhoto { get; set; }
|
||||||
|
public string PutPhoto { get; set; }
|
||||||
|
public string DeletePhoto { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
public class Movies
|
||||||
|
{
|
||||||
|
public string Base { get; set; }
|
||||||
|
public string GetAll { get; set; }
|
||||||
|
public string Get { get; set; }
|
||||||
|
public string Post { get; set; }
|
||||||
|
public string Put { get; set; }
|
||||||
|
public string Delete { get; set; }
|
||||||
|
public string GetGenres { get; set; }
|
||||||
|
public string PostGenre { get; set; }
|
||||||
|
public string DeleteGenre { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using WatchIt.Common.Model.Accounts;
|
||||||
|
using WatchIt.Common.Services.HttpClient;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
using WatchIt.Website.Services.WebAPI.Common;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.WebAPI.Accounts;
|
||||||
|
|
||||||
|
public class AccountsWebAPIService(IHttpClientService httpClientService, IConfigurationService configurationService) : BaseWebAPIService(configurationService), IAccountsWebAPIService
|
||||||
|
{
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public async Task Register(RegisterRequest data, Action<RegisterResponse> createdAction, Action<IDictionary<string, string[]>> badRequestAction)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.Register);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Post, url)
|
||||||
|
{
|
||||||
|
Body = data,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(createdAction)
|
||||||
|
.RegisterActionFor400BadRequest(badRequestAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Authenticate(AuthenticateRequest data, Action<AuthenticateResponse> successAction, Action<IDictionary<string, string[]>> badRequestAction, Action unauthorizedAction)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.Authenticate);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Post, url)
|
||||||
|
{
|
||||||
|
Body = data,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor400BadRequest(badRequestAction)
|
||||||
|
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AuthenticateRefresh(Action<AuthenticateResponse> successAction, Action unauthorizedAction, Action forbiddenAction)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.AuthenticateRefresh);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Post, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||||
|
.RegisterActionFor403Forbidden(forbiddenAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
protected override string GetServiceBase() => EndpointsConfiguration.Accounts.Base;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using WatchIt.Common.Model.Accounts;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.WebAPI.Accounts;
|
||||||
|
|
||||||
|
public interface IAccountsWebAPIService
|
||||||
|
{
|
||||||
|
Task Register(RegisterRequest data, Action<RegisterResponse> createdAction, Action<IDictionary<string, string[]>> badRequestAction);
|
||||||
|
Task Authenticate(AuthenticateRequest data, Action<AuthenticateResponse> successAction, Action<IDictionary<string, string[]>> badRequestAction, Action unauthorizedAction);
|
||||||
|
Task AuthenticateRefresh(Action<AuthenticateResponse> successAction, Action unauthorizedAction, Action forbiddenAction);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Common\WatchIt.Common.Model\WatchIt.Common.Model.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Common\WatchIt.Common.Services\WatchIt.Common.Services.HttpClient\WatchIt.Common.Services.HttpClient.csproj" />
|
||||||
|
<ProjectReference Include="..\..\WatchIt.Website.Services.Utility\WatchIt.Website.Services.Utility.Configuration\WatchIt.Website.Services.Utility.Configuration.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Website.Services.WebAPI.Common\WatchIt.Website.Services.WebAPI.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.WebAPI.Common;
|
||||||
|
|
||||||
|
public abstract class BaseWebAPIService(IConfigurationService configurationService)
|
||||||
|
{
|
||||||
|
#region FIELDS
|
||||||
|
|
||||||
|
protected Endpoints EndpointsConfiguration => configurationService.Data.Endpoints;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
protected abstract string GetServiceBase();
|
||||||
|
|
||||||
|
protected string GetUrl(string suffix) => string.Concat(EndpointsConfiguration.Base, GetServiceBase(), suffix);
|
||||||
|
|
||||||
|
protected string GetUrl(string suffix, params object[] format) => string.Concat(EndpointsConfiguration.Base, GetServiceBase(), string.Format(suffix, format));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Utility\WatchIt.WebAPI.Services.Utility.Configuration\WatchIt.WebAPI.Services.Utility.Configuration.csproj" />
|
||||||
|
<ProjectReference Include="..\..\WatchIt.Website.Services.Utility\WatchIt.Website.Services.Utility.Configuration\WatchIt.Website.Services.Utility.Configuration.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using WatchIt.Common.Model.Genres;
|
||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.WebAPI.Media;
|
||||||
|
|
||||||
|
public interface IMediaWebAPIService
|
||||||
|
{
|
||||||
|
Task GetGenres(long mediaId, Action<IEnumerable<GenreResponse>> successAction, Action notFoundAction);
|
||||||
|
Task PostGenre(long mediaId, long genreId, Action successAction, Action unauthorizedAction, Action forbiddenAction, Action notFoundAction);
|
||||||
|
Task GetPhotoRandomBackground(Action<MediaPhotoResponse> successAction, Action notFoundAction);
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using WatchIt.Common.Model.Genres;
|
||||||
|
using WatchIt.Common.Model.Media;
|
||||||
|
using WatchIt.Common.Services.HttpClient;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration.Model;
|
||||||
|
using WatchIt.Website.Services.WebAPI.Common;
|
||||||
|
|
||||||
|
namespace WatchIt.Website.Services.WebAPI.Media;
|
||||||
|
|
||||||
|
public class MediaWebAPIService(IHttpClientService httpClientService, IConfigurationService configurationService) : BaseWebAPIService(configurationService), IMediaWebAPIService
|
||||||
|
{
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public async Task GetGenres(long mediaId, Action<IEnumerable<GenreResponse>>? successAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Media.GetGenres, mediaId);
|
||||||
|
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PostGenre(long mediaId, long genreId, Action? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Media.PostGenre, mediaId, genreId);
|
||||||
|
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||||
|
.RegisterActionFor403Forbidden(forbiddenAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GetPhotoRandomBackground(Action<MediaPhotoResponse>? successAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Media.GetPhotoRandomBackground);
|
||||||
|
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
protected override string GetServiceBase() => EndpointsConfiguration.Media.Base;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Common\WatchIt.Common.Model\WatchIt.Common.Model.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\WatchIt.Common\WatchIt.Common.Services\WatchIt.Common.Services.HttpClient\WatchIt.Common.Services.HttpClient.csproj" />
|
||||||
|
<ProjectReference Include="..\..\WatchIt.Website.Services.Utility\WatchIt.Website.Services.Utility.Configuration\WatchIt.Website.Services.Utility.Configuration.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Website.Services.WebAPI.Common\WatchIt.Website.Services.WebAPI.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<base href="/"/>
|
<base href="/"/>
|
||||||
<link rel="stylesheet" href="bootstrap/bootstrap.min.css"/>
|
<link rel="stylesheet" href="bootstrap/bootstrap.min.css"/>
|
||||||
<link rel="stylesheet" href="app.css"/>
|
<link rel="stylesheet" href="app.css?version=0.2"/>
|
||||||
<link rel="stylesheet" href="WatchIt.Website.styles.css"/>
|
<link rel="stylesheet" href="WatchIt.Website.styles.css?version=0.2"/>
|
||||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
<HeadOutlet @rendermode="InteractiveServer"/>
|
<HeadOutlet @rendermode="InteractiveServer"/>
|
||||||
</head>
|
</head>
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
@inherits LayoutComponentBase
|
|
||||||
|
|
||||||
<div class="page">
|
|
||||||
<div class="sidebar">
|
|
||||||
<NavMenu/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="top-row px-4">
|
|
||||||
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<article class="content px-4">
|
|
||||||
@Body
|
|
||||||
</article>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="blazor-error-ui">
|
|
||||||
An unhandled error has occurred.
|
|
||||||
<a href="" class="reload">Reload</a>
|
|
||||||
<a class="dismiss">🗙</a>
|
|
||||||
</div>
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
.page {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
background-color: #f7f7f7;
|
|
||||||
border-bottom: 1px solid #d6d5d5;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 3.5rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
white-space: nowrap;
|
|
||||||
margin-left: 1.5rem;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a:first-child {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640.98px) {
|
|
||||||
.top-row {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 641px) {
|
|
||||||
.page {
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 250px;
|
|
||||||
height: 100vh;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row.auth ::deep a:first-child {
|
|
||||||
flex: 1;
|
|
||||||
text-align: right;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row, article {
|
|
||||||
padding-left: 2rem !important;
|
|
||||||
padding-right: 1.5rem !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#blazor-error-ui {
|
|
||||||
background: lightyellow;
|
|
||||||
bottom: 0;
|
|
||||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
|
||||||
display: none;
|
|
||||||
left: 0;
|
|
||||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blazor-error-ui .dismiss {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
right: 0.75rem;
|
|
||||||
top: 0.5rem;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<div class="top-row ps-3 navbar navbar-dark">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="">WatchIt.Website</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler"/>
|
|
||||||
|
|
||||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
|
||||||
<nav class="flex-column">
|
|
||||||
<div class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
|
||||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="counter">
|
|
||||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="weather">
|
|
||||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
.navbar-toggler {
|
|
||||||
appearance: none;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 3.5rem;
|
|
||||||
height: 2.5rem;
|
|
||||||
color: white;
|
|
||||||
position: absolute;
|
|
||||||
top: 0.5rem;
|
|
||||||
right: 1rem;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-toggler:checked {
|
|
||||||
background-color: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-row {
|
|
||||||
height: 3.5rem;
|
|
||||||
background-color: rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-brand {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bi {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 1.25rem;
|
|
||||||
height: 1.25rem;
|
|
||||||
margin-right: 0.75rem;
|
|
||||||
top: -1px;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bi-house-door-fill-nav-menu {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bi-plus-square-fill-nav-menu {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
|
||||||
}
|
|
||||||
|
|
||||||
.bi-list-nested-nav-menu {
|
|
||||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item:first-of-type {
|
|
||||||
padding-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item:last-of-type {
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item ::deep .nav-link {
|
|
||||||
color: #d7d7d7;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
height: 3rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
line-height: 3rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item ::deep a.active {
|
|
||||||
background-color: rgba(255,255,255,0.37);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item ::deep .nav-link:hover {
|
|
||||||
background-color: rgba(255,255,255,0.1);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-scrollable {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-toggler:checked ~ .nav-scrollable {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 641px) {
|
|
||||||
.navbar-toggler {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-scrollable {
|
|
||||||
/* Never collapse the sidebar for wide screens */
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
/* Allow sidebar to scroll for tall menus */
|
|
||||||
height: calc(100vh - 3.5rem);
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
@page "/counter"
|
|
||||||
|
|
||||||
<PageTitle>Counter</PageTitle>
|
|
||||||
|
|
||||||
<h1>Counter</h1>
|
|
||||||
|
|
||||||
<p role="status">Current count: @currentCount</p>
|
|
||||||
|
|
||||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private int currentCount = 0;
|
|
||||||
|
|
||||||
private void IncrementCount()
|
|
||||||
{
|
|
||||||
currentCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
@page "/Error"
|
|
||||||
@using System.Diagnostics
|
|
||||||
|
|
||||||
<PageTitle>Error</PageTitle>
|
|
||||||
|
|
||||||
<h1 class="text-danger">Error.</h1>
|
|
||||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
|
||||||
|
|
||||||
@if (ShowRequestId)
|
|
||||||
{
|
|
||||||
<p>
|
|
||||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
|
|
||||||
<h3>Development Mode</h3>
|
|
||||||
<p>
|
|
||||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
|
||||||
It can result in displaying sensitive information from exceptions to end users.
|
|
||||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
|
||||||
and restarting the app.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
@code{
|
|
||||||
[CascadingParameter] private HttpContext? HttpContext { get; set; }
|
|
||||||
|
|
||||||
private string? RequestId { get; set; }
|
|
||||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
|
||||||
|
|
||||||
protected override void OnInitialized() =>
|
|
||||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
@page "/"
|
|
||||||
|
|
||||||
<PageTitle>Home</PageTitle>
|
|
||||||
|
|
||||||
<h1>Hello, world!</h1>
|
|
||||||
|
|
||||||
Welcome to your new app.
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
@page "/weather"
|
|
||||||
|
|
||||||
<PageTitle>Weather</PageTitle>
|
|
||||||
|
|
||||||
<h1>Weather</h1>
|
|
||||||
|
|
||||||
<p>This component demonstrates showing data.</p>
|
|
||||||
|
|
||||||
@if (forecasts == null)
|
|
||||||
{
|
|
||||||
<p>
|
|
||||||
<em>Loading...</em>
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Temp. (C)</th>
|
|
||||||
<th>Temp. (F)</th>
|
|
||||||
<th>Summary</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var forecast in forecasts)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>@forecast.Date.ToShortDateString()</td>
|
|
||||||
<td>@forecast.TemperatureC</td>
|
|
||||||
<td>@forecast.TemperatureF</td>
|
|
||||||
<td>@forecast.Summary</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
}
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private WeatherForecast[]? forecasts;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
// Simulate asynchronous loading to demonstrate a loading indicator
|
|
||||||
await Task.Delay(500);
|
|
||||||
|
|
||||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
|
||||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
|
||||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
|
||||||
{
|
|
||||||
Date = startDate.AddDays(index),
|
|
||||||
TemperatureC = Random.Shared.Next(-20, 55),
|
|
||||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
|
||||||
}).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class WeatherForecast
|
|
||||||
{
|
|
||||||
public DateOnly Date { get; set; }
|
|
||||||
public int TemperatureC { get; set; }
|
|
||||||
public string? Summary { get; set; }
|
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
3
WatchIt.Website/WatchIt.Website/Layout/EmptyLayout.razor
Normal file
3
WatchIt.Website/WatchIt.Website/Layout/EmptyLayout.razor
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
@Body
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
99
WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor
Normal file
99
WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
@using System.Diagnostics
|
||||||
|
@using System.Text
|
||||||
|
@using WatchIt.Common.Model.Media
|
||||||
|
@using WatchIt.Website.Services.WebAPI.Media
|
||||||
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
@if (loaded)
|
||||||
|
{
|
||||||
|
<div class="container-xl">
|
||||||
|
<div class="row align-items-center m-2 rounded-3 header panel">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<a class="logo" href="/">
|
||||||
|
WatchIt
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<p>Menu</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="d-flex flex-row-reverse">
|
||||||
|
@if (signedIn)
|
||||||
|
{
|
||||||
|
<p>test</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a class="main-button" href="/auth">Sign in or up</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row body-content">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
@Body
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: url('@background') no-repeat center center fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo, .main-button {
|
||||||
|
background-image: linear-gradient(45deg, @firstGradientColor, @secondGradientColor);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
#region SERVICES
|
||||||
|
|
||||||
|
[Inject] public ILogger<MainLayout> Logger { get; set; } = default!;
|
||||||
|
[Inject] public IMediaWebAPIService MediaWebAPIService { get; set; } = default!;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region FIELDS
|
||||||
|
|
||||||
|
private bool loaded = false;
|
||||||
|
|
||||||
|
private string background = "assets/background_temp.jpg";
|
||||||
|
private string firstGradientColor = "#c6721c";
|
||||||
|
private string secondGradientColor = "#85200c";
|
||||||
|
private bool signedIn = false;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region METHODS
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
Action<MediaPhotoResponse> backgroundSuccess = (data) =>
|
||||||
|
{
|
||||||
|
string imageBase64 = Convert.ToBase64String(data.Image);
|
||||||
|
string firstColor = BitConverter.ToString(data.Background.FirstGradientColor)
|
||||||
|
.Replace("-", string.Empty);
|
||||||
|
string secondColor = BitConverter.ToString(data.Background.SecondGradientColor)
|
||||||
|
.Replace("-", string.Empty);
|
||||||
|
|
||||||
|
background = $"data:{data.MimeType};base64,{imageBase64}";
|
||||||
|
firstGradientColor = $"#{firstColor}";
|
||||||
|
secondGradientColor = $"#{secondColor}";
|
||||||
|
};
|
||||||
|
await MediaWebAPIService.GetPhotoRandomBackground(backgroundSuccess, null);
|
||||||
|
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
21
WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor.css
Normal file
21
WatchIt.Website/WatchIt.Website/Layout/MainLayout.razor.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
body {
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: sticky;
|
||||||
|
top: 10px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-content {
|
||||||
|
padding-top: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
73
WatchIt.Website/WatchIt.Website/Pages/Auth.razor
Normal file
73
WatchIt.Website/WatchIt.Website/Pages/Auth.razor
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
@page "/auth"
|
||||||
|
@layout EmptyLayout
|
||||||
|
|
||||||
|
<PageTitle>WatchIt - @(_authType == AuthType.SignIn ? "Sign in" : "Sign up")</PageTitle>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="h-100 d-flex align-items-center justify-content-center">
|
||||||
|
<div class="d-inline-flex flex-column justify-content-center panel rounded-3">
|
||||||
|
<a class="logo" href="/">
|
||||||
|
WatchIt
|
||||||
|
</a>
|
||||||
|
@if (_authType == AuthType.SignIn)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: url('@(_background)') no-repeat center center fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
background-image: linear-gradient(45deg, @_firstGradientColor, @_secondGradientColor);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
#region ENUMS
|
||||||
|
|
||||||
|
private enum AuthType
|
||||||
|
{
|
||||||
|
SignIn,
|
||||||
|
SignUp
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region FIELDS
|
||||||
|
|
||||||
|
private AuthType _authType = AuthType.SignIn;
|
||||||
|
private string _background = "assets/background_temp.jpg";
|
||||||
|
private string _firstGradientColor = "#c6721c";
|
||||||
|
private string _secondGradientColor = "#85200c";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region METHODS
|
||||||
|
|
||||||
|
protected override Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
return base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
8
WatchIt.Website/WatchIt.Website/Pages/Auth.razor.css
Normal file
8
WatchIt.Website/WatchIt.Website/Pages/Auth.razor.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
body {
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-size: 60px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
50
WatchIt.Website/WatchIt.Website/Pages/Home.razor
Normal file
50
WatchIt.Website/WatchIt.Website/Pages/Home.razor
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
@page "/"
|
||||||
|
|
||||||
|
<PageTitle>WatchIt</PageTitle>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
|
||||||
|
|
||||||
|
<h1>Hello, world!</h1>
|
||||||
|
|
||||||
|
Welcome to your new app.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
using WatchIt.Website.Components;
|
using WatchIt.Common.Services.HttpClient;
|
||||||
|
using WatchIt.Website.Services.Utility.Configuration;
|
||||||
|
using WatchIt.Website.Services.WebAPI.Accounts;
|
||||||
|
using WatchIt.Website.Services.WebAPI.Media;
|
||||||
|
|
||||||
namespace WatchIt.Website;
|
namespace WatchIt.Website;
|
||||||
|
|
||||||
public class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
WebApplication app = WebApplication.CreateBuilder(args)
|
||||||
|
.SetupServices()
|
||||||
// Add services to the container.
|
.SetupApplication()
|
||||||
builder.Services.AddRazorComponents()
|
.Build();
|
||||||
.AddInteractiveServerComponents();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (!app.Environment.IsDevelopment())
|
if (!app.Environment.IsDevelopment())
|
||||||
@@ -32,4 +34,34 @@ public class Program
|
|||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PRIVATE METHODS
|
||||||
|
|
||||||
|
private static WebApplicationBuilder SetupServices(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddHttpClient();
|
||||||
|
|
||||||
|
// Utility
|
||||||
|
builder.Services.AddSingleton<IHttpClientService, HttpClientService>();
|
||||||
|
builder.Services.AddSingleton<IConfigurationService, ConfigurationService>();
|
||||||
|
|
||||||
|
// WebAPI
|
||||||
|
builder.Services.AddSingleton<IAccountsWebAPIService, AccountsWebAPIService>();
|
||||||
|
builder.Services.AddSingleton<IMediaWebAPIService, MediaWebAPIService>();
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WebApplicationBuilder SetupApplication(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Services.AddRazorComponents()
|
||||||
|
.AddInteractiveServerComponents();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -13,4 +13,30 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\WatchIt.Common\WatchIt.Common.Services\WatchIt.Common.Services.HttpClient\WatchIt.Common.Services.HttpClient.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Website.Services\WatchIt.Website.Services.Utility\WatchIt.Website.Services.Utility.Configuration\WatchIt.Website.Services.Utility.Configuration.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Accounts\WatchIt.Website.Services.WebAPI.Accounts.csproj" />
|
||||||
|
<ProjectReference Include="..\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Media\WatchIt.Website.Services.WebAPI.Media.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Layout\EmptyLayout.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Layout\MainLayout.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Pages\Counter.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Pages\Error.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Pages\Home.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Components\Pages\Weather.razor" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<AdditionalFiles Include="Layout\MainLayout.razor" />
|
||||||
|
<AdditionalFiles Include="Pages\Home.razor" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Components\" />
|
||||||
|
<Folder Include="wwwroot\assets\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -7,4 +7,4 @@
|
|||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using WatchIt.Website
|
@using WatchIt.Website
|
||||||
@using WatchIt.Website.Components
|
@using WatchIt.Website.Layout
|
||||||
@@ -5,5 +5,46 @@
|
|||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*",
|
||||||
|
"Endpoints": {
|
||||||
|
"Base": "https://localhost:7160",
|
||||||
|
"Accounts": {
|
||||||
|
"Base": "/accounts",
|
||||||
|
"Register": "/register",
|
||||||
|
"Authenticate": "/authenticate",
|
||||||
|
"AuthenticateRefresh": "/authenticate-refresh"
|
||||||
|
},
|
||||||
|
"Genres": {
|
||||||
|
"Base": "/genres",
|
||||||
|
"GetAll": "",
|
||||||
|
"Get": "/{0}",
|
||||||
|
"Post": "",
|
||||||
|
"Put": "/{0}",
|
||||||
|
"Delete": "/{0}"
|
||||||
|
},
|
||||||
|
"Movies": {
|
||||||
|
"Base": "/movies",
|
||||||
|
"GetAll": "",
|
||||||
|
"Get": "/{0}",
|
||||||
|
"Post": "",
|
||||||
|
"Put": "/{0}",
|
||||||
|
"Delete": "/{0}",
|
||||||
|
"GetGenres": "/{0}/genres",
|
||||||
|
"PostGenre": "{0}/genres/{1}",
|
||||||
|
"DeleteGenre": "{0}/genres/{1}"
|
||||||
|
},
|
||||||
|
"Media": {
|
||||||
|
"Base": "/media",
|
||||||
|
"GetGenres": "/{0}/genres",
|
||||||
|
"PostGenre": "/{0}/genres/{1}",
|
||||||
|
"DeleteGenre": "/{0}/genres/{1}",
|
||||||
|
"GetPhotoMediaRandomBackground": "/{0}/photos/random_background",
|
||||||
|
"GetPhoto": "/photos/{0}",
|
||||||
|
"GetPhotos": "/photos",
|
||||||
|
"GetPhotoRandomBackground": "/photos/random_background",
|
||||||
|
"PostPhoto": "/photos",
|
||||||
|
"PutPhoto": "/photos/{0}",
|
||||||
|
"DeletePhoto": "/photos/{0}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,80 @@
|
|||||||
html, body {
|
@font-face {
|
||||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
font-family: Belanosima;
|
||||||
|
src: url(fonts/Belanosima-Regular.ttf) format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
a, .btn-link {
|
@font-face {
|
||||||
color: #006bb7;
|
font-family: Belanosima;
|
||||||
|
src: url(fonts/Belanosima-Bold.ttf) format('truetype');
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
body, html {
|
||||||
|
background-color: transparent;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-family: Belanosima;
|
||||||
|
text-decoration: none;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
backdrop-filter: blur(25px);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button {
|
||||||
|
--r:10px;
|
||||||
|
--b:2px;
|
||||||
|
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
padding: 5px 10px;
|
||||||
|
|
||||||
|
border-radius: var(--r);
|
||||||
|
display: block;
|
||||||
|
align-items: self-end;
|
||||||
|
position: relative;
|
||||||
|
z-index:0;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: 0.3s;
|
||||||
|
font-family: Belanosima;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button::before {
|
||||||
|
content:"";
|
||||||
|
position:absolute;
|
||||||
|
z-index:-1;
|
||||||
|
inset: 0;
|
||||||
|
border: var(--b) solid transparent;
|
||||||
|
border-radius: var(--r);
|
||||||
|
background: inherit;
|
||||||
|
background-origin: border-box;
|
||||||
|
background-clip: border-box;
|
||||||
|
-webkit-mask:
|
||||||
|
linear-gradient(#fff 0 0) padding-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: xor;
|
||||||
|
mask-composite: exclude;
|
||||||
|
-webkit-mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #1b6ec2;
|
-webkit-text-fill-color: #fff;
|
||||||
border-color: #1861ac;
|
-webkit-background-clip: border-box;
|
||||||
|
background-clip: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
.main-button:hover::before {
|
||||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
-webkit-mask:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
padding-top: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.valid.modified:not([type=checkbox]) {
|
|
||||||
outline: 1px solid #26b050;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invalid {
|
|
||||||
outline: 1px solid #e50000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.validation-message {
|
|
||||||
color: #e50000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blazor-error-boundary {
|
|
||||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
|
||||||
padding: 1rem 1rem 1rem 3.7rem;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blazor-error-boundary::after {
|
|
||||||
content: "An error has occurred."
|
|
||||||
}
|
|
||||||
|
|
||||||
.darker-border-checkbox.form-check-input {
|
|
||||||
border-color: #929292;
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
75
WatchIt.sln
75
WatchIt.sln
@@ -50,6 +50,32 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website", "WatchIt.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Controllers.Movies", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Movies\WatchIt.WebAPI.Services.Controllers.Movies.csproj", "{69BB6A9E-B673-42AB-A516-6B2513E21FDC}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Controllers.Movies", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Movies\WatchIt.WebAPI.Services.Controllers.Movies.csproj", "{69BB6A9E-B673-42AB-A516-6B2513E21FDC}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.Website.Services", "WatchIt.Website.Services", "{A82972D0-9A60-4B3F-AE46-9F304D79137F}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.Website.Services.WebAPI", "WatchIt.Website.Services.WebAPI", "{46E3711F-18BD-4004-AF53-EA4D8643D92F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Accounts", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Accounts\WatchIt.Website.Services.WebAPI.Accounts.csproj", "{68B7E892-9074-4034-8AFC-2474D7D5BE29}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Genres", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Genres\WatchIt.Website.Services.WebAPI.Genres.csproj", "{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Movies", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Movies\WatchIt.Website.Services.WebAPI.Movies.csproj", "{539404EB-BDFD-46F8-8F21-6A231ABED9B1}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.Website.Services.Utility", "WatchIt.Website.Services.Utility", "{130BC8F5-82CE-4EDF-AECB-21594DD41849}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WatchIt.Common.Services", "WatchIt.Common.Services", "{882A9795-4AC0-4556-9750-6582B2701EFA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Common.Query", "WatchIt.Common\WatchIt.Common.Query\WatchIt.Common.Query.csproj", "{6C3AE7B4-18C5-42D3-B254-460027E50143}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Common.Services.HttpClient", "WatchIt.Common\WatchIt.Common.Services\WatchIt.Common.Services.HttpClient\WatchIt.Common.Services.HttpClient.csproj", "{A4A75CCA-0DEE-4F1E-9816-60674CA807FA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.Utility.Configuration", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.Utility\WatchIt.Website.Services.Utility.Configuration\WatchIt.Website.Services.Utility.Configuration.csproj", "{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.WebAPI.Services.Controllers.Media", "WatchIt.WebAPI\WatchIt.WebAPI.Services\WatchIt.WebAPI.Services.Controllers\WatchIt.WebAPI.Services.Controllers.Media\WatchIt.WebAPI.Services.Controllers.Media.csproj", "{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Media", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Media\WatchIt.Website.Services.WebAPI.Media.csproj", "{1D64B7B5-650D-4AF3-AC33-A8D1F0999906}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchIt.Website.Services.WebAPI.Common", "WatchIt.Website\WatchIt.Website.Services\WatchIt.Website.Services.WebAPI\WatchIt.Website.Services.WebAPI.Common\WatchIt.Website.Services.WebAPI.Common.csproj", "{2D62ED42-489E-4888-9479-E5A50A0E7D70}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -77,6 +103,19 @@ Global
|
|||||||
{2EC6FD28-C580-45FA-B6A7-92A6BF0CCC54} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7}
|
{2EC6FD28-C580-45FA-B6A7-92A6BF0CCC54} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7}
|
||||||
{46CE78A1-3EC3-4112-AAAD-26EEB8D8B194} = {4CB91BF6-87F1-4088-A943-62548CD1F9F4}
|
{46CE78A1-3EC3-4112-AAAD-26EEB8D8B194} = {4CB91BF6-87F1-4088-A943-62548CD1F9F4}
|
||||||
{69BB6A9E-B673-42AB-A516-6B2513E21FDC} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7}
|
{69BB6A9E-B673-42AB-A516-6B2513E21FDC} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7}
|
||||||
|
{A82972D0-9A60-4B3F-AE46-9F304D79137F} = {4CB91BF6-87F1-4088-A943-62548CD1F9F4}
|
||||||
|
{46E3711F-18BD-4004-AF53-EA4D8643D92F} = {A82972D0-9A60-4B3F-AE46-9F304D79137F}
|
||||||
|
{68B7E892-9074-4034-8AFC-2474D7D5BE29} = {46E3711F-18BD-4004-AF53-EA4D8643D92F}
|
||||||
|
{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1} = {46E3711F-18BD-4004-AF53-EA4D8643D92F}
|
||||||
|
{539404EB-BDFD-46F8-8F21-6A231ABED9B1} = {46E3711F-18BD-4004-AF53-EA4D8643D92F}
|
||||||
|
{130BC8F5-82CE-4EDF-AECB-21594DD41849} = {A82972D0-9A60-4B3F-AE46-9F304D79137F}
|
||||||
|
{882A9795-4AC0-4556-9750-6582B2701EFA} = {E98C42C1-26E5-4939-8C22-72C253DE874B}
|
||||||
|
{6C3AE7B4-18C5-42D3-B254-460027E50143} = {E98C42C1-26E5-4939-8C22-72C253DE874B}
|
||||||
|
{A4A75CCA-0DEE-4F1E-9816-60674CA807FA} = {882A9795-4AC0-4556-9750-6582B2701EFA}
|
||||||
|
{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F} = {130BC8F5-82CE-4EDF-AECB-21594DD41849}
|
||||||
|
{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4} = {CEC468DB-CC49-47D3-9E3E-1CC9530C3CE7}
|
||||||
|
{1D64B7B5-650D-4AF3-AC33-A8D1F0999906} = {46E3711F-18BD-4004-AF53-EA4D8643D92F}
|
||||||
|
{2D62ED42-489E-4888-9479-E5A50A0E7D70} = {46E3711F-18BD-4004-AF53-EA4D8643D92F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{23383776-1F27-4B5D-8C7C-57BFF75FA473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{23383776-1F27-4B5D-8C7C-57BFF75FA473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
@@ -147,5 +186,41 @@ Global
|
|||||||
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
{69BB6A9E-B673-42AB-A516-6B2513E21FDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{68B7E892-9074-4034-8AFC-2474D7D5BE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{68B7E892-9074-4034-8AFC-2474D7D5BE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{68B7E892-9074-4034-8AFC-2474D7D5BE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{68B7E892-9074-4034-8AFC-2474D7D5BE29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A98D06A6-9C95-4449-9F4E-1D31BBE1D9B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{539404EB-BDFD-46F8-8F21-6A231ABED9B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{539404EB-BDFD-46F8-8F21-6A231ABED9B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{539404EB-BDFD-46F8-8F21-6A231ABED9B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{539404EB-BDFD-46F8-8F21-6A231ABED9B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6C3AE7B4-18C5-42D3-B254-460027E50143}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6C3AE7B4-18C5-42D3-B254-460027E50143}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6C3AE7B4-18C5-42D3-B254-460027E50143}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6C3AE7B4-18C5-42D3-B254-460027E50143}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A4A75CCA-0DEE-4F1E-9816-60674CA807FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A4A75CCA-0DEE-4F1E-9816-60674CA807FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A4A75CCA-0DEE-4F1E-9816-60674CA807FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A4A75CCA-0DEE-4F1E-9816-60674CA807FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0DBBE7EA-05FE-481F-8814-6FA0BC9E571F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3156AD7B-D6EC-4EB6-AEE8-4FBAF14C18E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1D64B7B5-650D-4AF3-AC33-A8D1F0999906}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1D64B7B5-650D-4AF3-AC33-A8D1F0999906}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1D64B7B5-650D-4AF3-AC33-A8D1F0999906}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1D64B7B5-650D-4AF3-AC33-A8D1F0999906}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2D62ED42-489E-4888-9479-E5A50A0E7D70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D62ED42-489E-4888-9479-E5A50A0E7D70}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D62ED42-489E-4888-9479-E5A50A0E7D70}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D62ED42-489E-4888-9479-E5A50A0E7D70}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
Reference in New Issue
Block a user