Polish facelift forms and clean package warnings

This commit is contained in:
nick 2026-07-31 21:36:05 +01:00
parent 8cca5ee347
commit 9a3bf18a31
8 changed files with 249 additions and 12 deletions

View File

@ -154,7 +154,7 @@
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="3.0.10" />
<PackageReference Include="MailKit" Version="4.15.1" />
<PackageReference Include="MailKit" Version="4.17.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" />
<PackageReference Include="Microsoft.Web.Administration" Version="11.1.0" />
<PackageReference Include="NAudio" Version="2.3.0" />
@ -164,7 +164,6 @@
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageReference Include="System.Drawing.Common" Version="10.0.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="WebMarkupMin.AspNetCoreLatest" Version="2.21.0" />
</ItemGroup>

View File

@ -95,8 +95,15 @@ namespace CatherineLynwood.Controllers
[Route("contact-catherine")]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ContactCatherine(Contact contact)
{
if (IsLikelySpamContact(contact))
{
_logger.LogInformation("Discarded likely spam contact submission.");
return RedirectToAction("ThankYou");
}
if (ModelState.IsValid)
{
await _dataAccess.SaveContact(contact, false);
@ -113,6 +120,29 @@ namespace CatherineLynwood.Controllers
return View(contact);
}
private bool IsLikelySpamContact(Contact contact)
{
var form = Request.HasFormContentType ? Request.Form : null;
var website = form?["Website"].ToString();
if (!string.IsNullOrWhiteSpace(website))
{
return true;
}
if (long.TryParse(form?["ContactStartedAt"].ToString(), out var startedAt))
{
var elapsedSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - startedAt;
if (elapsedSeconds >= 0 && elapsedSeconds < 4)
{
return true;
}
}
var message = contact.Message ?? string.Empty;
var linkCount = System.Text.RegularExpressions.Regex.Matches(message, @"https?://|www\.", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Count;
return linkCount > 2;
}
[Route("feed.xml")]
[Route("rss.xml")]
[Route("rss")]
@ -338,4 +368,4 @@ namespace CatherineLynwood.Controllers
#endregion Private Methods
}
}
}

View File

@ -21,7 +21,7 @@
Birmingham-born author of gritty, emotionally truthful fiction about women, survival, family secrets, and the fire people carry after everything else has been stripped away.
</p>
</div>
<div class="float-md-start w-md-50 p-3">
<div class="float-md-start w-md-50 p-3 cl-about-portrait">
<figure>
<responsive-image src="catherine-lynwood-15.png" alt="Catherine Lynwood" class="img-fluid rounded-5 border border-3 border-dark shadow-lg" display-width-percentage="50"></responsive-image>
<figcaption>Catherine Lynwood</figcaption>

View File

@ -17,7 +17,13 @@
<div class="row justify-content-center">
<div class="col-md-6">
<form asp-action="ContactCatherine" method="post" onsubmit="disableSubmit(this)">
<form asp-action="ContactCatherine" method="post" onsubmit="disableSubmit(this)" class="cl-contact-form">
@Html.AntiForgeryToken()
<input type="hidden" name="ContactStartedAt" value="@DateTimeOffset.UtcNow.ToUnixTimeSeconds()" />
<div class="cl-honeypot" aria-hidden="true">
<label for="Website">Website</label>
<input id="Website" name="Website" type="text" tabindex="-1" autocomplete="off" />
</div>
<div class="col-12 col-sm-8 col-md-12">
<h1>Contact Catherine</h1>
<p>I would love to hear your thoughts regarding my work. Please feel free to contact me and I will try my best to reply as soon as I can.</p>
@ -75,4 +81,4 @@
}
</script>
}
}

View File

@ -31,8 +31,8 @@
</section>
<div class="row justify-content-center p-3">
<div class="col-12 bg-white rounded-5">
<audio controls>
<div class="col-12 bg-white rounded-5 cl-audio-panel">
<audio controls preload="metadata" class="w-100">
<source src="/audio/samantha-lynwood.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
@ -72,4 +72,4 @@
"knowsAbout": ["fiction writing", "mystery novels", "family drama"]
}
</script>
}
}

