Compare commits

...

7 Commits

16 changed files with 140 additions and 381 deletions

View File

@ -31,35 +31,8 @@ public class ContactController : Controller
return RedirectToPage("/Contact/Index");
}
[HttpPost("privacy-policy")]
public async Task<IActionResult> HandlePrivacyPolicy()
{
if (!Request.HasFormContentType)
{
return RedirectToPage("/Contact/Privacy");
}
IFormCollection form = Request.Form;
StringValues name = form["name"];
StringValues email = form["email"];
StringValues subject = form["subject"];
StringValues message = form["message"];
StringValues privacyPolicy = form["privacy-policy"];
await using SmtpSender sender = CreateSender();
await sender.WriteEmail
.To("Oliver Booth", _destination.GetValue<string>("PrivacyPolicy"))
.From(name, email)
.Subject($"[{privacyPolicy}] {subject}")
.BodyHtml(message)
.SendAsync();
TempData["Success"] = true;
return RedirectToPage("/Contact/Result");
}
[HttpPost("other")]
public async Task<IActionResult> HandleMiscellaneous()
public async Task<IActionResult> HandleForm()
{
if (!Request.HasFormContentType)
{
@ -73,12 +46,21 @@ public class ContactController : Controller
StringValues message = form["message"];
await using SmtpSender sender = CreateSender();
await sender.WriteEmail
.To("Oliver Booth", _destination.GetValue<string>("Other"))
.From(name, email)
.Subject(subject)
.BodyHtml(message)
.SendAsync();
try
{
await sender.WriteEmail
.To("Oliver Booth", _destination.Get<string>())
.From(name, email)
.Subject($"[Contact via Website] {subject}")
.BodyText(message)
.SendAsync();
}
catch (Exception e)
{
_logger.LogError(e, "Failed to send email");
TempData["Success"] = false;
return RedirectToPage("/Contact/Result");
}
TempData["Success"] = true;
return RedirectToPage("/Contact/Result");

View File

@ -4,13 +4,34 @@
}
<h1 class="display-4">Contact</h1>
<p class="lead">What would you like to talk about?</p>
<ul class="contact-reasons">
<li><a asp-page="JobOpportunity">💼 Job opportunity / collaboration</a></li>
<li><a asp-page="/Donate">☕ Donate money for coffee</a></li>
<li><a asp-page="ProjectIdea">💡 Project idea</a></li>
<li><a asp-page="TechnicalHelp">💬️ Technical help and code review</a></li>
<li><a asp-page="OpenSource">🌍 Open source contribution</a></li>
<li><a asp-page="Privacy">🔒 Privacy policy concerns</a></li>
<li><a asp-page="Other">❓ Misc / general inquiry</a></li>
</ul>
<p>
Thanks for getting in touch! While I do my best to read to all inquiries, I cannot guarantee that I will be able to
respond to your message. Nevertheless, I appreciate you taking the time to reach out to me and I will respond if I
can.
</p>
<form method="post" asp-controller="Contact" asp-action="HandleForm">
<input type="hidden" name="contact-type" value="other">
<div class="form-group" style="margin-top: 10px;">
<label for="name">Your Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Who are you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="email">Your Email Address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="How can I reach you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="subject">Subject</label>
<input type="text" class="form-control" id="subject" name="subject" placeholder="What's the gist?" maxlength="100" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="message">Message</label>
<textarea class="form-control" id="message" name="message" rows="5" required placeholder="What's on your mind?"></textarea>
</div>
<button class="btn btn-primary" style="margin-top: 10px;">Submit</button>
</form>

View File

@ -1,56 +0,0 @@
@page "/contact/job-opportunity"
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Job Opportunity</li>
</ol>
</nav>
<p>
I am always open to hearing about future opportunities. If you have a position you think I could be a good fit for,
please feel free to contact me using the form below. At this time, I am only open to positions based in South East
Wales or that are 100% remote.
</p>
<p>I look forward to hearing from you!</p>
<form method="post">
<input type="hidden" name="contact-type" value="job-opportunity">
<div class="form-group" style="margin-top: 10px;">
<label for="name">Your Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Who are you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="email">Your Email Address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="How can I reach you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="company-name">Company Name</label>
<input type="text" class="form-control" id="company-name" name="company-name" placeholder="Who do you represent?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="position-title">Job Position Title</label>
<input type="text" class="form-control" id="position-title" name="position-title" placeholder="e.g. C# Software Developer" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="position-description">Description</label>
<textarea class="form-control" id="position-description" name="position-description" rows="5" required placeholder="Explain the duties of the role and a bit about the company."></textarea>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="starting-salary">Starting Salary</label>
<input type="text" class="form-control" id="starting-salary" name="starting-salary" placeholder="e.g. £30,000" required>
</div>
<button type="submit" class="btn btn-primary" style="margin-top: 10px;">Submit</button>
</form>

View File

@ -1,35 +0,0 @@
@page "/contact/open-source"
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Open Source Contribution</li>
</ol>
</nav>
<p>
Thank you for taking the time to consider contributing to one of my open source projects. I appreciate any and all
contributions that I receive. You do not need to contact me to do so, just submit a pull request on GitHub and I
will review it as soon as I can!
</p>
<p>
Below is a <mark>non-exhaustive</mark> list of the repositories that are currently active. This list is subject
to change at any time, but may not be up-to-date. For a better gauge of what I am currently working on, please
visit my <a href="https://github.com/oliverbooth">GitHub profile</a>. If you would like to contribute to a project
that is not in active development, I would recommend that you fork the repository and continue development on your
own as unfortunately I have no timeline as to when I will start such projects back up again.
</p>
<ul>
<li>
<a href="https://github.com/oliverbooth/X10D">X10D</a>
</li>
<li>
<a href="https://github.com/BrackeysBot/">BrackeysBot</a>
</li>
</ul>

View File

@ -1,45 +0,0 @@
@page
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Other</li>
</ol>
</nav>
<p>
Thanks for getting in touch! While I do my best to read to all inquiries, I cannot guarantee that I will be able to
respond to your message. Nevertheless, I appreciate you taking the time to reach out to me and I will respond if I
can.
</p>
<form method="post" asp-controller="Contact" asp-action="HandleMiscellaneous">
<input type="hidden" name="contact-type" value="other">
<div class="form-group" style="margin-top: 10px;">
<label for="name">Your Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Who are you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="email">Your Email Address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="How can I reach you?" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="subject">Subject</label>
<input type="text" class="form-control" id="subject" name="subject" placeholder="What's the gist?" maxlength="100" required>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="message">Message</label>
<textarea class="form-control" id="message" name="message" rows="5" required placeholder="What's on your mind?"></textarea>
</div>
<button class="btn btn-primary" style="margin-top: 10px;">Submit</button>
</form>

View File

@ -1,53 +0,0 @@
@page "/contact/privacy/{which?}"
@model OliverBooth.Pages.Contact.Privacy
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Privacy Policy Concerns</li>
</ol>
</nav>
<p>
Thank you for getting in touch. I take your privacy very seriously and will do my best to address any concerns you may have.
Please outline your concerns in the form below, and I will get back to you as soon as possible.
</p>
<form method="post" asp-controller="Contact" asp-action="HandlePrivacyPolicy">
<input type="hidden" name="contact-type" value="privacy-policy">
<div class="form-group" style="margin-top: 10px;">
<label for="name">Your Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Who are you?">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="email">Your Email Address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="How can I reach you?">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="privacy-policy">Privacy Policy</label>
<select name="privacy-policy" class="form-control" id="privacy-policy">
<option value="website" selected="@(Model.Which != "google-play")">This website's policy</option>
<option value="google-play" selected="@(Model.Which == "google-play")">Google Play policy</option>
</select>
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="subject">Subject</label>
<input type="text" class="form-control" id="subject" name="subject" placeholder="Describe your concerns here in a few words" maxlength="100">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="message">Description</label>
<textarea class="form-control" id="message" name="message" rows="5" required placeholder="Go into detail about the nature of your concerns."></textarea>
</div>
<button type="submit" class="btn btn-primary" style="margin-top: 10px;">Submit</button>
</form>

View File

@ -1,17 +0,0 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace OliverBooth.Pages.Contact;
public class Privacy : PageModel
{
public string Which { get; private set; } = "website";
public void OnGet(string? which = "website")
{
Which = which ?? "website";
}
public void SubmitForm()
{
}
}

View File

@ -1,70 +0,0 @@
@page "/contact/project-idea"
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Project Idea</li>
</ol>
</nav>
<p>
If you have any ideas for a project that you'd like to see me work on, please feel free to contact me using the
form below. I'm always looking for something new to work on, and I'm open to suggestions!
</p>
<div class="alert alert-warning">
<p>
Please note that by submitting an idea through the form on this page, you acknowledge and agree that any
intellectual property rights associated with the idea, including but not limited to copyright, patent, or any
other proprietary rights, shall be immediately and irrevocably transferred to me. You understand that this
transfer of intellectual property rights grants me the unrestricted and exclusive right to use, modify,
reproduce, distribute, disclose, or otherwise exploit the idea for any purpose, without the obligation to
provide credit or compensation to you. This includes the right to file for intellectual property protection or
pursue commercial opportunities derived from the idea. By submitting the idea, you further confirm that it is
your original work and does not infringe upon the rights of any third party.
</p>
<p>
<strong>
If this is not something you want, and you'd like to collaborate, please
<span style="text-decoration: underline">do not</span> use this form, instead, please use
<a asp-page="JobOpportunity">this one</a>.
</strong>
</p>
</div>
<form method="post">
<input type="hidden" name="contact-type" value="project-idea">
<div class="form-group" style="margin-top: 10px;">
<label for="name">Your Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Who are you?">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="email">Your Email Address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="How can I reach you, if I need to?">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="project-title">Project Title (If Applicable)</label>
<input type="text" class="form-control" id="project-title" name="project-title" placeholder="Title">
</div>
<div class="form-group" style="margin-top: 10px;">
<label for="project-description">Project Description</label>
<textarea class="form-control" id="project-description" name="project-description" rows="5" required placeholder="Explain the idea here"></textarea>
</div>
<div class="form-check" style="margin-top: 10px;">
<input class="form-check-input" type="checkbox" id="agreement-checkbox" name="agreement-checkbox" required>
<label class="form-check-label" for="agreement-checkbox">
I acknowledge and agree to the transfer of intellectual property rights as described above.
</label>
</div>
<button type="submit" class="btn btn-primary" style="margin-top: 10px;">Submit</button>
</form>

View File

@ -17,7 +17,7 @@
else
{
<h1 class="display-4 text-danger"><i class="fa-solid fa-circle-xmark"></i> A problem occured</h1>
<p>Sorry, something went wrong. This has been logged and if I'll get to it soon.</p>
<p>Sorry, something went wrong. This has been logged and if it's a problem on my end, I'll get to it soon.</p>
<p>
You can <a asp-page="Index">try again</a>, or check out my <a asp-page="/Blog/Index">blog</a> or
<a asp-page="/Projects/Index">portfolio</a>!

View File

@ -1,25 +0,0 @@
@page "/contact/technical-help"
@{
ViewData["Title"] = "Contact";
}
<nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a asp-page="Index">Contact</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Technical Help</li>
</ol>
</nav>
<p>
I'm sorry, but do I not offer help or advice regarding development of any kind outside of my website, and Discord
servers of which I'm a member. I'm most active in the <a href="https://discord.gg/brackeys">Brackeys Community</a>
Discord server, where I'm an Admin, but this does not give you permission to demand help from me on your schedule.
If you have a question, please ask in the appropriate channel in that server. If you ping or DM me, I will ignore
you.
</p>
<p>
I do not offer services to build or repair desktops, laptops, mobiles, or tablets, outside of my family and close
friends.
</p>

View File

@ -1,26 +1,34 @@
@page "/error/{code:int?}"
@model OliverBooth.Pages.ErrorModel
@{
Layout = "_MinimalLayout";
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error @(Model.StatusCode != 200 ? Model.StatusCode.ToString() : "")</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h2 class="text-danger">
@switch (Model.HttpStatusCode)
{
case 403:
<span>403 Forbidden</span>
break;
case 404:
<span>404 Page not found</span>
break;
case 500:
<span>Internal server error</span>
break;
default:
<span>Something went wrong</span>
break;
}
</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays 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>
}

View File

@ -8,28 +8,21 @@ namespace OliverBooth.Pages;
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public int StatusCode { get; private set; }
public int HttpStatusCode { get; private set; }
public void OnGet(int? code = null)
public IActionResult OnGet(int? code = null)
{
StatusCode = code ?? HttpContext.Response.StatusCode;
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
var originalPath = "unknown";
if (HttpContext.Items.TryGetValue("originalPath", out object? value))
HttpStatusCode = code ?? HttpContext.Response.StatusCode;
if (HttpStatusCode == 200)
{
originalPath = value as string;
return RedirectToPage("/Index");
}
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
return Page();
}
}

View File

@ -88,12 +88,18 @@
<footer class="footer text-muted">
<div class="container text-center">
<hr>
<ul class="footer-nav">
<li><a title="@("@oliver@mastodon.olivr.me")" href="https://mastodon.olivr.me/@@oliver" rel="me" class="brand-mastodon"><i class="fa-brands fa-mastodon"></i></a></li>
<li><a title="LinkedIn/oliverlukebooth" href="https://www.linkedin.com/in/oliverlukebooth/" class="brand-linkedin"><i class="fa-brands fa-linkedin"></i></a></li>
<li><a title="Blog RSS Feed" asp-controller="Rss" asp-action="OnGet"><i class="fa-solid fa-rss text-orange"></i></a></li>
<li><a title="View Source" href="https://git.oliverbooth.dev/oliverbooth/oliverbooth.dev"><i class="fa-solid fa-code"></i></a></li>
</ul>
<ul class="footer-nav" style="margin-top: 20px;">
<li>&copy; @DateTime.UtcNow.Year</li>
<li><a asp-page="/privacy/index">Privacy</a></li>
<li><a href="https://mastodon.olivr.me/@@oliver" rel="me" class="brand-mastodon"><i class="fa-brands fa-mastodon"></i></a></li>
<li><a href="https://www.linkedin.com/in/oliverlukebooth/" class="brand-linkedin"><i class="fa-brands fa-linkedin"></i></a></li>
<li><a asp-controller="Rss" asp-action="OnGet"><i class="fa-solid fa-rss text-orange"></i></a></li>
</ul>
</div>
</footer>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="dark">
<meta name="theme-color" content="#121212">
<title>Oliver Booth</title>
<link rel="shortcut icon" href="/img/favicon.png" asp-append-version="true">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/css/bootstrap.min.css" integrity="sha512-Z/def5z5u2aR89OuzYcxmDJ0Bnd5V1cKqBEbvLOiUNWdg9PQeXVvXLI90SE4QOHGlfLqUnDNVAYyZi8UwUTmWQ==" crossorigin="anonymous" referrerpolicy="no-referrer">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.css" integrity="sha512-7nTa5CnxbzfQgjQrNmHXB7bxGTUVO/DcYX6rpgt06MkzM0rVXP3EYCv/Ojxg5H0dKbY7llbbYaqgfZjnGOAWGA==" crossorigin="anonymous" referrerpolicy="no-referrer">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css" integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA==" crossorigin="anonymous" referrerpolicy="no-referrer">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" integrity="sha512-c42qTSw/wPZ3/5LBzD+Bw5f7bSF2oxou6wEb+I/lqeaKV5FDIfMvvRp772y4jcJLKuGUOpbJMdg/BTl50fJYAw==" crossorigin="anonymous" referrerpolicy="no-referrer">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@100;400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="~/css/prism.min.css" asp-append-version="true">
<link rel="stylesheet" href="~/css/prism.vs.min.css" asp-append-version="true">
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true">
</head>
<body>
<header class="container" style="margin-top: 20px;">
<div id="site-title" class="text-center">
<h1>
<a href="/"><img src="~/img/ob-256x256.png" alt="Oliver Booth" height="128"> Oliver Booth</a>
</h1>
</div>
</header>
<div style="margin:50px 0;"></div>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/js/bootstrap.bundle.min.js" integrity="sha512-ToL6UYWePxjhDQKNioSi4AyJ5KkRxY+F1+Fi7Jgh0Hp5Kk2/s8FD7zusJDdonfe5B00Qw+B8taXxF6CFLnqNCw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.8/katex.min.js" integrity="sha512-aoZChv+8imY/U1O7KIHXvO87EOzCuKO0GhFtpD6G2Cyjo/xPeTgdf3/bchB10iB+AojMTDkMHDPLKNxPJVqDcw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/js/all.min.js" integrity="sha512-uKQ39gEGiyUJl4AI6L+ekBdGKpGw4xJ55+xyJG7YFlJokPNYegn9KwQ3P8A7aFQAUtUsAQHep+d/lrGqrbPIDQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js" integrity="sha512-E1dSFxg+wsfJ4HKjutk/WaCzK7S2wv1POn1RRPGh8ZK+ag9l244Vqxji3r6wgz9YBf6+vhQEYJZpSjqWFPg9gg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="~/js/prism.min.js" asp-append-version="true" data-manual></script>
<script src="~/js/app.min.js" asp-append-version="true"></script>
<script id="loading-spinner-template" type="text/x-handlebars-template">
@await Html.PartialAsync("_LoadingSpinner")
</script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@ -54,6 +54,7 @@ if (!app.Environment.IsDevelopment())
}
app.UseHttpsRedirection();
app.UseStatusCodePagesWithRedirects("/error/{0}");
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

View File

@ -1,8 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Markdig;
using Markdig.Parsers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
using Microsoft.EntityFrameworkCore;
using OliverBooth.Data.Web;