From 49468b205c8142cf673d89e1df5430d4c7f3c25e Mon Sep 17 00:00:00 2001 From: Ivan Yaremenchuk Date: Fri, 30 Sep 2022 04:51:30 -0500 Subject: [PATCH 1/3] Add cover file to Token --- NftFaucet/Models/Dto/TokenDto.cs | 12 +++-- NftFaucet/Models/NewFileModel.cs | 9 ++-- NftFaucet/Models/TokenMetadata.cs | 3 ++ NftFaucet/Pages/CreateTokenDialog.razor | 16 ++++++- NftFaucet/Pages/CreateTokenDialog.razor.cs | 50 +++++++++++++++++---- NftFaucet/Pages/CreateUploadDialog.razor.cs | 31 +++++++++---- NftFaucet/Pages/TokensPage.razor.cs | 41 ++++++++++------- NftFaucet/Plugins/IToken.cs | 3 +- NftFaucet/Plugins/Token.cs | 3 +- NftFaucet/Program.cs | 14 +++--- NftFaucet/Services/Mapper.cs | 31 ++++++++----- NftFaucet/Services/StateRepository.cs | 2 +- 12 files changed, 157 insertions(+), 58 deletions(-) diff --git a/NftFaucet/Models/Dto/TokenDto.cs b/NftFaucet/Models/Dto/TokenDto.cs index fe936f5..4afffd8 100644 --- a/NftFaucet/Models/Dto/TokenDto.cs +++ b/NftFaucet/Models/Dto/TokenDto.cs @@ -6,8 +6,12 @@ public class TokenDto public string Name { get; set; } public string Description { get; set; } public DateTime CreatedAt { get; set; } - public string ImageFileName { get; set; } - public string ImageFileType { get; set; } - public string ImageFileData { get; set; } - public long? ImageFileSize { get; set; } + public string MainFileName { get; set; } + public string MainFileType { get; set; } + public string MainFileData { get; set; } + public long? MainFileSize { get; set; } + public string CoverFileName { get; set; } + public string CoverFileType { get; set; } + public string CoverFileData { get; set; } + public long? CoverFileSize { get; set; } } diff --git a/NftFaucet/Models/NewFileModel.cs b/NftFaucet/Models/NewFileModel.cs index 36a2e7c..e47543e 100644 --- a/NftFaucet/Models/NewFileModel.cs +++ b/NftFaucet/Models/NewFileModel.cs @@ -4,7 +4,10 @@ public class NewFileModel { public string Name { get; set; } public string Description { get; set; } - public string FileData { get; set; } - public string FileName { get; set; } - public long? FileSize { get; set; } + public string MainFileData { get; set; } + public string MainFileName { get; set; } + public long? MainFileSize { get; set; } + public string CoverFileData { get; set; } + public string CoverFileName { get; set; } + public long? CoverFileSize { get; set; } } diff --git a/NftFaucet/Models/TokenMetadata.cs b/NftFaucet/Models/TokenMetadata.cs index dfd8f14..5959e7c 100644 --- a/NftFaucet/Models/TokenMetadata.cs +++ b/NftFaucet/Models/TokenMetadata.cs @@ -13,6 +13,9 @@ public class TokenMetadata [JsonProperty("image")] public string Image { get; set; } + [JsonProperty("animation_url")] + public string AnimationUrl { get; set; } + [JsonProperty("external_url")] public string ExternalUrl { get; set; } } diff --git a/NftFaucet/Pages/CreateTokenDialog.razor b/NftFaucet/Pages/CreateTokenDialog.razor index d87b0d5..2c3fdf8 100644 --- a/NftFaucet/Pages/CreateTokenDialog.razor +++ b/NftFaucet/Pages/CreateTokenDialog.razor @@ -5,10 +5,22 @@
-

Image

- +

Main file

