Compare commits
8 Commits
13ed2c1b13
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 742b5b52c7 | |||
| 4f6c18a1ac | |||
| ad6aab94a9 | |||
| 909e868001 | |||
| b590d3e859 | |||
| 7feb501bc2 | |||
| 38113310aa | |||
| 046f847b3d |
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -2,7 +2,7 @@
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"version": "0.2.0",
|
||||
"version": "1.0.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch (web)",
|
||||
@@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/bin/Debug/net6.0/contact.dll",
|
||||
"program": "${workspaceFolder}/bin/Debug/net10.0/contact.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
@page
|
||||
@page
|
||||
@model ContactModel
|
||||
@{
|
||||
ViewData["Title"] = "Contact";
|
||||
}
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
@if (Model.SendFailed)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
Sorry, your message could not be sent. Please try again in a few minutes,
|
||||
or email support@ayanova.com directly.
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="jumbotron text-center"
|
||||
style="background-image: url(images/jumbotronbackgroundABC.png); background-size: 100% no-repeat center;">
|
||||
<font color="white">
|
||||
@@ -63,9 +70,9 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label asp-for="Contact.DbId" class="col-md-3 right">DbId:</label>
|
||||
<label asp-for="Contact.DbId" class="col-md-3 right">Database ID:</label>
|
||||
<div class="col-md-9">
|
||||
<input asp-for="Contact.DbId" placeholder="AyaNova Database Id (optional)" class="form-control" required />
|
||||
<input asp-for="Contact.DbId" placeholder="AyaNova Database Id (optional)" class="form-control" />
|
||||
<span asp-validation-for="Contact.DbId"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,42 +104,25 @@
|
||||
|
||||
|
||||
|
||||
<!-- Button -->
|
||||
<!-- <div class="form-group">
|
||||
|
||||
<label class="col-md-4 control-label" for="Send"></label>
|
||||
<div class="col-md-4">
|
||||
<div class="g-recaptcha" data-callback="imNotARobot" data-sitekey="6LcH7GUUAAAAAJIDf_JDZolSv__xN6oqr9Dx79zs">
|
||||
</div>
|
||||
<button id="btnsubmit" type="submit" class="btn btn-info">Send us your question</button>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="form-group">
|
||||
|
||||
<label class="col-md-4 control-label" for="Send"></label>
|
||||
<div class="col-md-4">
|
||||
|
||||
<button type="submit" class="btn btn-info">Send us your question</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row">
|
||||
<div class="col-md-12">
|
||||
<button type="submit">Send us your question</button>
|
||||
</div>
|
||||
</div> -->
|
||||
</form>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p>All of our responses are from real live people, so there could be a delay receiving a reply due to time
|
||||
<p>We respond personally so there could be a delay receiving a reply due to time
|
||||
zone differences, time of day, weekend, or if a holiday long weekend.</p>
|
||||
<strong>
|
||||
<p>Why do we ask for your name, company name and email address?</p>
|
||||
</strong>
|
||||
<p>We use the information you send us to respond to you, to provide sales support and technicial support to
|
||||
<p>We use the information you send us to respond to you, to provide sales support and technical support to
|
||||
you and your company, and to make AyaNova recommendations and suggestions to you and your company. Also
|
||||
refer to our <a href="https://www.ayanova.com/privacypolicy.htm" target="_blank">Privacy Policy</a> for more
|
||||
refer to our <a href="https://www.ayanova.com/r/privacy.htm" target="_blank">Privacy Policy</a> for more
|
||||
clarity.</p>
|
||||
|
||||
</div>
|
||||
@@ -164,8 +154,7 @@
|
||||
<p>In order to be able to provide an affordable product for small business with fast technical support
|
||||
globally, we do not provide phone support.</p>
|
||||
<p>Please contact us via the online form above, or send us a direct email to support@ayanova.com and our
|
||||
North American support staff will respond promptly between 9:00AM and 5:00PM Pacific Standard Time (-8GMT/
|
||||
UTC) Monday to Friday.</p>
|
||||
North American support staff will respond promptly between 9:00AM and 5:00PM Pacific Time (PCT) Monday to Friday.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,7 +171,9 @@
|
||||
<span>Since 1999 AyaNova® is a registered trademark of Ground Zero Tech-Works Inc. in the United States and
|
||||
other countries.</span>
|
||||
<br>
|
||||
<span><a href="https://ayanova.com/privacypolicy.htm">Privacy Policy</a></span></small>
|
||||
<span><a href="https://ayanova.com/r/privacy.htm">Privacy Policy</a></span></small>
|
||||
</div>
|
||||
</div>
|
||||
<!--end bottom container-->
|
||||
|
||||
</div>
|
||||
@@ -1,13 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using contact.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net.Mail;
|
||||
using System.Net;
|
||||
//for captcha:
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace contact.Pages
|
||||
{
|
||||
@@ -22,172 +20,79 @@ namespace contact.Pages
|
||||
public string Name { get; set; }
|
||||
[Required]
|
||||
public string Company { get; set; }
|
||||
//Optional; AyaNova clients deep-link to this page with their database ID.
|
||||
//Binding attributes left exactly as they were so that link keeps working.
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public string DbId { get; set; }
|
||||
[Required, EmailAddress]
|
||||
public string Email { get; set; }
|
||||
[Required]
|
||||
public string Message { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ContactModel : PageModel
|
||||
{
|
||||
public string Message { get; set; }
|
||||
private const string ConfirmedUrl = "https://ayanova.com/confirmed.htm";
|
||||
|
||||
//2022-05-06 Company names containing any of these are dropped silently but still get the
|
||||
//success redirect, so the spammer gets no signal and has to pay someone to enter them by hand
|
||||
public static readonly string[] SpamBlocks = { "google", "jumboleadmagnet", "boostleadgeneration" };
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public ContactFormModel Contact { get; set; }
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
public ContactModel(IConfiguration configuration)
|
||||
//Set when the send fails, so the page can tell the visitor instead of claiming success
|
||||
public bool SendFailed { get; set; }
|
||||
|
||||
private readonly MailSender _mail;
|
||||
private readonly ILogger<ContactModel> _logger;
|
||||
|
||||
public ContactModel(MailSender mail, ILogger<ContactModel> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_mail = mail;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public ActionResult OnPost()
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
//2025-11-01 reCAPTCHA removed (Google service change). Replacement deferred, see runbook Phase 6.
|
||||
|
||||
//2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
|
||||
// if (!ReCaptchaPassed(
|
||||
// Request.Form["g-recaptcha-response"], // that's how you get it from the Request object
|
||||
// _configuration.GetSection("GoogleReCaptcha:secret").Value
|
||||
// ))
|
||||
// {
|
||||
// //Return a fail code that will hopefully take us off the spammers list
|
||||
// return StatusCode(500);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
//go away spammers
|
||||
//2022-05-06 changes to get rid of jumbo lead magnet spammer but still force him to pay someone to manually enter the stuff
|
||||
//ideally it should read from a text file here but this is a quickie fix while Joyce is on important viha phone call
|
||||
var blocks = new List<string>();
|
||||
blocks.Add("google");
|
||||
blocks.Add("jumboleadmagnet");//<--go away this guy in particular, keeps spamming
|
||||
blocks.Add("boostleadgeneration");
|
||||
//ericjonesmyemail@gmail.com
|
||||
var companyname = Contact.Company.ToLowerInvariant();
|
||||
foreach (string s in blocks)
|
||||
if (IsBlocked(Contact.Company))
|
||||
{
|
||||
if (companyname.Contains(s))
|
||||
return Redirect(ConfirmedUrl);
|
||||
}
|
||||
|
||||
//Email is in the body as well as Reply-To, so it survives even if Reply-To can't be set
|
||||
var body = $"Name:\r\n{Contact.Name}\r\n\r\nCompany:\r\n{Contact.Company}\r\n\r\nEmail:\r\n{Contact.Email}\r\n\r\nDatabase Id:\r\n{Contact.DbId}\r\n\r\nMessage:\r\n{Contact.Message}";
|
||||
|
||||
try
|
||||
{
|
||||
goto skipspam;
|
||||
|
||||
await _mail.SendToSupportAsync($"Question about AyaNova from {Contact.Company}", body, Contact.Name, Contact.Email);
|
||||
}
|
||||
}
|
||||
|
||||
SendMail();
|
||||
|
||||
skipspam:
|
||||
//TODO: go to a successful submit page on the ayanova site
|
||||
//return Redirect("/confirm.html");//sample quickie page I made up
|
||||
return Redirect("https://ayanova.com/confirmed.htm");
|
||||
}
|
||||
|
||||
|
||||
private void SendMail()
|
||||
catch (Exception ex)
|
||||
{
|
||||
var MessageBody = $"Name:\r\n{Contact.Name}\r\n\r\nCompany:\r\n{Contact.Company}\r\n\r\nDatabase Id:\r\n{Contact.DbId}\r\n\r\nMessage:\r\n{Contact.Message}";
|
||||
//Log the whole submission so it can be recovered from the journal, not lost
|
||||
_logger.LogError(ex, "Contact form send failed. Submission:\r\n{Body}", body);
|
||||
SendFailed = true;
|
||||
return Page();
|
||||
}
|
||||
|
||||
//SEND TO US
|
||||
using (var message = new MailMessage())
|
||||
return Redirect(ConfirmedUrl);
|
||||
}
|
||||
|
||||
public static bool IsBlocked(string company)
|
||||
{
|
||||
message.To.Add(new MailAddress("support@ayanova.com"));
|
||||
message.From = new MailAddress(Contact.Email);
|
||||
message.Subject = $"Question about AyaNova from {Contact.Company}";
|
||||
message.Body = MessageBody;
|
||||
using (var smtpClient = new SmtpClient("smtp.fastmail.com"))
|
||||
{
|
||||
|
||||
smtpClient.Host = "smtp.fastmail.com";
|
||||
smtpClient.Port = 587;
|
||||
smtpClient.UseDefaultCredentials = false;
|
||||
//testing
|
||||
smtpClient.EnableSsl = true;
|
||||
|
||||
// smtpClient.Port=465;
|
||||
// smtpClient.DeliveryMethod= SmtpDeliveryMethod.Network;
|
||||
|
||||
|
||||
|
||||
//NOTE: Do not use the noreply email address to send mail, it crashes the server somehow
|
||||
|
||||
//******************************************************************************************************************
|
||||
//******************************************************************************************************************
|
||||
//TEST CRASH
|
||||
// smtpClient.Credentials = new System.Net.NetworkCredential("noreply@ayanova.com", "91768700489f8edd28aa71e3e0f4073eba54ce83c4c1a6a910700fa94094ddfd");
|
||||
|
||||
|
||||
//FASTMAIL CHANGES
|
||||
//Fastmail server names and ports help page: https://www.fastmail.help/hc/en-us/articles/1500000278342
|
||||
//APP Password created in fastmail for smtp use only labelled 'contact-form': cnea8agl6nlx5j7l
|
||||
|
||||
//try using from as support@onayanova.com
|
||||
//try domain version if this still won't work
|
||||
smtpClient.Credentials = new System.Net.NetworkCredential("support@onayanova.com", "cnea8agl6nlx5j7l");
|
||||
//******************************************************************************************************************
|
||||
//******************************************************************************************************************
|
||||
|
||||
smtpClient.Send(message);
|
||||
var c = company.ToLowerInvariant();
|
||||
return SpamBlocks.Any(s => c.Contains(s));
|
||||
}
|
||||
}
|
||||
|
||||
//Removed 2022-10-06 causing backscatter and also not helpful
|
||||
// //SEND COPY TO CLIENT
|
||||
// using (var message = new MailMessage())
|
||||
// {
|
||||
// message.To.Add(new MailAddress(Contact.Email));
|
||||
// message.From = new MailAddress("support@ayanova.com");
|
||||
// message.Subject = $"Confirmation that your question about AyaNova has been received from {Contact.Company}";
|
||||
// message.Body = MessageBody;
|
||||
|
||||
// using (var smtpClient = new SmtpClient("smtp.fastmail.com"))
|
||||
// {
|
||||
|
||||
// smtpClient.Host = "smtp.fastmail.com";
|
||||
// smtpClient.Port = 587;
|
||||
// smtpClient.UseDefaultCredentials = false;
|
||||
// smtpClient.EnableSsl=true;
|
||||
// //NOTE: Do not use the noreply email address to send mail, it crashes the server somehow
|
||||
// smtpClient.Credentials = new System.Net.NetworkCredential("support@onayanova.com", "cnea8agl6nlx5j7l");
|
||||
// smtpClient.Send(message);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
Message = "Your contact page.";
|
||||
}
|
||||
|
||||
|
||||
//2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
|
||||
// public static bool ReCaptchaPassed(string gRecaptchaResponse, string secret)
|
||||
// {
|
||||
// HttpClient httpClient = new HttpClient();
|
||||
// var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={gRecaptchaResponse}").Result;
|
||||
// if (res.StatusCode != HttpStatusCode.OK)
|
||||
// {
|
||||
// // logger.LogError("Error while sending request to ReCaptcha");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// string JSONres = res.Content.ReadAsStringAsync().Result;
|
||||
// dynamic JSONdata = JObject.Parse(JSONres);
|
||||
// if (JSONdata.success != "true")
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@page
|
||||
@page
|
||||
@model RequestModel
|
||||
@{
|
||||
ViewData["Title"] = "Request";
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
<div class="container">
|
||||
|
||||
@if (Model.SendFailed)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
Sorry, your request could not be sent. Please try again in a few minutes,
|
||||
or email support@ayanova.com directly.
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="jumbotron text-center">
|
||||
<h2>Request AyaNova subscription 7 day trial account</h2>
|
||||
</div>
|
||||
@@ -58,7 +66,7 @@
|
||||
<label asp-for="SubRequest.DataCenter" class="col-md-3 right">Data center (closest to
|
||||
you):</label>
|
||||
<div class="col-md-9">
|
||||
<select asp-for="SubRequest.DataCenter" asp-items="Model.DataCenters"></select>
|
||||
<select asp-for="SubRequest.DataCenter" asp-items="Model.DataCenters" class="form-control"></select>
|
||||
<span asp-validation-for="SubRequest.DataCenter"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -67,18 +75,6 @@
|
||||
|
||||
|
||||
|
||||
<!-- Button -->
|
||||
<!-- <div class="form-group">
|
||||
|
||||
<label class="col-md-4 control-label" for="Send"></label>
|
||||
<div class="col-md-4">
|
||||
<div class="g-recaptcha" data-callback="imNotARobot"
|
||||
data-sitekey="6LcH7GUUAAAAAJIDf_JDZolSv__xN6oqr9Dx79zs">
|
||||
</div>
|
||||
<button id="btnsubmit" type="submit" class="btn btn-info">Send us your request</button>
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="form-group">
|
||||
|
||||
<label class="col-md-4 control-label" for="Send"></label>
|
||||
@@ -103,3 +99,5 @@
|
||||
</div>
|
||||
</div>
|
||||
<!--end bottom container-->
|
||||
|
||||
</div>
|
||||
@@ -1,14 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Net.Mail;
|
||||
using System.Net;
|
||||
//for captcha:
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
using contact.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace contact.Pages
|
||||
{
|
||||
@@ -23,26 +25,26 @@ namespace contact.Pages
|
||||
public string Name { get; set; }
|
||||
[Required]
|
||||
public string Company { get; set; }
|
||||
|
||||
[Required, EmailAddress]
|
||||
public string Email { get; set; }
|
||||
[Required]
|
||||
public string DataCenter { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class RequestModel : PageModel
|
||||
{
|
||||
// public string DataCenter { get; set; }
|
||||
private const string EvaluateUrl = "https://ayanova.com/docs/ay-evaluate/";
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public RequestFormModel SubRequest { get; set; }
|
||||
|
||||
//Set when neither Sockeye nor the email got the request, so the page can say so
|
||||
public bool SendFailed { get; set; }
|
||||
|
||||
public List<SelectListItem> DataCenters { get; } = new List<SelectListItem>
|
||||
{
|
||||
new SelectListItem { Value = "SF", Text = "San Francisco" },
|
||||
new SelectListItem { Value = "ATL", Text = "Atlanta" },
|
||||
new SelectListItem { Value = "NY", Text = "New York" },
|
||||
new SelectListItem { Value = "TOR", Text = "Toronto" },
|
||||
new SelectListItem { Value = "AMS", Text = "Amsterdam" },
|
||||
@@ -51,64 +53,99 @@ namespace contact.Pages
|
||||
new SelectListItem { Value = "SNG", Text = "Singapore" },
|
||||
new SelectListItem { Value = "BNG", Text = "Bangalore" },
|
||||
new SelectListItem { Value = "SYD", Text = "Sydney Australia" }
|
||||
|
||||
};
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
public RequestModel(IConfiguration configuration)
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly MailSender _mail;
|
||||
private readonly ILogger<RequestModel> _logger;
|
||||
|
||||
public RequestModel(IConfiguration configuration, IHttpClientFactory httpClientFactory, MailSender mail, ILogger<RequestModel> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_mail = mail;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public ActionResult OnPost()
|
||||
public void OnGet()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
//The select can be bypassed by a hand-crafted POST; only accept codes from the list
|
||||
if (!DataCenters.Any(d => d.Value == SubRequest.DataCenter))
|
||||
{
|
||||
ModelState.AddModelError("SubRequest.DataCenter", "Please choose a data center from the list.");
|
||||
}
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
//2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
|
||||
// if (!ReCaptchaPassed(
|
||||
// Request.Form["g-recaptcha-response"], // that's how you get it from the Request object
|
||||
// _configuration.GetSection("GoogleReCaptcha:secret").Value
|
||||
// ))
|
||||
// {
|
||||
// //Return a fail code that will hopefully take us off the spammers list
|
||||
// return StatusCode(500);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
//fuck those spammers
|
||||
//2022-05-06 changes to get rid of jumbo lead magnet spammer but still force him to pay someone to manually enter the stuff
|
||||
//ideally it should read from a text file here but this is a quickie fix while Joyce is on important viha phone call
|
||||
var blocks = new List<string>();
|
||||
blocks.Add("google");
|
||||
blocks.Add("jumboleadmagnet");//<--fuck this guy in particular, keeps spamming
|
||||
blocks.Add("boostleadgeneration");
|
||||
//ericjonesmyemail@gmail.com
|
||||
var companyname = SubRequest.Company.ToLowerInvariant();
|
||||
foreach (string s in blocks)
|
||||
if (ContactModel.IsBlocked(SubRequest.Company))
|
||||
{
|
||||
if (companyname.Contains(s))
|
||||
{
|
||||
goto skipspam;
|
||||
|
||||
}
|
||||
return Redirect(EvaluateUrl);
|
||||
}
|
||||
|
||||
PostRequestToSockeye();
|
||||
SendMail();
|
||||
|
||||
skipspam:
|
||||
return Redirect("https://ayanova.com/docs/ay-evaluate/");
|
||||
//1. Record the request in Sockeye. A failure here is logged and reported in the email,
|
||||
// so the trial can be set up by hand instead of the request disappearing.
|
||||
string sockeyeResult;
|
||||
bool sockeyeOk;
|
||||
try
|
||||
{
|
||||
await PostRequestToSockeyeAsync();
|
||||
sockeyeOk = true;
|
||||
sockeyeResult = "Recorded in Sockeye.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sockeyeOk = false;
|
||||
sockeyeResult = $"NOT RECORDED IN SOCKEYE ({ex.Message}). Set this trial up by hand.";
|
||||
_logger.LogError(ex, "Trial request post to Sockeye failed. {Body}", Describe());
|
||||
}
|
||||
|
||||
private void PostRequestToSockeye()
|
||||
//2. Notify support. Email is in the body; From is the form account, so it was never there before either
|
||||
var body = $"{Describe()}\r\n\r\nSockeye:\r\n{sockeyeResult}";
|
||||
var subject = sockeyeOk
|
||||
? $"Trial request from {SubRequest.Company}"
|
||||
: $"Trial request NOT RECORDED from {SubRequest.Company}";
|
||||
bool mailOk;
|
||||
try
|
||||
{
|
||||
await _mail.SendToSupportAsync(subject, body, SubRequest.Name, SubRequest.Email);
|
||||
mailOk = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mailOk = false;
|
||||
_logger.LogError(ex, "Trial request email failed. Submission:\r\n{Body}", body);
|
||||
}
|
||||
|
||||
using var client = new HttpClient();
|
||||
//client.BaseAddress = new System.Uri("https://sockeye.ayanova.com");///api/v8.0/subscription-server/
|
||||
//Either path reaching John means the request is not lost; only both failing is a failure for the visitor
|
||||
if (!sockeyeOk && !mailOk)
|
||||
{
|
||||
SendFailed = true;
|
||||
return Page();
|
||||
}
|
||||
|
||||
return Redirect(EvaluateUrl);
|
||||
}
|
||||
|
||||
private string Describe() =>
|
||||
$"Name:\r\n{SubRequest.Name}\r\n\r\nCompany:\r\n{SubRequest.Company}\r\n\r\nEmail:\r\n{SubRequest.Email}\r\n\r\nDataCenter:\r\n{SubRequest.DataCenter}";
|
||||
|
||||
private async Task PostRequestToSockeyeAsync()
|
||||
{
|
||||
//Sockeye:TrialRequestUrl. On the server this is http://127.0.0.1:7575/subscription-server-trial-request,
|
||||
//straight to Kestrel on the same host, so it depends on neither DNS nor the droplet reaching its own reserved IP.
|
||||
var url = _configuration["Sockeye:TrialRequestUrl"];
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
throw new InvalidOperationException("Sockeye:TrialRequestUrl is not configured");
|
||||
}
|
||||
|
||||
var r = new
|
||||
{
|
||||
@@ -119,110 +156,10 @@ namespace contact.Pages
|
||||
rValue = "totallylegit"
|
||||
};
|
||||
|
||||
|
||||
HttpContent body = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(r),
|
||||
System.Text.Encoding.UTF8,
|
||||
"application/json");
|
||||
var response = client.PostAsync("https://sockeye.ayanova.com/subscription-server-trial-request", body).Result;
|
||||
//var response = client.PostAsync("http://localhost:7676/subscription-server-trial-request", body).Result;
|
||||
|
||||
// if (response.IsSuccessStatusCode)
|
||||
// {
|
||||
// var content = await response.Content.ReadAsStringAsync();
|
||||
// if (!string.IsNullOrEmpty(content))
|
||||
// {
|
||||
// var objDeserializeObject = JsonConvert.DeserializeObject<SongsModel>(content);
|
||||
|
||||
// Console.WriteLine("Data Saved Successfully.");
|
||||
|
||||
// if (objDeserializeObject != null)
|
||||
// {
|
||||
// Console.WriteLine(objDeserializeObject.Name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void SendMail()
|
||||
{
|
||||
var MessageBody = $"Name:\r\n{SubRequest.Name}\r\n\r\nCompany:\r\n{SubRequest.Company}\r\n\r\nDataCenter:\r\n{SubRequest.DataCenter}";
|
||||
|
||||
//SEND TO US
|
||||
using (var message = new MailMessage())
|
||||
{
|
||||
message.To.Add(new MailAddress("support@ayanova.com"));
|
||||
message.From = new MailAddress(SubRequest.Email);
|
||||
message.Subject = $"Trial request from {SubRequest.Company}";
|
||||
message.Body = MessageBody;
|
||||
using (var smtpClient = new SmtpClient("smtp.fastmail.com"))
|
||||
{
|
||||
|
||||
smtpClient.Host = "smtp.fastmail.com";
|
||||
smtpClient.Port = 587;
|
||||
smtpClient.UseDefaultCredentials = false;
|
||||
//testing
|
||||
smtpClient.EnableSsl = true;
|
||||
|
||||
// smtpClient.Port=465;
|
||||
// smtpClient.DeliveryMethod= SmtpDeliveryMethod.Network;
|
||||
|
||||
|
||||
|
||||
//NOTE: Do not use the noreply email address to send mail, it crashes the server somehow
|
||||
|
||||
//******************************************************************************************************************
|
||||
//******************************************************************************************************************
|
||||
//TEST CRASH
|
||||
// smtpClient.Credentials = new System.Net.NetworkCredential("noreply@ayanova.com", "91768700489f8edd28aa71e3e0f4073eba54ce83c4c1a6a910700fa94094ddfd");
|
||||
|
||||
|
||||
//FASTMAIL CHANGES
|
||||
//Fastmail server names and ports help page: https://www.fastmail.help/hc/en-us/articles/1500000278342
|
||||
//APP Password created in fastmail for smtp use only labelled 'contact-form': cnea8agl6nlx5j7l
|
||||
|
||||
//try using from as support@onayanova.com
|
||||
//try domain version if this still won't work
|
||||
smtpClient.Credentials = new System.Net.NetworkCredential("support@onayanova.com", "cnea8agl6nlx5j7l");
|
||||
//******************************************************************************************************************
|
||||
//******************************************************************************************************************
|
||||
|
||||
smtpClient.Send(message);
|
||||
var client = _httpClientFactory.CreateClient("sockeye");
|
||||
var response = await client.PostAsJsonAsync(url, r);
|
||||
//Previously the response was never checked, so a rejected request failed silently
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
|
||||
// public static bool ReCaptchaPassed(string gRecaptchaResponse, string secret)
|
||||
// {
|
||||
// HttpClient httpClient = new HttpClient();
|
||||
// var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={gRecaptchaResponse}").Result;
|
||||
// if (res.StatusCode != HttpStatusCode.OK)
|
||||
// {
|
||||
// // logger.LogError("Error while sending request to ReCaptcha");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// string JSONres = res.Content.ReadAsStringAsync().Result;
|
||||
// dynamic JSONdata = JObject.Parse(JSONres);
|
||||
// if (JSONdata.success != "true")
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,40 +16,16 @@
|
||||
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
|
||||
</environment>
|
||||
|
||||
<script src='https://www.google.com/recaptcha/api.js'></script>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<!-- <nav class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a asp-page="/Index" class="navbar-brand">contact</a>
|
||||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a asp-page="/Index">Home</a></li>
|
||||
<li><a asp-page="/About">About</a></li>
|
||||
<li><a asp-page="/Contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav> -->
|
||||
<!--
|
||||
<partial name="_CookieConsentPartial" /> -->
|
||||
|
||||
|
||||
<div class="container body-content">
|
||||
@RenderBody()
|
||||
<!-- <hr />
|
||||
<footer>
|
||||
<p>© 2018 - contact</p>
|
||||
</footer> -->
|
||||
|
||||
</div>
|
||||
|
||||
<environment include="Development">
|
||||
@@ -72,13 +48,13 @@
|
||||
</script>
|
||||
<script src="~/js/site.min.js" asp-append-version="true"></script>
|
||||
</environment>
|
||||
<script type="text/javascript">
|
||||
@* <script type="text/javascript">
|
||||
$("#btnsubmit").hide();
|
||||
var imNotARobot = function() {
|
||||
//console.info("Button was clicked");
|
||||
$("#btnsubmit").show();
|
||||
};
|
||||
</script>
|
||||
</script> *@
|
||||
@RenderSection("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
||||
20
Program.cs
20
Program.cs
@@ -1,19 +1,17 @@
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace contact
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseUrls("http://*:3002")//only this port works with nginx proxy
|
||||
//.UseUrls("http://localhost:3002")//this doesn't work with nginx proxy
|
||||
.UseStartup<Startup>();
|
||||
//No UseUrls here. The listening address comes from ASPNETCORE_URLS in the systemd unit
|
||||
//(http://127.0.0.1:3002) and from launchSettings.json for local runs.
|
||||
//The old "only *:3002 works with nginx" comment was F1: nginx proxied to $server_addr, the public IP.
|
||||
public static void Main(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(web => web.UseStartup<Startup>())
|
||||
.Build()
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:30176",
|
||||
"sslPort": 44340
|
||||
}
|
||||
},
|
||||
{
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:3002",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
||||
47
Services/MailSender.cs
Normal file
47
Services/MailSender.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Threading.Tasks;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit.Security;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using MimeKit;
|
||||
|
||||
namespace contact.Services
|
||||
{
|
||||
//Sends web form submissions to support.
|
||||
//From is always the authenticated account; the visitor goes in Reply-To, so there is no sender spoofing.
|
||||
//SMTP settings come from the "Smtp" config section; the password is never in source.
|
||||
public class MailSender
|
||||
{
|
||||
private const string SupportAddress = "support@ayanova.com";
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public MailSender(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task SendToSupportAsync(string subject, string body, string visitorName, string visitorEmail)
|
||||
{
|
||||
var smtp = _configuration.GetSection("Smtp");
|
||||
|
||||
var message = new MimeMessage();
|
||||
message.From.Add(new MailboxAddress("AyaNova web forms", smtp["User"]));
|
||||
message.To.Add(MailboxAddress.Parse(SupportAddress));
|
||||
if (MailboxAddress.TryParse(visitorEmail, out var replyTo))
|
||||
{
|
||||
replyTo.Name = visitorName;
|
||||
message.ReplyTo.Add(replyTo);
|
||||
}
|
||||
message.Subject = OneLine(subject);
|
||||
message.Body = new TextPart("plain") { Text = body };
|
||||
|
||||
using var client = new SmtpClient();
|
||||
await client.ConnectAsync(smtp["Host"], smtp.GetValue<int>("Port"), SecureSocketOptions.StartTls);
|
||||
await client.AuthenticateAsync(smtp["User"], smtp["Password"]);
|
||||
await client.SendAsync(message);
|
||||
await client.DisconnectAsync(true);
|
||||
}
|
||||
|
||||
//Subjects include visitor-supplied text; a hand-crafted POST could put line breaks in it
|
||||
private static string OneLine(string s) => s.Replace("\r", " ").Replace("\n", " ");
|
||||
}
|
||||
}
|
||||
30
Startup.cs
30
Startup.cs
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using contact.Services;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -15,14 +19,28 @@ namespace contact
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers().AddNewtonsoftJson();
|
||||
services.AddRazorPages();
|
||||
services.AddSingleton<MailSender>();
|
||||
|
||||
services.AddHttpClient("sockeye", client =>
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(15);
|
||||
});
|
||||
|
||||
//Antiforgery tokens on the forms are encrypted with Data Protection keys. The service account has no
|
||||
//home directory, so without this the keys live only in memory and every restart breaks forms that
|
||||
//visitors already have open. Set DataProtection:KeyPath on the server (systemd StateDirectory=contact).
|
||||
var keyPath = Configuration["DataProtection:KeyPath"];
|
||||
if (!string.IsNullOrWhiteSpace(keyPath))
|
||||
{
|
||||
services.AddDataProtection()
|
||||
.SetApplicationName("contact")
|
||||
.PersistKeysToFileSystem(new DirectoryInfo(keyPath));
|
||||
}
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
@@ -32,21 +50,15 @@ namespace contact
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
// app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
// app.UseCookiePolicy();
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapRazorPages();
|
||||
|
||||
|
||||
});
|
||||
// app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
"AllowedHosts": "localhost",
|
||||
"Sockeye": {
|
||||
"TrialRequestUrl": "http://localhost:7676/subscription-server-trial-request"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"GoogleReCaptcha": {
|
||||
"key": "6LcH7GUUAAAAAJIDf_JDZolSv__xN6oqr9Dx79zs",
|
||||
"secret": "6LcH7GUUAAAAAERHuA3fWDcMIlJ3QHE_WNZm4BSO"
|
||||
"AllowedHosts": "contact.ayanova.com",
|
||||
"Smtp": {
|
||||
"Host": "smtp.fastmail.com",
|
||||
"Port": 587,
|
||||
"User": "support@onayanova.com"
|
||||
},
|
||||
"Sockeye": {
|
||||
"TrialRequestUrl": "http://127.0.0.1:7575/subscription-server-trial-request"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<UserSecretsId>efc95c93-c628-4ad5-a697-cd1613181a44</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.0" />
|
||||
<!-- Match whatever 4.x Sockeye is on -->
|
||||
<PackageReference Include="MailKit" Version="4.18.1" />
|
||||
</ItemGroup>
|
||||
<!-- <ItemGroup>
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.3.111.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.4" />
|
||||
<PackageReference Include="jose-jwt" Version="2.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.4" />
|
||||
<PackageReference Include="mailkit" Version="2.7.0" />
|
||||
|
||||
</ItemGroup> -->
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user