View File

@ -43,7 +43,7 @@
}
<form asp-action="Comment" class="row" id="comment" onsubmit="disableSubmit(this)">
<form asp-action="Comment" class="row cl-comment-form" id="comment" onsubmit="disableSubmit(this)">
<div class="col-12 pb-3">
<h2>Leave a Comment</h2>
In invite you to leave comments regarding this blog post. As you can see I ask that you give me your name and email address, as well as your age and sex.
@ -160,4 +160,4 @@
agreeCheckbox.focus(); // Focus on checkbox
});
});
</script>
</script>

View File

@ -1687,6 +1687,208 @@ body.cl-site-shell {
border-top-color: rgba(240, 208, 160, 0.36) !important;
}
/* Facelift refinement pass */
.cl-site-shell .card,
.cl-site-shell .character-card,
.cl-site-shell .accordion-item,
.cl-site-shell form.bg-white,
.cl-site-shell .modal-content,
.cl-site-shell .alert,
.cl-site-shell .bg-white,
.cl-site-shell .bg-light,
.cl-site-shell .cl-panel,
.cl-site-shell .cl-editorial-hero,
.cl-page-about section,
.cl-page-verostic section > .mb-4,
.cl-page-verostic section > .mb-5,
.cl-discovery-buy-intro,
.cl-discovery-buy-panel,
.cl-discovery-audio,
.cl-discovery-review,
.cl-discovery-chapter-grid article,
.cl-discovery-hero,
.cl-journal-filter {
border-radius: 8px !important;
border-color: rgba(240, 208, 160, 0.34) !important;
box-shadow:
0 1.35rem 3.2rem rgba(0, 0, 0, 0.44),
0 0 1.8rem rgba(201, 154, 115, 0.08),
inset 0 1px 0 rgba(255, 244, 223, 0.08),
inset 0 -1px 0 rgba(0, 0, 0, 0.26) !important;
}
.cl-site-shell .card:hover,
.cl-site-shell .cl-feature-card:hover,
.cl-discovery-chapter-grid article:hover {
border-color: rgba(240, 208, 160, 0.46) !important;
box-shadow:
0 1.55rem 3.7rem rgba(0, 0, 0, 0.5),
0 0 2.2rem rgba(201, 154, 115, 0.12),
inset 0 1px 0 rgba(255, 244, 223, 0.1),
inset 0 -1px 0 rgba(0, 0, 0, 0.28) !important;
}
.cl-site-shell .rounded-3,
.cl-site-shell .rounded-4,
.cl-site-shell .rounded-5 {
border-radius: 8px !important;
}
.cl-page-journal .pagination {
gap: 0.28rem;
flex-wrap: wrap;
}
.cl-page-journal .page-link {
min-width: 2.05rem;
color: #fff1d8 !important;
text-align: center;
background:
linear-gradient(145deg, rgba(84, 42, 31, 0.96), rgba(40, 19, 20, 0.96)) !important;
border: 1px solid rgba(240, 208, 160, 0.36) !important;
border-radius: 7px !important;
box-shadow: inset 0 1px 0 rgba(255, 244, 223, 0.08), 0 0.45rem 1rem rgba(0, 0, 0, 0.25);
}
.cl-page-journal .page-link:hover,
.cl-page-journal .page-link:focus {
color: #fff7ec !important;
background:
linear-gradient(145deg, rgba(123, 41, 67, 0.98), rgba(70, 28, 43, 0.98)) !important;
}
.cl-page-journal .page-item.active .page-link {
color: #24120f !important;
background: linear-gradient(145deg, #f0d0a0, #c99a73) !important;
border-color: rgba(255, 243, 223, 0.62) !important;
font-weight: 800;
}
.cl-page-journal .page-item.disabled .page-link {
color: rgba(240, 208, 160, 0.48) !important;
background: rgba(26, 13, 13, 0.72) !important;
}
.cl-about-portrait {
position: relative;
z-index: 3;
}
.cl-about-portrait figure {
margin: 0;
padding: 0.7rem;
background:
linear-gradient(145deg, rgba(255, 232, 194, 0.14), rgba(75, 24, 39, 0.12)),
rgba(18, 10, 10, 0.72);
border: 1px solid rgba(240, 208, 160, 0.34);
border-radius: 8px;
box-shadow: 0 1.5rem 3.5rem rgba(0, 0, 0, 0.48), 0 0 2rem rgba(201, 154, 115, 0.12);
}
.cl-about-portrait .img-fluid {
filter: none !important;
opacity: 1 !important;
}
.cl-about-portrait figcaption {
margin-top: 0.55rem;
color: rgba(240, 208, 160, 0.82);
text-align: center;
}
.cl-contact-form {
padding: clamp(1rem, 3vw, 2rem);
background:
linear-gradient(145deg, rgba(255, 233, 197, 0.11), rgba(79, 28, 42, 0.08)),
rgba(21, 13, 13, 0.68);
border: 1px solid rgba(240, 208, 160, 0.28);
border-radius: 8px;
box-shadow: 0 1.4rem 3.4rem rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.cl-contact-form .form-floating > label {
color: #5c3a25 !important;
font-weight: 650;
}
.cl-contact-form .form-control {
color: #2a1812;
background: linear-gradient(145deg, #f7ead5, #e5cda8);
border-color: rgba(240, 208, 160, 0.42);
}
.cl-contact-form .form-control:focus {
color: #21100d;
background: #fff1d8;
}
.cl-comment-form {
padding: clamp(1rem, 3vw, 2rem);
background:
linear-gradient(145deg, rgba(255, 233, 197, 0.11), rgba(79, 28, 42, 0.08)),
rgba(21, 13, 13, 0.68);
border: 1px solid rgba(240, 208, 160, 0.28);
border-radius: 8px;
box-shadow: 0 1.4rem 3.4rem rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.cl-comment-form .form-floating > label,
.cl-comment-form .form-check-label {
color: #5c3a25 !important;
font-weight: 650;
}
.cl-comment-form .form-control,
.cl-comment-form .form-select {
color: #2a1812;
background: linear-gradient(145deg, #f7ead5, #e5cda8);
border-color: rgba(240, 208, 160, 0.42);
}
.cl-comment-form .form-control:focus,
.cl-comment-form .form-select:focus {
color: #21100d;
background: #fff1d8;
}
.cl-comment-form .alert .form-check-label {
color: #fff0d9 !important;
}
.cl-honeypot {
position: absolute;
left: -10000px;
width: 1px;
height: 1px;
overflow: hidden;
}
.cl-audio-panel,
.audio-player,
.cl-site-shell .plyr--audio {
padding: 0.75rem;
background:
linear-gradient(145deg, rgba(255, 233, 197, 0.12), rgba(92, 32, 63, 0.12)),
rgba(21, 13, 13, 0.78) !important;
border: 1px solid rgba(240, 208, 160, 0.32);
border-radius: 8px;
box-shadow: 0 1rem 2.4rem rgba(0, 0, 0, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.cl-site-shell audio {
display: block;
width: 100%;
min-height: 46px;
filter: sepia(0.12) saturate(0.82) brightness(0.95);
}
.cl-site-shell .plyr--audio .plyr__controls {
color: #2a1812 !important;
background: linear-gradient(145deg, #fff1d8, #d7b982) !important;
border: 1px solid rgba(240, 208, 160, 0.45) !important;
border-radius: 7px !important;
}
@media (max-width: 991.98px) {
.cl-discovery-hero,
.cl-discovery-buy-shell,

File diff suppressed because one or more lines are too long