Files
contact/Pages/Request.cshtml.cs

166 lines
6.2 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net.Http;
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
{
[BindProperties(SupportsGet = true)]
public class RequestFormModel
{
public RequestFormModel()
{
DataCenter = "SF";
}
[Required]
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
{
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" },
new SelectListItem { Value = "LON", Text = "London" },
new SelectListItem { Value = "FFT", Text = "Frankfurt" },
new SelectListItem { Value = "SNG", Text = "Singapore" },
new SelectListItem { Value = "BNG", Text = "Bangalore" },
new SelectListItem { Value = "SYD", Text = "Sydney Australia" }
};
private readonly 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 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();
}
if (ContactModel.IsBlocked(SubRequest.Company))
{
return Redirect(EvaluateUrl);
}
//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());
}
//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);
}
//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
{
dataCenter = SubRequest.DataCenter,
email = SubRequest.Email,
company = SubRequest.Company,
name = SubRequest.Name,
rValue = "totallylegit"
};
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();
}
}
}