589 lines
25 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using gehGassi.Domain.Common;
using gehGassi.Web.Controllers;
using gehGassi.Web.Models;
using gehGassi.Web.Services;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace gehGassi.Web.Helper
{
/// <summary>
/// Hilfsklasse mit Erweiterungen
/// </summary>
public static class Extensions
{
/// <summary>
/// Erweiterung für PartialViewResults.
/// Erstellt aus dem Partialview einen String
/// </summary>
/// <param name="partialView">Gewünschter PartialView</param>
/// <param name="actionContext">Instanz des ActionContext</param>
/// <returns>View-Ergebnis als String</returns>
public static async Task<string> ToStringAsync(this PartialViewResult partialView, ActionContext actionContext)
{
using (var writer = new StringWriter())
{
var serviceProvider = (IServiceProvider)actionContext.HttpContext.RequestServices;
var executor = (PartialViewResultExecutor)serviceProvider.GetService(typeof(PartialViewResultExecutor));
var view = executor.FindView(actionContext, partialView).View;
var viewContext = new ViewContext(actionContext, view, partialView.ViewData, partialView.TempData, writer, new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return writer.ToString();
}
}
/// <summary>
/// Erweiterung für ViewResults.
/// Erstellt aus dem View einen String
/// </summary>
/// <param name="viewResult">Gewünschter PartialView</param>
/// <param name="actionContext">Instanz des ActionContext</param>
/// <returns>View-Ergebnis als String</returns>
public static async Task<string> ToStringAsync(this ViewResult viewResult, ActionContext actionContext)
{
using (var writer = new StringWriter())
{
var serviceProvider = (IServiceProvider)actionContext.HttpContext.RequestServices;
var executor = (ViewResultExecutor)serviceProvider.GetService(typeof(ViewResultExecutor));
var view = executor.FindView(actionContext, viewResult).View;
var viewContext = new ViewContext(actionContext, view, viewResult.ViewData, viewResult.TempData, writer, new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return writer.ToString();
}
}
/// <summary>
/// Prüft ob eine URL lokal ist. Wenn nicht, wird eine lokale zurückgegeben
/// </summary>
/// <param name="urlHelper">Instanz eines IUrlHelper</param>
/// <param name="localUrl">zu prüfende URL</param>
/// <returns>URL</returns>
public static string GetLocalUrl(this IUrlHelper urlHelper, string localUrl)
{
if (!urlHelper.IsLocalUrl(localUrl))
{
return urlHelper.Page("/Index");
}
return localUrl;
}
/// <summary>
/// Gibt zurück ob ein String mit "http" startet.
/// Wird bei Fotos verwendet um zwischen lokalen und online Fotos zu unterscheiden
/// </summary>
/// <param name="text">Text der geprüft werden soll</param>
/// <returns>true wenn mit http startet, false sonst</returns>
public static bool StartsWithHttp(this string text)
{
if (!string.IsNullOrWhiteSpace(text))
{
return text.ToLower().StartsWith("http");
}
return false;
}
/// <summary>
/// Erstellt einen Link für das Zurücksetzen des Passwortes
/// </summary>
/// <param name="urlHelper">Instanz eines IUrlHelper</param>
/// <param name="userId">Benutzer-ID</param>
/// <param name="code">Bestätigungscode</param>
/// <param name="scheme">HTTP-Scheme (http/https)</param>
/// <returns>Link</returns>
public static string ResetPasswordCallbackLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
return urlHelper.Action(
action: nameof(AccountController.ResetPassword),
controller: "Account",
values: new { userId, code },
protocol: scheme);
}
/// <summary>
/// Erstellt einen Link für das Zurücksetzen des Passwortes für die APP
/// </summary>
/// <param name="urlHelper">Instanz eines IUrlHelper</param>
/// <param name="userId">Benutzer-ID</param>
/// <param name="code">Bestätigungscode</param>
/// <param name="scheme">HTTP-Scheme (http/https)</param>
/// <returns>Link</returns>
public static string ResetPasswordCallbackLinkApp(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
return urlHelper.Action(
action: nameof(AccountController.ResetPasswordApp),
controller: "Account",
values: new { userId, code },
protocol: scheme);
}
/// <summary>
/// Erstellt einen Link für das Löschen eines Accounts
/// </summary>
/// <param name="urlHelper">Instanz eines IUrlHelper</param>
/// <param name="userId">Benutzer-ID</param>
/// <param name="code">Bestätigungscode</param>
/// <param name="scheme">HTTP-Scheme (http/https)</param>
/// <returns>Link</returns>
public static string DeleteAccountCallbackLinkApp(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
return urlHelper.Action(
action: nameof(AppController.DoDeleteAccount),
controller: "App",
values: new { userId, code },
protocol: scheme);
}
/// <summary>
/// Sendet eine Email an gehgassi, dass ein Benutzer gelöscht werden soll
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="userAccountEmail">Email Adresse des Benutzers = Benutzername</param>
/// <param name="userFirstName">Vorname des Benutzers</param>
/// <param name="userLastName">Nachname des Benutzers</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="emailSenderOptions">Instanz eines IOptions EmailSenderOptions</param>
/// <returns>Task</returns>
public static Task SendDeleteAccountEmailAsync(this IEmailSender emailSender, string userAccountEmail, string userFirstName, string userLastName, IStringLocalizer localizer, IOptions<EmailSenderOptions> emailSenderOptions)
{
string subject = localizer["DeleteAccountEmail_Subject"];
string message = localizer["DeleteAccountEmail_Message"];
message = string.Format(message, userFirstName, userLastName, userAccountEmail);
var targetEmail = "support@gehgassi.com";
#if DEBUG
targetEmail = "mihalits@creativebits.com";
#endif
return emailSender.SendEmailAsync(targetEmail, subject, message);
}
/// <summary>
/// Sendet eine Email für die Bestätigung der Email-Adresse
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="email">Ziel-Adresse</param>
/// <param name="link">Link für die Bestätigung</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="licenseOptions">Instanz eines IOptions LicenseOptions</param>
/// <returns>Task</returns>
public static Task SendEmailConfirmationAsync(this IEmailSender emailSender, string email, string link, IStringLocalizer localizer, IOptions<LicenseOptions> licenseOptions)
{
string subject = localizer["ConfirmEmail_Subject"];
string message = localizer["ConfirmEmail_Message"];
subject = string.Format(subject, licenseOptions.Value.Software);
message = string.Format(message, HtmlEncoder.Default.Encode(link), licenseOptions.Value.Software);
return emailSender.SendEmailAsync(email, subject, message);
}
/// <summary>
/// Sendet eine Email für die Bestätigung der Email-Adresse für die App
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="email">Ziel-Adresse</param>
/// <param name="link">Link für die Bestätigung</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="licenseOptions">Instanz eines IOptions LicenseOptions</param>
/// <returns>Task</returns>
public static Task SendEmailConfirmationAppAsync(this IEmailSender emailSender, string email, string link, IStringLocalizer localizer, IOptions<LicenseOptions> licenseOptions)
{
string subject = localizer["ConfirmEmail_Subject_App"];
string message = localizer["ConfirmEmail_Message_App"];
subject = string.Format(subject, licenseOptions.Value.Software);
message = string.Format(message, HtmlEncoder.Default.Encode(link), licenseOptions.Value.Software);
return emailSender.SendEmailAsync(email, subject, message);
}
/// <summary>
/// Sendet eine Email für die Bestätigung des Passwort Zurücksetzens
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="email">Ziel-Adresse</param>
/// <param name="link">Link für die Bestätigung</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="licenseOptions">Instanz eines IOptions LicenseOptions</param>
/// <returns>Task</returns>
public static Task SendPasswordResetAsync(this IEmailSender emailSender, string email, string link, IStringLocalizer localizer, IOptions<LicenseOptions> licenseOptions)
{
string subject = localizer["ResetPassword_Subject"];
string message = localizer["ResetPassword_Message"];
subject = string.Format(subject, licenseOptions.Value.Software);
message = string.Format(message, HtmlEncoder.Default.Encode(link), licenseOptions.Value.Software);
return emailSender.SendEmailAsync(email, subject, message);
}
/// <summary>
/// Sendet eine Email für die Bestätigung des Passwort Zurücksetzens für die APP
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="email">Ziel-Adresse</param>
/// <param name="link">Link für die Bestätigung</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <param name="licenseOptions">Instanz eines IOptions LicenseOptions</param>
/// <returns>Task</returns>
public static Task SendPasswordResetAppAsync(this IEmailSender emailSender, string email, string link, IStringLocalizer localizer, IOptions<LicenseOptions> licenseOptions)
{
string subject = localizer["ResetPassword_Subject_App"];
string message = localizer["ResetPassword_Message_App"];
subject = string.Format(subject, licenseOptions.Value.Software);
message = string.Format(message, HtmlEncoder.Default.Encode(link), licenseOptions.Value.Software);
return emailSender.SendEmailAsync(email, subject, message);
}
/// <summary>
/// Sendet eine Email für die Bestätigung der Löschung des Accounts
/// </summary>
/// <param name="emailSender">Instanz eines IEmailSender</param>
/// <param name="email">Ziel-Adresse</param>
/// <param name="link">Link für die Bestätigung</param>
/// <param name="localizer">Instanz eines IStringLocalizer</param>
/// <returns>Task</returns>
public static Task SendDeleteAccountAsync(this IEmailSender emailSender, string email, string link, IStringLocalizer localizer)
{
string subject = localizer["DeleteAccount_Subject"];
string message = localizer["DeleteAccount_Message"];
message = string.Format(message, HtmlEncoder.Default.Encode(link));
return emailSender.SendEmailAsync(email, subject, message);
}
/// <summary>
/// Serialisiert ein Objekt für die Speicherung in einer Session
/// </summary>
/// <typeparam name="T">Typ des Objektes</typeparam>
/// <param name="session">ISession</param>
/// <param name="key">Key</param>
/// <param name="value">Objekt</param>
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
/// <summary>
/// Deserialisiert ein Objekt aus einer Session
/// </summary>
/// <typeparam name="T">Typ des Objektes</typeparam>
/// <param name="session">ISession</param>
/// <param name="key">Key</param>
/// <returns>Deserialisiertes Objekt</returns>
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) :
JsonConvert.DeserializeObject<T>(value);
}
/// <summary>
/// Serialisiert ein Objekt in JSON mit CamelCase Resolver.
/// </summary>
/// <param name="item">Objekt das Serialisiert werden soll</param>
/// <returns>JSON-string</returns>
public static string ToCamelCaseJson(this object item)
{
var jsonOptions = new JsonSerializerSettings()
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
jsonOptions.Converters.Add(new NetTopologySuite.IO.Converters.GeometryConverter());
return JsonConvert.SerializeObject(item, jsonOptions);
}
/// <summary>
/// Erstellt aus einem Dateinamen einen eineutigen durch das Anhängen der Ticks der aktuellen Systemzeit
/// </summary>
/// <param name="filename">Dateiname</param>
/// <returns>Eindeutiger Dateiname</returns>
public static string ToUniqueFilename(this string filename)
{
if (!string.IsNullOrWhiteSpace(filename))
{
if (filename.Contains("."))
{
var lastIndex = filename.LastIndexOf('.');
if (lastIndex + 1 < filename.Length)
{
var firstPart = filename.Substring(0, lastIndex);
var secondPart = filename.Substring(lastIndex + 1);
return firstPart + "_" + DateTime.UtcNow.Ticks + "." + secondPart;
}
}
}
return filename;
}
public static IEnumerable<object> GetColumn<T>(this IList<T> items, string columnName)
{
var values = items.Select(x => x.GetType().GetProperty(columnName)?.GetValue(x));
return values;
}
/// <summary>
/// Ist ein HTTP-Request eine Ajax Request?
/// </summary>
/// <param name="request">HttpRequest</param>
/// <returns>true wenn ja, false sonst</returns>
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
if (request.Headers != null)
return !string.IsNullOrEmpty(request.Headers["X-Requested-With"]) &&
string.Equals(
request.Headers["X-Requested-With"],
"XmlHttpRequest",
StringComparison.OrdinalIgnoreCase);
return false;
}
/// <summary>
/// Gibt die Subdomain des aktuellen Requests zurück
/// </summary>
/// <param name="request">HttpRequest</param>
/// <returns>Subdomain wenn gefunden, string.empty sonst</returns>
public static string GetSubdomain(this HttpRequest request)
{
if (request == null)
return string.Empty;
if (!string.IsNullOrWhiteSpace(request.Host.Host))
{
var parts = request.Host.Host.Split(".");
if (parts.Length > 1)
return parts[0];
}
return string.Empty;
}
/// <summary>
/// Gibt die aktuelle URL mit der subdomain eingesetzt zurück.
/// Das Betrifft scheme und host und port
/// </summary>
/// <param name="request">HttpRequest</param>
/// <param name="subdomain">Subdomain die gesetzt werden soll</param>
/// <returns>neue url mit subdomain</returns>
public static string GetWithSubdomain(this HttpRequest request, string subdomain)
{
if (request == null || string.IsNullOrWhiteSpace(subdomain))
return string.Empty;
if (!string.IsNullOrWhiteSpace(request.Host.Host))
{
var host = request.Host.Host;
var parts = request.Host.Host.Split(".");
if (parts.Length == 3)
{
host = host.Replace(parts[0], subdomain);
}
if (parts.Length <= 2)
{
host = $"{subdomain}.{host}";
}
if (request.Host.Port.HasValue)
{
host += $":{request.Host.Port}";
}
return $"{request.Scheme}://{host}";
}
return string.Empty;
}
/// <summary>
/// Gibt die aktuelle URL mit der subdomain eingesetzt zurück.
/// Das Betrifft scheme und host und port
/// </summary>
/// <param name="request">HttpRequest</param>
/// <returns>neue url mit subdomain</returns>
public static string GetBaseDomain(this HttpRequest request)
{
if (request == null)
return string.Empty;
if (!string.IsNullOrWhiteSpace(request.Host.Host))
{
var host = request.Host.Host;
var parts = request.Host.Host.Split(".");
if (parts.Length == 3)
{
host = host.Replace(parts[0] + ".", "");
}
else if (parts.Length <= 2)
{
host = $"{host}";
}
return host;
}
return string.Empty;
}
/// <summary>
/// Convert a standard string into a htmlstring for rendering in a view
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static HtmlString ToHtmlString(this string value)
{
return new HtmlString(value);
}
/// <summary>
/// Wenn eine Web-Adresse nicht mit https:// beginnt, wird diese mit https:// zurückgegeben
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToHttpsWebAddress(this string value)
{
if (!value.ToLower().StartsWith("https://"))
return $"https://{value}";
else if (value.ToLower().StartsWith("http://"))
return value.ToLower().Replace("http://", "https://");
else
return value;
}
/// <summary>
/// Anonymisieren eines vollen Namen.
/// Optimalerweise in das Forma Vorname N.
/// </summary>
/// <param name="value"></param>
/// <returns>Anonymisierter Name</returns>
public static string AnonymizeFullName(this string value)
{
if (!string.IsNullOrWhiteSpace(value))
{
var name = value.Trim(' ');
if (name.Contains(" "))
{
var nameSplit = name.Split(' ');
var result = string.Empty;
for (int i = 0; i < nameSplit.Length; i++)
{
if (i > 0)
result += " ";
if (i < nameSplit.Length - 1)
result += nameSplit[i];
else
result += nameSplit[i].Substring(0, 1) + ".";
}
return result;
}
else
{
return name.Substring(0, 1) + ".";
}
}
return "Anonymous";
}
/// <summary>
/// Erstellt aus einem Text der Environment.Newline beinhaltet eine Liste von <p>xxx</p>
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static HtmlString ToParagraphs(this string value)
{
if (string.IsNullOrWhiteSpace(value))
return new HtmlString(value);
else
{
var result = string.Empty;
var lines = value.Split(Environment.NewLine);
result = lines.Aggregate(result, (current, line) => current + $"<p>{line}</p>");
return new HtmlString(result);
}
}
/// <summary>
/// Gibt den Display-Name für einen Enum-Wert zurück
/// </summary>
/// <param name="enumValue">enum-Wert</param>
/// <param name="stringLocalizer">Stringlocalizer der verwendet werden soll</param>
/// <returns>Displayname</returns>
public static string GetDisplayName(this Enum enumValue, IStringLocalizer stringLocalizer)
{
var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>();
var name = displayAttribute.GetName();
var translation = stringLocalizer[name];
return translation;
}
/// <summary>
/// Prüft ob eine Adresse gegenüber dem Viewmodel Änderungen hat
/// </summary>
/// <param name="address">Adresse</param>
/// <param name="addressVm">Viewmodel der Adresse</param>
/// <returns>true wenn es Änderungen gab, false sonst</returns>
public static bool HasChanges(this Address address, AddressVm addressVm)
{
if (address.AddressLine1 != addressVm.AddressLine1)
return true;
if (address.AddressLine2 != addressVm.AddressLine2)
return true;
if (address.Zip != addressVm.Zip)
return true;
if (address.City != addressVm.City)
return true;
if (address.State != addressVm.State)
return true;
if (address.CountryCode != addressVm.CountryCode)
return true;
return false;
}
/// <summary>
/// Prüft ob eine Adresse gegenüber dem Viewmodel Änderungen hat
/// </summary>
/// <param name="address">Adresse</param>
/// <param name="addressVm">Viewmodel der Adresse</param>
/// <returns>true wenn es Änderungen gab, false sonst</returns>
public static bool HasChanges(this Address address, AddressRequiredVm addressVm)
{
if (address.AddressLine1 != addressVm.AddressLine1)
return true;
if (address.AddressLine2 != addressVm.AddressLine2)
return true;
if (address.Zip != addressVm.Zip)
return true;
if (address.City != addressVm.City)
return true;
if (address.State != addressVm.State)
return true;
if (address.CountryCode != addressVm.CountryCode)
return true;
return false;
}
}
}