using FluentValidation; using Raven.Client.Documents; using Raven.Client.Documents.Session; using System; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; using zero.Core.Api; using zero.Core.Entities; namespace zero.Core.Extensions { public static class ValidatorExtensions { private const char DOT = '.'; private const char KLAMMERAFFE = '@'; private static string HEX_REGEX = "#[0-9a-fA-F]{3,8}"; /// /// Validate a color input as HEX (#aabbccdd or #aabbcc or #abc) /// public static IRuleBuilderOptions Hex(this IRuleBuilder ruleBuilder) { return ruleBuilder.Matches(HEX_REGEX).WithMessage("@errors.forms.hex_format"); } /// /// Validate an email /// public static IRuleBuilderOptions Url(this IRuleBuilder ruleBuilder) { return ruleBuilder.Must((root, value, context) => { return value.IsNullOrWhiteSpace() || Uri.IsWellFormedUriString(value, UriKind.Absolute); }).WithMessage("@errors.forms.url_format"); } /// /// Validate an email /// public static IRuleBuilderOptions Email(this IRuleBuilder ruleBuilder) { return ruleBuilder.Must((root, value, context) => { if (value.IsNullOrWhiteSpace()) { return true; } int index = value.IndexOf(KLAMMERAFFE); if (index < 0 || index == value.Length - 1 || index != value.LastIndexOf(KLAMMERAFFE)) { return false; } return true; }).WithMessage("@errors.forms.email_invalid"); } /// /// Validate one or multiple emails /// public static IRuleBuilderOptions Emails(this IRuleBuilder ruleBuilder) { return ruleBuilder.Must((root, value, context) => { if (value.IsNullOrWhiteSpace()) { return true; } string[] mails = value.Split(',', ';').Select(x => x.Trim()).Where(x => !x.IsNullOrWhiteSpace()).ToArray(); if (!mails.Any()) { return false; } foreach (string mail in mails) { int index = value.IndexOf(KLAMMERAFFE); if (index < 0 || index == value.Length - 1 || index != value.LastIndexOf(KLAMMERAFFE)) { return false; } } return true; }).WithMessage("@errors.forms.emails_invalid"); } /// /// Check if this value is unique within a collection /// public static IRuleBuilderOptions Unique(this IRuleBuilder ruleBuilder, IBackofficeStore store) where T : ZeroEntity { return ruleBuilder.MustAsync(async (entity, value, context, cancellation) => { using IAsyncDocumentSession session = store.Store.OpenAsyncSession(); bool any = await session.Advanced.AsyncDocumentQuery() .WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id) .WhereEquals(context.PropertyName.ToPascalCaseId(), value) .AnyAsync(cancellation); return !any; }).WithMessage("@errors.forms.not_unique"); } /// /// Check if this value is at least set once to the expected value within a collection /// public static IRuleBuilderOptions ExpectAnyUnique(this IRuleBuilder ruleBuilder, IBackofficeStore store, TProperty expectedValue) where T : ZeroEntity { return ruleBuilder.MustAsync(async (entity, value, context, cancellation) => { using IAsyncDocumentSession session = store.Store.OpenAsyncSession(); return await session.Advanced.AsyncDocumentQuery() .WhereNotEquals(nameof(ZeroIdEntity.Id), entity.Id) .WhereEquals(context.PropertyName.ToPascalCaseId(), expectedValue) .AnyAsync(cancellation); }).WithMessage("@errors.forms.not_unique_alone"); } /// /// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current) /// public static IRuleBuilderOptions Exists(this IRuleBuilder ruleBuilder, IBackofficeStore store) where T : ZeroEntity { return ruleBuilder.Exists(store); } /// /// Check if this reference exists and is an entity which can be referenced (appId = shared for shareable entities or appId = current) /// public static IRuleBuilderOptions Exists(this IRuleBuilder ruleBuilder, IBackofficeStore store) where T : ZeroEntity where TReference : ZeroEntity { return ruleBuilder.MustAsync(async (entity, id, context, cancellation) => { if (id.IsNullOrWhiteSpace()) { return true; } using IAsyncDocumentSession session = store.Store.OpenAsyncSession(); TReference model = await session.LoadAsync(id); return model != null; }).WithMessage("@errors.forms.reference_notfound"); } /// /// Validates a culture identifier /// public static IRuleBuilderOptions Culture(this IRuleBuilder ruleBuilder) { return ruleBuilder.Must((root, value, context) => { if (value.IsNullOrWhiteSpace()) { return true; } try { CultureInfo info = CultureInfo.GetCultureInfo(value); return info != null && !info.EnglishName.Equals(value, StringComparison.InvariantCultureIgnoreCase); } catch { return false; } }).WithMessage("@errors.forms.culture"); } } }