Replace ResultT with a tuple.

Result<T> is a fundamentally good idea, but just doesn't fit into bantflags properly. We don't implement the other functional extensions that would make it useful, and our use case is so small that the extra safety we get isn't worth the code complexity. It was just used as a wrapper around a tuple like (T thingWeVerifyAgainstBusinessLogic, bool failed, string errorMessage), and we can ignore the bool by using default and checking for null. Less code, easier to read.
dotnetflags
C-xC-c 5 years ago
parent 0d2551bc92
commit af65b7fd1d

@ -61,16 +61,16 @@ namespace BantFlags.Controllers
{ {
string splitFlag = (version ?? 0) > 1 ? "," : "||"; // comma for v2+, else || for backwards compatibility. string splitFlag = (version ?? 0) > 1 ? "," : "||"; // comma for v2+, else || for backwards compatibility.
Result<PostModel> post = PostModel.Create(post_nr, board, regions, splitFlag, Database.KnownFlags, Database.Boards); (PostModel flag, string error) = PostModel.Create(post_nr, board, regions, splitFlag, Database.KnownFlags, Database.Boards);
if (post.Failed) if (flag is null)
{ {
return Problem(post.ErrorMessage, statusCode: StatusCodes.Status400BadRequest); return Problem(error, statusCode: StatusCodes.Status400BadRequest);
} }
await Database.InsertPost(post.Value); await Database.InsertPost(flag);
return Ok(post.Value); return Ok(flag);
} }
/// <summary> /// <summary>

@ -22,31 +22,31 @@ namespace BantFlags.Data
Flags = flags; Flags = flags;
} }
public static Result<PostModel> Create(string post_nr, string board, string regions, string splitFlag, HashSet<string> knownFlags, HashSet<string> boards) public static (PostModel, string) Create(string post_nr, string board, string regions, string splitFlag, HashSet<string> knownFlags, HashSet<string> boards)
{ {
string[] empty = { "empty, or there were errors. Re-set your flags." }; string[] empty = { "empty, or there were errors. Re-set your flags." };
if (!int.TryParse(post_nr, out int postNumber)) if (!int.TryParse(post_nr, out int postNumber))
return Result<PostModel>.Fail("Invalid post number."); return (default, "Invalid post number.");
if (!boards.Contains(board)) if (!boards.Contains(board))
return Result<PostModel>.Fail("Invalid board parameter."); return (default, "Invalid board parameter.");
if (regions == null) if (regions == null)
return Result<PostModel>.Pass(new PostModel(postNumber, board, empty)); return (new PostModel(postNumber, board, empty), default);
var flags = regions.Split(splitFlag); var flags = regions.Split(splitFlag);
if (flags.Count() > 30) if (flags.Count() > 30)
return Result<PostModel>.Fail("Too many flags."); return (default, "Too many flags.");
foreach (string flag in flags) foreach (string flag in flags)
{ {
if (!knownFlags.Contains(flag)) // Not ideal but it's better than doing it in the controller or passing the database here. if (!knownFlags.Contains(flag)) // Not ideal but it's better than doing it in the controller or passing the database here.
return Result<PostModel>.Pass(new PostModel(postNumber, board, empty)); return (new PostModel(postNumber, board, empty), default);
} }
return Result<PostModel>.Pass(new PostModel(postNumber, board, flags)); return (new PostModel(postNumber, board, flags), default);
} }
} }
} }

@ -1,30 +0,0 @@
// (C) Copyright 2019 C-xC-c <boku@plum.moe>
// This file is part of BantFlags.
// BantFlags is licensed under the GNU AGPL Version 3.0 or later.
// see the LICENSE file or <https://www.gnu.org/licenses/>
using System;
namespace BantFlags.Data
{
public struct Result<T>
{
public bool Failed { get; private set; }
public string ErrorMessage { get; private set; }
private T _Value { get; set; }
public T Value => Failed ? throw new Exception() : _Value;
public Result(bool failed, string error, T value)
{
Failed = failed;
ErrorMessage = error;
_Value = value;
}
public static Result<T> Pass(T value) => new Result<T>(false, default, value);
public static Result<T> Fail(string error) => new Result<T>(true, error, default);
}
}