+
+ @if (!string.IsNullOrEmpty(Model.MainFileData) && !string.IsNullOrEmpty(Model.MainFileName) && Model.MainFileSize != null && Model.MainFileSize != 0) + { + var mainFileType = DetermineFileType(Model.MainFileName); + if (!mainFileType.StartsWith("image/") || mainFileType == "image/gif") + { +
+

Cover

+ +
+ } + } +

Name

diff --git a/NftFaucet/Pages/CreateTokenDialog.razor.cs b/NftFaucet/Pages/CreateTokenDialog.razor.cs index b8801f9..707faa3 100644 --- a/NftFaucet/Pages/CreateTokenDialog.razor.cs +++ b/NftFaucet/Pages/CreateTokenDialog.razor.cs @@ -2,6 +2,7 @@ using MimeTypes; using NftFaucet.Components; using NftFaucet.Models; using NftFaucet.Plugins; +using Radzen; namespace NftFaucet.Pages; @@ -21,14 +22,28 @@ public partial class CreateTokenDialog : BasicComponent Name = Model.Name, Description = Model.Description, CreatedAt = DateTime.Now, - Image = new TokenMedia + MainFile = new TokenMedia { - FileName = Model.FileName, - FileType = DetermineFileType(Model.FileName), - FileData = Model.FileData, - FileSize = Model.FileSize!.Value, + FileName = Model.MainFileName, + FileType = DetermineFileType(Model.MainFileName), + FileData = Model.MainFileData, + FileSize = Model.MainFileSize!.Value, }, }; + + if (!string.IsNullOrEmpty(Model.CoverFileData) && + !string.IsNullOrEmpty(Model.CoverFileName) && + Model.CoverFileSize != null) + { + token.CoverFile = new TokenMedia + { + FileName = Model.CoverFileName, + FileType = DetermineFileType(Model.CoverFileName), + FileData = Model.CoverFileData, + FileSize = Model.CoverFileSize!.Value, + }; + } + DialogService.Close(token); } @@ -51,15 +66,34 @@ public partial class CreateTokenDialog : BasicComponent if (string.IsNullOrWhiteSpace(Model.Description)) return false; - if (string.IsNullOrEmpty(Model.FileData)) + if (string.IsNullOrEmpty(Model.MainFileData)) return false; - if (string.IsNullOrEmpty(Model.FileName)) + if (string.IsNullOrEmpty(Model.MainFileName)) return false; - if (Model.FileSize is null or 0) + if (Model.MainFileSize is null or 0) return false; return true; } + + private void OnMainFileError(UploadErrorEventArgs args) + { + NotificationService.Notify(NotificationSeverity.Error, "File selection error", args.Message); + Model.MainFileData = null; + Model.MainFileName = null; + Model.MainFileSize = null; + Model.CoverFileData = null; + Model.CoverFileName = null; + Model.CoverFileSize = null; + } + + private void OnCoverFileError(UploadErrorEventArgs args) + { + NotificationService.Notify(NotificationSeverity.Error, "File selection error", args.Message); + Model.CoverFileData = null; + Model.CoverFileName = null; + Model.CoverFileSize = null; + } } diff --git a/NftFaucet/Pages/CreateUploadDialog.razor.cs b/NftFaucet/Pages/CreateUploadDialog.razor.cs index 88cb5d7..7e1a94b 100644 --- a/NftFaucet/Pages/CreateUploadDialog.razor.cs +++ b/NftFaucet/Pages/CreateUploadDialog.razor.cs @@ -74,24 +74,38 @@ public partial class CreateUploadDialog : BasicComponent IsUploading = true; RefreshMediator.NotifyStateHasChangedSafe(); - var imageLocationResult = await SelectedUploader.Upload(Token.Image.FileName, Token.Image.FileType, Base64DataToBytes(Token.Image.FileData)); - if (imageLocationResult.IsFailure) + var mainFileLocationResult = await SelectedUploader.Upload(Token.MainFile.FileName, Token.MainFile.FileType, Base64DataToBytes(Token.MainFile.FileData)); + if (mainFileLocationResult.IsFailure) { IsUploading = false; RefreshMediator.NotifyStateHasChangedSafe(); - NotificationService.Notify(NotificationSeverity.Error, "Uploading image failed", imageLocationResult.Error); + NotificationService.Notify(NotificationSeverity.Error, "Failed to upload main file", mainFileLocationResult.Error); return; } + var mainFileLocation = mainFileLocationResult.Value; - var imageLocation = imageLocationResult.Value; - var tokenMetadata = GenerateTokenMetadata(Token, imageLocation); + Uri coverFileLocation = null; + if (Token.CoverFile != null) + { + var coverFileLocationResult = await SelectedUploader.Upload(Token.CoverFile.FileName, Token.CoverFile.FileType, Base64DataToBytes(Token.CoverFile.FileData)); + if (coverFileLocationResult.IsFailure) + { + IsUploading = false; + RefreshMediator.NotifyStateHasChangedSafe(); + NotificationService.Notify(NotificationSeverity.Error, "Failed to upload cover file", coverFileLocationResult.Error); + return; + } + coverFileLocation = coverFileLocationResult.Value; + } + + var tokenMetadata = GenerateTokenMetadata(Token, mainFileLocation, coverFileLocation); var tokenMetadataBytes = Encoding.UTF8.GetBytes(tokenMetadata); var tokenLocationResult = await SelectedUploader.Upload($"{Token.Id}.json", "application/json", tokenMetadataBytes); if (tokenLocationResult.IsFailure) { IsUploading = false; RefreshMediator.NotifyStateHasChangedSafe(); - NotificationService.Notify(NotificationSeverity.Error, "Uploading metadata failed", tokenLocationResult.Error); + NotificationService.Notify(NotificationSeverity.Error, "Failed to upload metadata", tokenLocationResult.Error); return; } @@ -117,13 +131,14 @@ public partial class CreateUploadDialog : BasicComponent return Convert.FromBase64String(encoded); } - private static string GenerateTokenMetadata(IToken token, Uri imageLocation) + private static string GenerateTokenMetadata(IToken token, Uri mainFileLocation, Uri coverFileLocation) { var tokenMetadata = new TokenMetadata { Name = token.Name, Description = token.Description, - Image = imageLocation.OriginalString, + Image = coverFileLocation != null ? coverFileLocation.OriginalString : mainFileLocation.OriginalString, + AnimationUrl = coverFileLocation != null ? mainFileLocation.OriginalString : null, ExternalUrl = "https://darkcodi.github.io/nft-faucet/", }; var metadataJson = JsonConvert.SerializeObject(tokenMetadata, Formatting.Indented); diff --git a/NftFaucet/Pages/TokensPage.razor.cs b/NftFaucet/Pages/TokensPage.razor.cs index 4de9d59..9445139 100644 --- a/NftFaucet/Pages/TokensPage.razor.cs +++ b/NftFaucet/Pages/TokensPage.razor.cs @@ -21,25 +21,36 @@ public partial class TokensPage : BasicComponent } private CardListItem MapCardListItem(IToken token) - => new CardListItem + { + var properties = new List + { + new CardListItemProperty + { + Name = "Description", + Value = token.Description, + }, + }; + properties.Add(new CardListItemProperty + { + Name = token.CoverFile == null ? "Size" : "MF Size", + Value = ByteSize.FromBytes(token.MainFile.FileSize).ToString(), + }); + if (token.CoverFile != null) + { + properties.Add(new CardListItemProperty + { + Name = "CF Size", + Value = ByteSize.FromBytes(token.CoverFile.FileSize).ToString(), + }); + } + return new CardListItem { Id = token.Id, Header = token.Name, - ImageLocation = token.Image.FileData, - Properties = new[] - { - new CardListItemProperty - { - Name = "Description", - Value = token.Description, - }, - new CardListItemProperty - { - Name = "Size", - Value = ByteSize.FromBytes(token.Image.FileSize).ToString(), - }, - }, + ImageLocation = token.CoverFile?.FileData ?? token.MainFile.FileData, + Properties = properties.ToArray(), }; + } private async Task OpenCreateTokenDialog() { diff --git a/NftFaucet/Plugins/IToken.cs b/NftFaucet/Plugins/IToken.cs index 740a91d..db02a95 100644 --- a/NftFaucet/Plugins/IToken.cs +++ b/NftFaucet/Plugins/IToken.cs @@ -6,5 +6,6 @@ public interface IToken public string Name { get; } public string Description { get; } public DateTime CreatedAt { get; } - public ITokenMedia Image { get; } + public ITokenMedia MainFile { get; } + public ITokenMedia CoverFile { get; } } diff --git a/NftFaucet/Plugins/Token.cs b/NftFaucet/Plugins/Token.cs index 08f4b72..232e2bc 100644 --- a/NftFaucet/Plugins/Token.cs +++ b/NftFaucet/Plugins/Token.cs @@ -6,5 +6,6 @@ public class Token : IToken public string Name { get; set; } public string Description { get; set; } public DateTime CreatedAt { get; set; } = DateTime.Now; - public ITokenMedia Image { get; set; } + public ITokenMedia MainFile { get; set; } + public ITokenMedia CoverFile { get; set; } } diff --git a/NftFaucet/Program.cs b/NftFaucet/Program.cs index bcf2604..1beb50f 100644 --- a/NftFaucet/Program.cs +++ b/NftFaucet/Program.cs @@ -33,7 +33,7 @@ builder.Services.AddMetaMaskBlazor(); builder.Services.AddIndexedDB(dbStore => { dbStore.DbName = "NftFaucet"; - dbStore.Version = 1; + dbStore.Version = 2; dbStore.Stores.Add(new StoreSchema { @@ -60,10 +60,14 @@ builder.Services.AddIndexedDB(dbStore => new IndexSpec {Name = "name", KeyPath = "name", Auto = false}, new IndexSpec {Name = "description", KeyPath = "description", Auto = false}, new IndexSpec {Name = "createdAt", KeyPath = "createdAt", Auto = false}, - new IndexSpec {Name = "imageFileName", KeyPath = "imageFileName", Auto = false}, - new IndexSpec {Name = "imageFileType", KeyPath = "imageFileType", Auto = false}, - new IndexSpec {Name = "imageFileData", KeyPath = "imageFileData", Auto = false}, - new IndexSpec {Name = "imageFileSize", KeyPath = "imageFileSize", Auto = false}, + new IndexSpec {Name = "mainFileName", KeyPath = "mainFileName", Auto = false}, + new IndexSpec {Name = "mainFileType", KeyPath = "mainFileType", Auto = false}, + new IndexSpec {Name = "mainFileData", KeyPath = "mainFileData", Auto = false}, + new IndexSpec {Name = "mainFileSize", KeyPath = "mainFileSize", Auto = false}, + new IndexSpec {Name = "coverFileName", KeyPath = "coverFileName", Auto = false}, + new IndexSpec {Name = "coverFileType", KeyPath = "coverFileType", Auto = false}, + new IndexSpec {Name = "coverFileData", KeyPath = "coverFileData", Auto = false}, + new IndexSpec {Name = "coverFileSize", KeyPath = "coverFileSize", Auto = false}, } }); diff --git a/NftFaucet/Services/Mapper.cs b/NftFaucet/Services/Mapper.cs index fa4a1c8..f72e8e2 100644 --- a/NftFaucet/Services/Mapper.cs +++ b/NftFaucet/Services/Mapper.cs @@ -25,10 +25,14 @@ public class Mapper Name = token.Name, Description = token.Description, CreatedAt = token.CreatedAt, - ImageFileName = token.Image?.FileName, - ImageFileType = token.Image?.FileType, - ImageFileData = token.Image?.FileData, - ImageFileSize = token.Image?.FileSize, + MainFileName = token.MainFile?.FileName, + MainFileType = token.MainFile?.FileType, + MainFileData = token.MainFile?.FileData, + MainFileSize = token.MainFile?.FileSize, + CoverFileName = token.CoverFile?.FileName, + CoverFileType = token.CoverFile?.FileType, + CoverFileData = token.CoverFile?.FileData, + CoverFileSize = token.CoverFile?.FileSize, }; public UploadLocationDto ToDto(ITokenUploadLocation uploadLocation) @@ -58,18 +62,25 @@ public class Mapper }; public IToken ToDomain(TokenDto tokenDto) - => tokenDto == null ? null : new Token + => tokenDto == null || string.IsNullOrEmpty(tokenDto.MainFileData) ? null : new Token { Id = tokenDto.Id, Name = tokenDto.Name, Description = tokenDto.Description, CreatedAt = tokenDto.CreatedAt, - Image = new TokenMedia + MainFile = new TokenMedia { - FileName = tokenDto.ImageFileName, - FileType = tokenDto.ImageFileType, - FileData = tokenDto.ImageFileData, - FileSize = tokenDto.ImageFileSize ?? 0, + FileName = tokenDto.MainFileName, + FileType = tokenDto.MainFileType, + FileData = tokenDto.MainFileData, + FileSize = tokenDto.MainFileSize ?? 0, + }, + CoverFile = string.IsNullOrEmpty(tokenDto.CoverFileData) ? null : new TokenMedia + { + FileName = tokenDto.CoverFileName, + FileType = tokenDto.CoverFileType, + FileData = tokenDto.CoverFileData, + FileSize = tokenDto.CoverFileSize ?? 0, }, }; diff --git a/NftFaucet/Services/StateRepository.cs b/NftFaucet/Services/StateRepository.cs index 1be8080..71bf793 100644 --- a/NftFaucet/Services/StateRepository.cs +++ b/NftFaucet/Services/StateRepository.cs @@ -76,7 +76,7 @@ public class StateRepository if (existingTokens == null || existingTokens.Count == 0) return Array.Empty(); - return existingTokens.Select(_mapper.ToDomain).ToArray(); + return existingTokens.Select(_mapper.ToDomain).Where(x => x != null).ToArray(); } public async Task SaveUploadLocation(ITokenUploadLocation uploadLocation) From dc679a7dc1d2cbb8629954c9dc3b4c5fd44eb361 Mon Sep 17 00:00:00 2001 From: Ivan Yaremenchuk Date: Fri, 30 Sep 2022 04:58:21 -0500 Subject: [PATCH 2/3] Update Radzen package --- NftFaucet/NftFaucet.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NftFaucet/NftFaucet.csproj b/NftFaucet/NftFaucet.csproj index 9014c70..1b4b8e3 100644 --- a/NftFaucet/NftFaucet.csproj +++ b/NftFaucet/NftFaucet.csproj @@ -18,7 +18,7 @@ - + From f7ed2e3fd433c608e3dc32077a60423dc808f669 Mon Sep 17 00:00:00 2001 From: Ivan Yaremenchuk Date: Fri, 30 Sep 2022 04:58:38 -0500 Subject: [PATCH 3/3] Add required marking to TokenUpload dialog --- NftFaucet/Pages/CreateTokenDialog.razor | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NftFaucet/Pages/CreateTokenDialog.razor b/NftFaucet/Pages/CreateTokenDialog.razor index 2c3fdf8..0490170 100644 --- a/NftFaucet/Pages/CreateTokenDialog.razor +++ b/NftFaucet/Pages/CreateTokenDialog.razor @@ -5,7 +5,7 @@
-

Main file

+ Main file *
@@ -15,19 +15,19 @@ if (!mainFileType.StartsWith("image/") || mainFileType == "image/gif") {
-

Cover

+ Cover file
} }
-

Name

+ Name *
-

Description

+ Description *