(feat): media attachments

This commit is contained in:
Maksym Sadovnychyy 2022-09-07 21:51:54 +02:00
parent 2c137947c6
commit ab3154e375
43 changed files with 755 additions and 465 deletions

File diff suppressed because one or more lines are too long

View File

@ -10,24 +10,28 @@
"title": "Shop item title", "title": "Shop item title",
"shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
"text": "", "text": "",
"contentType": 0, "textFormat": 0,
"plainText": "", "plainText": "",
"badges": [ "badges": [
"sale" "sale"
] ]
} }
], ],
"images": [ "mediaAttachments": [
{ {
"src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "src": "api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692",
"l10n": [ "mediaType": 0,
"l10n": [
{ {
"locale": 0, "locale": 0,
"alt": "..." "alt": "...",
} "href": "/title-image-2",
"title": "Title image 2",
"description": "Title image 1 description."
}
] ]
} }
], ],
"author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"created": { "created": {
"$date": "2022-01-01T00:00:00.000Z" "$date": "2022-01-01T00:00:00.000Z"
@ -58,24 +62,28 @@
"title": "Shop item title", "title": "Shop item title",
"shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
"text": "", "text": "",
"contentType": 0, "textFormat": 0,
"plainText": "", "plainText": "",
"badges": [ "badges": [
"sale" "sale"
] ]
} }
], ],
"images": [ "mediaAttachments": [
{ {
"src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "src": "api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692",
"l10n": [ "mediaType": 0,
"l10n": [
{ {
"locale": 0, "locale": 0,
"alt": "..." "alt": "...",
} "href": "/title-image-2",
"title": "Title image 2",
"description": "Title image 1 description."
}
] ]
} }
], ],
"author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"created": { "created": {
"$date": "2022-01-01T00:00:00.000Z" "$date": "2022-01-01T00:00:00.000Z"
@ -106,24 +114,28 @@
"title": "Shop item title", "title": "Shop item title",
"shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
"text": "", "text": "",
"contentType": 0, "textFormat": 0,
"plainText": "", "plainText": "",
"badges": [ "badges": [
"sale" "sale"
] ]
} }
], ],
"images": [ "mediaAttachments": [
{ {
"src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "src": "api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692",
"l10n": [ "mediaType": 0,
"l10n": [
{ {
"locale": 0, "locale": 0,
"alt": "..." "alt": "...",
} "href": "/title-image-2",
"title": "Title image 2",
"description": "Title image 1 description."
}
] ]
} }
], ],
"author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"created": { "created": {
"$date": "2022-01-01T00:00:00.000Z" "$date": "2022-01-01T00:00:00.000Z"
@ -154,24 +166,28 @@
"title": "Shop item title", "title": "Shop item title",
"shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...", "shortText": "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Eaque fugit ratione dicta mollitia. Officiis ad...",
"text": "", "text": "",
"contentType": 0, "textFormat": 0,
"plainText": "", "plainText": "",
"badges": [ "badges": [
"sale" "sale"
] ]
} }
], ],
"images": [ "mediaAttachments": [
{ {
"src": "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", "src": "api/Image/450x300/5033d24e-a7c3-4960-ac3c-f396d6773692",
"l10n": [ "mediaType": 0,
"l10n": [
{ {
"locale": 0, "locale": 0,
"alt": "..." "alt": "...",
} "href": "/title-image-2",
"title": "Title image 2",
"description": "Title image 1 description."
}
] ]
} }
], ],
"author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60", "author": "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60",
"created": { "created": {
"$date": "2022-01-01T00:00:00.000Z" "$date": "2022-01-01T00:00:00.000Z"

View File

@ -3,6 +3,6 @@
namespace Core.Abstractions.DomainObjects { namespace Core.Abstractions.DomainObjects {
public abstract class PersonBase<T> : DomainObjectBase<T> { public abstract class PersonBase<T> : DomainObjectBase<T> {
public Guid Id { get; set; } public Guid Id { get; set; }
public Image? Image { get; set; } public MediaAttachment? Image { get; set; }
} }
} }

View File

@ -15,7 +15,7 @@ namespace Core.Abstractions.DomainObjects {
public List<PostItemL10n> L10n { get; set; } public List<PostItemL10n> L10n { get; set; }
public List<Image>? Images { get; set; } public List<MediaAttachment>? MediaAttachments { get; set; }
public Guid Author { get; set; } public Guid Author { get; set; }

View File

@ -13,8 +13,8 @@ namespace Core.DomainObjects.Documents {
hash = hash * 23 + Id.GetHashCode(); hash = hash * 23 + Id.GetHashCode();
hash = hash * 23 + SiteId.GetHashCode(); hash = hash * 23 + SiteId.GetHashCode();
hash = hash * 23 + L10n.GetHashCode(); hash = hash * 23 + L10n.GetHashCode();
if (Images != null) if (MediaAttachments != null)
hash = hash * 23 + Images.Sum(x => x.GetHashCode()); hash = hash * 23 + MediaAttachments.Sum(x => x.GetHashCode());
hash = hash * 23 + Author.GetHashCode(); hash = hash * 23 + Author.GetHashCode();
hash = hash * 23 + Created.GetHashCode(); hash = hash * 23 + Created.GetHashCode();
if(Tags != null) if(Tags != null)

View File

@ -15,8 +15,8 @@ namespace Core.DomainObjects.Documents {
hash = hash * 23 + Id.GetHashCode(); hash = hash * 23 + Id.GetHashCode();
hash = hash * 23 + SiteId.GetHashCode(); hash = hash * 23 + SiteId.GetHashCode();
hash = hash * 23 + L10n.GetHashCode(); hash = hash * 23 + L10n.GetHashCode();
if (Images != null) if (MediaAttachments != null)
hash = hash * 23 + Images.Sum(x => x.GetHashCode()); hash = hash * 23 + MediaAttachments.Sum(x => x.GetHashCode());
hash = hash * 23 + Author.GetHashCode(); hash = hash * 23 + Author.GetHashCode();
hash = hash * 23 + Created.GetHashCode(); hash = hash * 23 + Created.GetHashCode();
hash = hash * 23 + Tags.GetHashCode(); hash = hash * 23 + Tags.GetHashCode();

View File

@ -6,9 +6,10 @@ namespace Core.DomainObjects {
public class Image : DomainObjectBase<Image> { public class MediaAttachment : DomainObjectBase<MediaAttachment> {
public string Src { get; set; } public string Src { get; set; }
public List<ImageL10n> L10n { get; set; } public MediaTypes MediaType { get; set; }
public List<MediaAttachmentL10n> L10n { get; set; }
public override int GetHashCode() { public override int GetHashCode() {
int hash = 17; int hash = 17;

View File

@ -7,14 +7,27 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Core.DomainObjects.L10n { namespace Core.DomainObjects.L10n {
public class ImageL10n : DomainObjectBase<ImageL10n> { public class MediaAttachmentL10n : DomainObjectBase<MediaAttachmentL10n> {
public Locales Locale { get; set; } public Locales Locale { get; set; }
public string Alt { get; set; } public string Alt { get; set; }
public string? Target { get; set; }
public string? Titile { get; set; }
public string? Description { get; set; }
public override int GetHashCode() { public override int GetHashCode() {
int hash = 17; int hash = 17;
hash = hash * 23 + Locale.GetHashCode(); hash = hash * 23 + Locale.GetHashCode();
hash = hash * 23 + Alt.GetHashCode(); hash = hash * 23 + Alt.GetHashCode();
if(Target != null)
hash = hash * 23 + Target.GetHashCode();
if (Titile != null)
hash = hash * 23 + Target.GetHashCode();
if (Description != null)
hash = hash * 23 + Description.GetHashCode();
return hash; return hash;
} }
} }

View File

@ -8,7 +8,7 @@ namespace Core.DomainObjects.L10n {
public string Description { get; set; } public string Description { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Text { get; set; } public string Text { get; set; }
public ContentTypes ContentType { get; set; } public TextFormat TextFormat { get; set; }
public string PlainText { get; set; } public string PlainText { get; set; }
public string ShortText { get; set; } public string ShortText { get; set; }
public List<string>? Badges { get; set; } public List<string>? Badges { get; set; }
@ -21,7 +21,7 @@ namespace Core.DomainObjects.L10n {
hash = hash * 23 + Description.GetHashCode(); hash = hash * 23 + Description.GetHashCode();
hash = hash * 23 + Title.GetHashCode(); hash = hash * 23 + Title.GetHashCode();
hash = hash * 23 + Text.GetHashCode(); hash = hash * 23 + Text.GetHashCode();
hash = hash * 23 + ContentType.GetHashCode(); hash = hash * 23 + TextFormat.GetHashCode();
hash = hash * 23 + ShortText.GetHashCode(); hash = hash * 23 + ShortText.GetHashCode();
hash = hash * 23 + Badges.Sum(x => x.GetHashCode()); hash = hash * 23 + Badges.Sum(x => x.GetHashCode());
return hash; return hash;

View File

@ -2,7 +2,7 @@
namespace Core.DomainObjects.PageSections { namespace Core.DomainObjects.PageSections {
public class TitleSection : PageSectionBase<TitleSection> { public class TitleSection : PageSectionBase<TitleSection> {
public Image? Image { get; set; } public MediaAttachment? Image { get; set; }
public Link? PrimaryLink { get; set; } public Link? PrimaryLink { get; set; }
public Link? SecondaryLink { get; set; } public Link? SecondaryLink { get; set; }
public string? PostedOnBy { get; set; } public string? PostedOnBy { get; set; }

View File

@ -1,11 +0,0 @@
using Core.Abstractions;
namespace Core.Enumerations {
public class ContentTypes : Enumeration {
public static ContentTypes Html = new(0, "HTML");
public static ContentTypes Md = new(1, "MD");
private ContentTypes(int id, string displayName) : base(id, displayName) { }
}
}

View File

@ -0,0 +1,15 @@
using Core.Abstractions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core.Enumerations {
public class MediaTypes : Enumeration {
public static MediaTypes Image = new(0, "image");
public static MediaTypes Video = new(1, "video");
public static MediaTypes Document = new(1, "document");
private MediaTypes(int id, string displayName) : base(id, displayName) { }
}
}

View File

@ -0,0 +1,11 @@
using Core.Abstractions;
namespace Core.Enumerations {
public class TextFormat : Enumeration {
public static TextFormat Html = new(0, "HTML");
public static TextFormat Md = new(1, "MD");
private TextFormat(int id, string displayName) : base(id, displayName) { }
}
}

View File

@ -96,7 +96,8 @@ namespace DataProviders.Abstractions {
{ "siteId", $"{siteId}"}, { "siteId", $"{siteId}"},
{ "userId", $"{userId}"}, { "userId", $"{userId}"},
{ "fileName", file.Name }, { "fileName", file.Name },
{ "contentType", file.ContentType } { "contentType", file.ContentType },
{ "private", true }
}; };
var fileId = Guid.NewGuid(); var fileId = Guid.NewGuid();

View File

@ -0,0 +1,58 @@
using DomainResults.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataProviders.Buckets {
/// <summary>
///
/// </summary>
public interface IBucketDataProvider {
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="file"></param>
/// <returns></returns>
(Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
(List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
(BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
IDomainResult DeletMany(Guid siteId, Guid userId);
}
}

View File

@ -11,57 +11,7 @@ namespace DataProviders.Buckets {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public interface IImagesBucketDataProvider { public class ImagesBucketDataProvider : BucketDataProviderBase, IBucketDataProvider {
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="file"></param>
/// <returns></returns>
(Guid?, IDomainResult) Upload(Guid siteId, Guid userId, BucketFile file);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="files"></param>
/// <returns></returns>
(List<Guid>?, IDomainResult) UploadMany(Guid siteId, Guid userId, List<BucketFile> files);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
(BucketFile?, IDomainResult) Download(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <param name="fileId"></param>
/// <returns></returns>
IDomainResult DeleteOne(Guid siteId, Guid userId, Guid fileId);
/// <summary>
///
/// </summary>
/// <param name="siteId"></param>
/// <param name="userId"></param>
/// <returns></returns>
IDomainResult DeletMany(Guid siteId, Guid userId);
}
/// <summary>
///
/// </summary>
public class ImagesBucketDataProvider : BucketDataProviderBase, IImagesBucketDataProvider {
private const string _bucketName = "images"; private const string _bucketName = "images";

View File

@ -29,7 +29,7 @@ namespace DataProviders.Extensions
#endregion #endregion
#region Buckets #region Buckets
services.AddSingleton<IImagesBucketDataProvider, ImagesBucketDataProvider>(); services.AddSingleton<IBucketDataProvider, ImagesBucketDataProvider>();
#endregion #endregion
} }
} }

View File

@ -34,13 +34,13 @@ namespace DataProviders {
cm.GetMemberMap(c => c.Locale) cm.GetMemberMap(c => c.Locale)
.SetSerializer(new EnumerationSerializer<Locales>()); .SetSerializer(new EnumerationSerializer<Locales>());
cm.GetMemberMap(c => c.ContentType) cm.GetMemberMap(c => c.TextFormat)
.SetSerializer(new EnumerationSerializer<ContentTypes>()); .SetSerializer(new EnumerationSerializer<TextFormat>());
}); });
} }
if (!BsonClassMap.IsClassMapRegistered(typeof(ImageL10n))) { if (!BsonClassMap.IsClassMapRegistered(typeof(MediaAttachmentL10n))) {
BsonClassMap.RegisterClassMap<ImageL10n>(cm => { BsonClassMap.RegisterClassMap<MediaAttachmentL10n>(cm => {
cm.AutoMap(); cm.AutoMap();
cm.GetMemberMap(c => c.Locale) cm.GetMemberMap(c => c.Locale)
@ -108,8 +108,8 @@ namespace DataProviders {
}); });
} }
if (!BsonClassMap.IsClassMapRegistered(typeof(Image))) { if (!BsonClassMap.IsClassMapRegistered(typeof(MediaAttachment))) {
BsonClassMap.RegisterClassMap<Image>(cm => { BsonClassMap.RegisterClassMap<MediaAttachment>(cm => {
cm.AutoMap(); cm.AutoMap();
}); });
} }

View File

@ -0,0 +1,6 @@
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();

View File

@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:39739",
"sslPort": 44327
}
},
"profiles": {
"ReverseProxy": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7174;http://localhost:5178",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,29 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"route1": {
"ClusterId": "cluster1",
"Match": {
"Path": "{**catch-all}"
}
}
},
"Clusters": {
"cluster1": {
"Destinations": {
"destination1": {
"Address": "https://example.com/"
}
}
}
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FileSecurityService {
/// <summary>
///
/// </summary>
public enum FileCategory {
/// <summary>
///
/// </summary>
Document,
/// <summary>
///
/// </summary>
Image,
/// <summary>
///
/// </summary>
Video
}
}

View File

@ -1,4 +1,5 @@
using DomainResults.Common; using Core.Enumerations;
using DomainResults.Common;
using ExtensionMethods; using ExtensionMethods;
namespace FileSecurityService { namespace FileSecurityService {
@ -14,7 +15,7 @@ namespace FileSecurityService {
/// <param name="bytes"></param> /// <param name="bytes"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <returns></returns> /// <returns></returns>
(FileCategory?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType); (MediaTypes?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType);
} }
public class FileSecurityService : IFileSecurityService { public class FileSecurityService : IFileSecurityService {
@ -33,13 +34,13 @@ namespace FileSecurityService {
".pdf", ".pdf",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,25504446" "0,25504446"
}, "application/pdf", FileCategory.Document) }, "application/pdf", MediaTypes.Document)
}, },
{ {
".rtf", ".rtf",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,7B5C72746631" "0,7B5C72746631"
}, "application/rtf", FileCategory.Document) }, "application/rtf", MediaTypes.Document)
}, },
{ {
".doc", ".doc",
@ -49,7 +50,7 @@ namespace FileSecurityService {
"0,D0CF11E0A1B11AE1", "0,D0CF11E0A1B11AE1",
"0,DBA52D00", "0,DBA52D00",
"512,ECA5C100" "512,ECA5C100"
}, "application/msword", FileCategory.Document) }, "application/msword", MediaTypes.Document)
}, },
{ {
".xls", ".xls",
@ -58,7 +59,7 @@ namespace FileSecurityService {
"0,D0CF11E0A1B11AE1", "0,D0CF11E0A1B11AE1",
"512,FDFFFFFF04", "512,FDFFFFFF04",
"512,FDFFFFFF20000000" "512,FDFFFFFF20000000"
}, "application/vnd.ms-excel", FileCategory.Document) }, "application/vnd.ms-excel", MediaTypes.Document)
}, },
{ {
".ppt", ".ppt",
@ -68,25 +69,25 @@ namespace FileSecurityService {
"512,A0461DF0", "512,A0461DF0",
"0,D0CF11E0A1B11AE1", "0,D0CF11E0A1B11AE1",
"512,FDFFFFFF04" "512,FDFFFFFF04"
}, "application/vnd.ms-powerpoint", FileCategory.Document) }, "application/vnd.ms-powerpoint", MediaTypes.Document)
}, },
{ {
".docx", ".docx",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,504B030414000600" "0,504B030414000600"
}, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", FileCategory.Document) }, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", MediaTypes.Document)
}, },
{ {
".xlsx", ".xlsx",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,504B030414000600" "0,504B030414000600"
}, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", FileCategory.Document) }, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", MediaTypes.Document)
}, },
{ {
".pptx", ".pptx",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,504B030414000600" "0,504B030414000600"
}, "application/vnd.openxmlformats-officedocument.presentationml.presentation", FileCategory.Document) }, "application/vnd.openxmlformats-officedocument.presentationml.presentation", MediaTypes.Document)
}, },
#endregion #endregion
@ -95,39 +96,39 @@ namespace FileSecurityService {
".jpg", ".jpg",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,FFD8" "0,FFD8"
}, "image/jpeg", FileCategory.Image) }, "image/jpeg", MediaTypes.Image)
}, },
{ {
".jpeg", ".jpeg",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,FFD8" "0,FFD8"
}, "image/jpeg", FileCategory.Image) }, "image/jpeg", MediaTypes.Image)
}, },
{ {
".jpe", ".jpe",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,FFD8" "0,FFD8"
}, "image/jpeg", FileCategory.Image) }, "image/jpeg", MediaTypes.Image)
}, },
{ {
".jfif", ".jfif",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,FFD8" "0,FFD8"
}, "image/jpeg", FileCategory.Image) }, "image/jpeg", MediaTypes.Image)
}, },
{ {
".png", ".png",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,89504E470D0A1A0A" "0,89504E470D0A1A0A"
}, "image/png", FileCategory.Image) }, "image/png", MediaTypes.Image)
}, },
{ {
".webp", ".webp",
new FileSignature(new List<string> { new FileSignature(new List<string> {
"0,52494646" "0,52494646"
}, "image/webp", FileCategory.Image) }, "image/webp", MediaTypes.Image)
} }
#endregion #endregion
}; };
@ -141,16 +142,16 @@ namespace FileSecurityService {
/// <param name="bytes"></param> /// <param name="bytes"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <returns></returns> /// <returns></returns>
public (FileCategory?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType) { public (MediaTypes?, IDomainResult) CheckFileSignature(string fileName, byte[] bytes, string contentType) {
var data = _data.SingleOrDefault(x => x.Key == Path.GetExtension(fileName).ToLower()).Value; var data = _data.SingleOrDefault(x => x.Key == Path.GetExtension(fileName).ToLower()).Value;
if (data == null) if (data == null)
return IDomainResult.NotFound<FileCategory?>(); return IDomainResult.NotFound<MediaTypes?>();
// check content type // check content type
if (contentType != data.ContentType) if (contentType != data.ContentType)
return IDomainResult.Failed<FileCategory?>(); return IDomainResult.Failed<MediaTypes?>();
// check signatures // check signatures
foreach (var signature in data.Signatures) { foreach (var signature in data.Signatures) {
@ -172,10 +173,10 @@ namespace FileSecurityService {
x |= sample[i] ^ signBytes[i]; x |= sample[i] ^ signBytes[i];
} }
if (x == 0) return IDomainResult.Success(data.FileCategory); if (x == 0) return IDomainResult.Success(data.MediaType);
} }
return IDomainResult.Failed<FileCategory?>(); return IDomainResult.Failed<MediaTypes?>();
} }
} }
} }