@ -68,35 +68,36 @@ namespace BantFlags.Data
FlagMethod = method; FlagMethod = method;
} }
public static Result<Flag> CreateFromDelete(string name) public static Flag CreateFromDelete(string name) => new Flag(name, Method.Delete); // We don't need any validation for deleted flags.
=> Result<Flag>.Pass(new Flag(name, Method.Delete)); // We don't need any validation for deleted flags.
public static Result<Flag> CreateFromRename(string oldName, string newName, HashSet<string> names) public static (Flag, string) CreateFromRename(string oldName, string newName, HashSet<string> names)
{ {
Result<string> fileName = ValidateFileName(newName, names); (bool valid, string error) = ValidateFileName(newName, names);
if (fileName.Failed) if (!valid)
return Result<Flag>.Fail(fileName.ErrorMessage); {
return (default, error);
}
return Result<Flag>.Pass(new Flag(newName, oldName, Method.Rename)); return (new Flag(newName, oldName, Method.Rename), default);
} }
public static async Task<Result<Flag>> CreateFromFile(IFormFile upload, HashSet<string> names) public static async Task<(Flag, string)> CreateFromFile(IFormFile upload, HashSet<string> names)
{ {
byte[] PNGHeader = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; byte[] PNGHeader = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
if (upload.ContentType.ToLower() != "image/png") if (upload.ContentType.ToLower() != "image/png")
return Result<Flag>.Fail("Image must be a png."); return (default, "Image must be a png.");
if (upload.Length > 15 * 1024) if (upload.Length > 15 * 1024)
return Result<Flag>.Fail("File too big. Max size is 15kb."); return (default, "File too big. Max size is 15kb.");
var name = Path.GetFileNameWithoutExtension(upload.FileName); var name = Path.GetFileNameWithoutExtension(upload.FileName);
Result<string> fileName = ValidateFileName(name, names); (bool valid, string error) = ValidateFileName(name, names);
if (fileName.Failed) if (!valid)
return Result<Flag>.Fail(fileName.ErrorMessage); return (default, error);
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
@ -106,7 +107,7 @@ namespace BantFlags.Data
using (var image = new MagickImage(memoryStream)) using (var image = new MagickImage(memoryStream))
{ {
if (image.Width != 16 || image.Height != 11) if (image.Width != 16 || image.Height != 11)
return Result<Flag>.Fail("Invalid image dimensions. Flags should be 16px by 11px."); return (default, "Invalid image dimensions. Flags should be 16px by 11px.");
} }
using (var reader = new BinaryReader(memoryStream)) using (var reader = new BinaryReader(memoryStream))
@ -114,11 +115,11 @@ namespace BantFlags.Data
reader.BaseStream.Position = 0; reader.BaseStream.Position = 0;
if (!reader.ReadBytes(PNGHeader.Length).SequenceEqual(PNGHeader)) if (!reader.ReadBytes(PNGHeader.Length).SequenceEqual(PNGHeader))
return Result<Flag>.Fail("Invalid png header."); return (default, "Invalid png header.");
} }
} }
return Result<Flag>.Pass(new Flag(name, Method.Add)); return (new Flag(name, Method.Add), default);
} }
/// <summary> /// <summary>
@ -126,24 +127,24 @@ namespace BantFlags.Data
/// </summary> /// </summary>
/// <param name="name">The file name to validate.</param> /// <param name="name">The file name to validate.</param>
/// <param name="names">The list of current file names.</param> /// <param name="names">The list of current file names.</param>
private static Result<string> ValidateFileName(string name, HashSet<string> names) private static (bool, string) ValidateFileName(string name, HashSet<string> names)
{ {
if (string.IsNullOrWhiteSpace(name)) if (string.IsNullOrWhiteSpace(name))
return Result<string>.Fail("Flag name can't be empty."); return (false, "Flag name can't be empty.");
if (name.Length > 100) if (name.Length > 100)
return Result<string>.Fail("Flag name too long."); return (false, "Flag name too long.");
if (name == "empty, or there were errors. Re - set your flags.") if (name == "empty, or there were errors. Re - set your flags.")
return Result<string>.Fail("Invalid flag name."); return (false, "Invalid flag name.");
if (name.Contains("||") || name.Contains(",")) if (name.Contains("||") || name.Contains(","))
return Result<string>.Fail("Flag name contains invalid characters. You can't use \"||\" or \",\"."); return (false, "Flag name contains invalid characters. You can't use \"||\" or \",\".");
if (names.Contains(name)) if (names.Contains(name))
return Result<string>.Fail("A flag with that name already exists."); return (false, "A flag with that name already exists.");
return Result<string>.Pass(name); return (true, name);
} }
} }
} }

@ -43,7 +43,7 @@ namespace BantFlags
public IActionResult OnPostDelete(string flag) public IActionResult OnPostDelete(string flag)
{ {
var stagingFlag = Flag.CreateFromDelete(flag).Value; var stagingFlag = Flag.CreateFromDelete(flag);
StagedFlags.Flags.Add(stagingFlag); StagedFlags.Flags.Add(stagingFlag);
StagedFlags.Names.Remove(stagingFlag.Name); StagedFlags.Names.Remove(stagingFlag.Name);
@ -54,28 +54,28 @@ namespace BantFlags
public IActionResult OnPostRename(string flag, string newName) public IActionResult OnPostRename(string flag, string newName)
{ {
var stagingFlag = Flag.CreateFromRename(flag, newName, AllNames); (Flag stagingFlag, string error) = Flag.CreateFromRename(flag, newName, AllNames);
if (stagingFlag.Failed) if (stagingFlag is null)
{ {
Message = stagingFlag.ErrorMessage; Message = error;
return Page(); return Page();
} }
StagedFlags.Flags.Add(stagingFlag.Value); StagedFlags.Flags.Add(stagingFlag);
StagedFlags.Names.Add(stagingFlag.Value.Name); StagedFlags.Names.Add(stagingFlag.Name);
Message = $"{stagingFlag.Value.OldName} renamed to {stagingFlag.Value.Name}."; Message = $"{stagingFlag.OldName} renamed to {stagingFlag.Name}.";
return Page(); return Page();
} }
public async Task<IActionResult> OnPostAddAsync(IFormFile upload, bool gloss) public async Task<IActionResult> OnPostAddAsync(IFormFile upload, bool gloss)
{ {
var stagingFlag = await Flag.CreateFromFile(upload, AllNames); (Flag stagingFlag, string error) = await Flag.CreateFromFile(upload, AllNames);
if (stagingFlag.Failed) if (stagingFlag is null)
{ {
Message = stagingFlag.ErrorMessage; Message = error;
return Page(); return Page();
} }
@ -98,9 +98,9 @@ namespace BantFlags
image.Write(WebRoot + "/flags/staging/" + upload.FileName); image.Write(WebRoot + "/flags/staging/" + upload.FileName);
StagedFlags.Flags.Add(stagingFlag.Value); StagedFlags.Flags.Add(stagingFlag);
Message = $"{stagingFlag.Value.Name} uploaded"; Message = $"{stagingFlag.Name} uploaded";
return Page(); return Page();
} }

Loading…
Cancel
Save