View File

@ -13,6 +13,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Core\Core.csproj" />
<ProjectReference Include="..\..\Extensions\Extensions.csproj" /> <ProjectReference Include="..\..\Extensions\Extensions.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -1,4 +1,5 @@
using System; using Core.Enumerations;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -23,18 +24,18 @@ namespace FileSecurityService {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public FileCategory FileCategory { get; private set; } public MediaTypes MediaType { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="signatures"></param> /// <param name="signatures"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <param name="fileCategory"></param> /// <param name="mediaType"></param>
public FileSignature(List<string> signatures, string contentType, FileCategory fileCategory) { public FileSignature(List<string> signatures, string contentType, MediaTypes mediaType) {
Signatures = signatures; Signatures = signatures;
ContentType = contentType; ContentType = contentType;
FileCategory = fileCategory; MediaType = mediaType;
} }
} }
} }

View File

@ -29,7 +29,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreTests", "Tests\Core\Cor
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageService", "Services\ImageService\ImageService.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageService", "Services\ImageService\ImageService.csproj", "{16552644-D7EE-4B4A-A725-79909A8103DE}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSecurityService", "Services\FileSecurityService\FileSecurityService.csproj", "{AD515653-9145-4894-9017-0ABA5A5892F4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSecurityService", "Services\FileSecurityService\FileSecurityService.csproj", "{AD515653-9145-4894-9017-0ABA5A5892F4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseProxy", "ReverseProxy\ReverseProxy.csproj", "{281F43C5-3B40-4DA6-B32B-8E8BC39D3DA3}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -85,6 +87,10 @@ Global
{AD515653-9145-4894-9017-0ABA5A5892F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD515653-9145-4894-9017-0ABA5A5892F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD515653-9145-4894-9017-0ABA5A5892F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD515653-9145-4894-9017-0ABA5A5892F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD515653-9145-4894-9017-0ABA5A5892F4}.Release|Any CPU.Build.0 = Release|Any CPU {AD515653-9145-4894-9017-0ABA5A5892F4}.Release|Any CPU.Build.0 = Release|Any CPU
{281F43C5-3B40-4DA6-B32B-8E8BC39D3DA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{281F43C5-3B40-4DA6-B32B-8E8BC39D3DA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{281F43C5-3B40-4DA6-B32B-8E8BC39D3DA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{281F43C5-3B40-4DA6-B32B-8E8BC39D3DA3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -18,7 +18,7 @@ namespace WeatherForecast.Models.Abstractions {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ImageResponseModel? Image { get; set; } public MediaAttachmentResponseModel? Image { get; set; }
/// <summary> /// <summary>
/// ///

View File

@ -19,6 +19,9 @@ namespace WeatherForecast.Models.Abstractions {
/// </summary> /// </summary>
public List<PostItemL10nModel>? L10n { get; set; } public List<PostItemL10nModel>? L10n { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>

View File

@ -74,7 +74,7 @@ namespace WeatherForecast.Models.Abstractions {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<ImageResponseModel>? Images { get; set; } public List<MediaAttachmentResponseModel>? MediaAttachemnts { get; set; }
/// <summary> /// <summary>
/// ///
@ -123,7 +123,7 @@ namespace WeatherForecast.Models.Abstractions {
public PostItemResponseModelBase(PostItemBase<T> postItem, List<Category> categories) : this(postItem) { public PostItemResponseModelBase(PostItemBase<T> postItem, List<Category> categories) : this(postItem) {
L10n = postItem.L10n.Select(x => new PostItemL10nModel(x)).ToList(); L10n = postItem.L10n.Select(x => new PostItemL10nModel(x)).ToList();
Categories = categories.Select(x => new CategoryItemResponseModel(x)).ToList(); Categories = categories.Select(x => new CategoryItemResponseModel(x)).ToList();
Images = postItem.Images?.Select(x => new ImageResponseModel(x)).ToList(); MediaAttachemnts = postItem.MediaAttachments?.Select(x => new MediaAttachmentResponseModel(x)).ToList();
} }
/// <summary> /// <summary>
@ -147,7 +147,7 @@ namespace WeatherForecast.Models.Abstractions {
} }
Categories = categories.Select(x => new CategoryItemResponseModel(x, locale)).ToList(); Categories = categories.Select(x => new CategoryItemResponseModel(x, locale)).ToList();
Images = postItem.Images?.Select(x => new ImageResponseModel(x, locale)).ToList(); MediaAttachemnts = postItem.MediaAttachments?.Select(x => new MediaAttachmentResponseModel(x, locale)).ToList();
} }
} }
} }

View File

@ -11,7 +11,7 @@ namespace WeatherForecast.Models.PageSections {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ImageResponseModel? Image { get; set; } public MediaAttachmentResponseModel? Image { get; set; }
/// <summary> /// <summary>
/// ///

View File

@ -10,7 +10,7 @@ namespace WeatherForecast.Models {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class ImageRequestModel : RequestModelBase<Image> { public class ImageRequestModel : RequestModelBase<MediaAttachment> {
/// <summary> /// <summary>
/// ///
@ -32,7 +32,7 @@ namespace WeatherForecast.Models {
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
/// <exception cref="NotImplementedException"></exception> /// <exception cref="NotImplementedException"></exception>
public override Image ToDomainObject() { public override MediaAttachment ToDomainObject() {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -10,7 +10,7 @@ namespace WeatherForecast.Models.Requests.L10n {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class ImageL10nModel : RequestModelBase<ImageL10n> { public class ImageL10nModel : RequestModelBase<MediaAttachmentL10n> {
/// <summary> /// <summary>
/// ///
@ -26,10 +26,10 @@ namespace WeatherForecast.Models.Requests.L10n {
/// ///
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public override ImageL10n ToDomainObject() { public override MediaAttachmentL10n ToDomainObject() {
if (HasValidationErrors()) throw new ValidationException(); if (HasValidationErrors()) throw new ValidationException();
return new ImageL10n() { return new MediaAttachmentL10n() {
Locale = Enumeration.FromDisplayName<Locales>(Locale), Locale = Enumeration.FromDisplayName<Locales>(Locale),
Alt = Alt Alt = Alt
}; };

View File

@ -75,7 +75,7 @@ namespace WeatherForecast.Models.Requests.L10n {
// TODO: create plain text creation logic // TODO: create plain text creation logic
PlainText = "TODO", PlainText = "TODO",
ContentType = Enumeration.FromDisplayName<ContentTypes>(ContentType), TextFormat = Enumeration.FromDisplayName<TextFormat>(ContentType),
Badges = Badges Badges = Badges
}; };
} }
@ -108,7 +108,7 @@ namespace WeatherForecast.Models.Requests.L10n {
if (string.IsNullOrWhiteSpace(ContentType)) if (string.IsNullOrWhiteSpace(ContentType))
yield return new ValidationResult($"{nameof(ContentType)} {Errors.NullOrWhiteSpace.Name}"); yield return new ValidationResult($"{nameof(ContentType)} {Errors.NullOrWhiteSpace.Name}");
else if (Enumeration.FromDisplayName<ContentTypes>(ContentType) == null) else if (Enumeration.FromDisplayName<TextFormat>(ContentType) == null)
yield return new ValidationResult($"{nameof(ContentType)} {Errors.WrongOrNotManaged}"); yield return new ValidationResult($"{nameof(ContentType)} {Errors.WrongOrNotManaged}");
} }

View File

@ -6,7 +6,7 @@ namespace WeatherForecast.Models.Responses.L10n {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class ImageL10nModel : ResponseModelBase { public class MediaAttachmentL10nModel : ResponseModelBase {
/// <summary> /// <summary>
/// ///
@ -18,11 +18,26 @@ namespace WeatherForecast.Models.Responses.L10n {
/// </summary> /// </summary>
public string Alt { get; set; } public string Alt { get; set; }
/// <summary>
///
/// </summary>
public string? Target { get; set; }
/// <summary>
///
/// </summary>
public string? Title { get; set; }
/// <summary>
///
/// </summary>
public string? Description { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="imageL10n"></param> /// <param name="imageL10n"></param>
public ImageL10nModel(ImageL10n imageL10n) { public MediaAttachmentL10nModel(MediaAttachmentL10n imageL10n) {
Locale = imageL10n.Locale.Name; Locale = imageL10n.Locale.Name;
Alt = imageL10n.Alt; Alt = imageL10n.Alt;
} }

View File

@ -46,7 +46,7 @@ namespace WeatherForecast.Models.Responses.L10n {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ContentType { get; set; } public string TextFormat { get; set; }
/// <summary> /// <summary>
/// ///
@ -66,7 +66,7 @@ namespace WeatherForecast.Models.Responses.L10n {
ShortText = postItemL10n.ShortText; ShortText = postItemL10n.ShortText;
PlainText = postItemL10n.PlainText; PlainText = postItemL10n.PlainText;
Text = postItemL10n.Text; Text = postItemL10n.Text;
ContentType = postItemL10n.ContentType.Name; TextFormat = postItemL10n.TextFormat.Name;
Badges = postItemL10n.Badges; Badges = postItemL10n.Badges;
} }
} }

View File

@ -7,12 +7,12 @@ namespace WeatherForecast.Models {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class ImageResponseModel { public class MediaAttachmentResponseModel {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public List<ImageL10nModel>? L10n { get; set; } public List<MediaAttachmentL10nModel>? L10n { get; set; }
/// <summary> /// <summary>
/// ///
@ -28,19 +28,19 @@ namespace WeatherForecast.Models {
/// ///
/// </summary> /// </summary>
/// <param name="image"></param> /// <param name="image"></param>
public ImageResponseModel(Image image) { public MediaAttachmentResponseModel(MediaAttachment image) {
L10n = image.L10n.Select(x => new ImageL10nModel(x)).ToList(); L10n = image.L10n.Select(x => new MediaAttachmentL10nModel(x)).ToList();
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="image"></param> /// <param name="mediaAttachment"></param>
/// <param name="locale"></param> /// <param name="locale"></param>
public ImageResponseModel(Image image, Locales locale) { public MediaAttachmentResponseModel(MediaAttachment mediaAttachment, Locales locale) {
Src = image.Src; Src = mediaAttachment.Src;
var l10n = image.L10n.Single(x => x.Locale == locale); var l10n = mediaAttachment.L10n.Single(x => x.Locale == locale);
if (l10n != null) { if (l10n != null) {
Alt = l10n.Alt; Alt = l10n.Alt;

View File

@ -22,7 +22,7 @@ namespace WeatherForecast.Models.Responses {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ImageResponseModel? Image { get; set; } public MediaAttachmentResponseModel? Image { get; set; }
/// <summary> /// <summary>
/// ///
@ -82,8 +82,8 @@ namespace WeatherForecast.Models.Responses {
ShortText = l10n.ShortText; ShortText = l10n.ShortText;
} }
if(shopItem.Images != null) if(shopItem.MediaAttachments != null)
Image = new ImageResponseModel(shopItem.Images.First(), locale); Image = new MediaAttachmentResponseModel(shopItem.MediaAttachments.First(), locale);
} }
} }

View File

@ -104,11 +104,11 @@ namespace WeatherForecast.Services {
item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid(); item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid();
// TODO: should be placed to object storage // TODO: should be placed to object storage
item.Images = new List<Image>() { item.MediaAttachments = new List<MediaAttachment>() {
new Image { new MediaAttachment {
Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg",
L10n = new List<ImageL10n> { L10n = new List<MediaAttachmentL10n> {
new ImageL10n { new MediaAttachmentL10n {
Locale = Locales.Us, Locale = Locales.Us,
Alt = "..." Alt = "..."
} }

View File

@ -1,4 +1,5 @@
using Core; using Core;
using Core.Enumerations;
using DataProviders; using DataProviders;
using DataProviders.Buckets; using DataProviders.Buckets;
using DomainResults.Common; using DomainResults.Common;
@ -46,7 +47,7 @@ namespace WeatherForecast.Services {
private readonly ILogger<FilesService> _logger; private readonly ILogger<FilesService> _logger;
private readonly IFileSecurityService _fileSecurityService; private readonly IFileSecurityService _fileSecurityService;
private readonly IImagesBucketDataProvider _imageBucketDataProvider; private readonly IBucketDataProvider _imageBucketDataProvider;
/// <summary> /// <summary>
/// ///
@ -57,7 +58,7 @@ namespace WeatherForecast.Services {
public FileService( public FileService(
ILogger<FilesService> logger, ILogger<FilesService> logger,
IFileSecurityService fileSecurityService, IFileSecurityService fileSecurityService,
IImagesBucketDataProvider imageBucketDataProvider IBucketDataProvider imageBucketDataProvider
) { ) {
_logger = logger; _logger = logger;
_fileSecurityService = fileSecurityService; _fileSecurityService = fileSecurityService;
@ -80,8 +81,8 @@ namespace WeatherForecast.Services {
file.CopyTo(ms); file.CopyTo(ms);
var bytes = ms.ToArray(); var bytes = ms.ToArray();
var (fileCategory, signatureResult) = _fileSecurityService.CheckFileSignature(file.FileName, bytes, file.ContentType); var (mediaType, signatureResult) = _fileSecurityService.CheckFileSignature(file.FileName, bytes, file.ContentType);
if(!signatureResult.IsSuccess || fileCategory == null) if(!signatureResult.IsSuccess || mediaType == null)
return IDomainResult.Failed<Guid?>(); return IDomainResult.Failed<Guid?>();
var bucketFile = new BucketFile(file.FileName, bytes, file.ContentType); var bucketFile = new BucketFile(file.FileName, bytes, file.ContentType);
@ -89,13 +90,10 @@ namespace WeatherForecast.Services {
IDomainResult result; IDomainResult result;
Guid? fileId; Guid? fileId;
switch (fileCategory) { if (mediaType == MediaTypes.Image)
case FileCategory.Image: (fileId, result) = _imageBucketDataProvider.Upload(siteId, userId, bucketFile);
(fileId, result) = _imageBucketDataProvider.Upload(siteId, userId, bucketFile); else
break; return IDomainResult.Failed<Guid?>();
default:
return IDomainResult.Failed<Guid?>();
}
if (!result.IsSuccess || fileId == null) if (!result.IsSuccess || fileId == null)
return IDomainResult.Failed<Guid?>(); return IDomainResult.Failed<Guid?>();

View File

@ -35,7 +35,7 @@ namespace WeatherForecast.Services {
private readonly ILogger<FilesService> _logger; private readonly ILogger<FilesService> _logger;
private readonly IFileSecurityService _fileSecurityService; private readonly IFileSecurityService _fileSecurityService;
private readonly IImagesBucketDataProvider _imageBucketDataProvider; private readonly IBucketDataProvider _imageBucketDataProvider;
/// <summary> /// <summary>
/// ///
@ -45,7 +45,7 @@ namespace WeatherForecast.Services {
public FilesService( public FilesService(
ILogger<FilesService> logger, ILogger<FilesService> logger,
IFileSecurityService fileSecurityService, IFileSecurityService fileSecurityService,
IImagesBucketDataProvider imageBucketDataProvider IBucketDataProvider imageBucketDataProvider
) { ) {
_logger = logger; _logger = logger;
_fileSecurityService = fileSecurityService; _fileSecurityService = fileSecurityService;

View File

@ -110,11 +110,11 @@ namespace WeatherForecast.Services {
item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid(); item.Author = "fdc5aa50-ee68-4bae-a8e6-b8ae2c258f60".ToGuid();
// TODO: should be placed to object storage // TODO: should be placed to object storage
item.Images = new List<Image>() { item.MediaAttachments = new List<MediaAttachment>() {
new Image { new MediaAttachment {
Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg", Src = "https://dummyimage.com/450x300/dee2e6/6c757d.jpg",
L10n = new List<ImageL10n> { L10n = new List<MediaAttachmentL10n> {
new ImageL10n { new MediaAttachmentL10n {
Locale = Locales.Us, Locale = Locales.Us,
Alt = "..." Alt = "..."
} }