using FluentValidation;
using Raven.Client.Documents;
using System.Globalization;
namespace zero.Validation;
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, IZeroStore store) where T : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
{
bool any = await store.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, IZeroStore store, TProperty expectedValue) where T : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
{
return await store.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, IZeroStore 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, IZeroStore store) where T : ZeroEntity where TReference : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, id, context, cancellation) =>
{
if (id.IsNullOrWhiteSpace())
{
return true;
}
TReference model = await store.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");
}
///
/// Check if this value is unique within a collection
///
public static IRuleBuilderOptions Unique(this IRuleBuilder ruleBuilder, IZeroDocumentSession session) where T : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
{
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, IZeroDocumentSession session, TProperty expectedValue) where T : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, value, context, cancellation) =>
{
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, IZeroDocumentSession session) where T : ZeroEntity
{
return ruleBuilder.Exists(session);
}
///
/// 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, IZeroDocumentSession session) where T : ZeroEntity where TReference : ZeroEntity
{
return ruleBuilder.MustAsync(async (entity, id, context, cancellation) =>
{
if (id.IsNullOrWhiteSpace())
{
return true;
}
TReference model = await session.LoadAsync(id);
return model != null;
}).WithMessage("@errors.forms.reference_notfound");
}
}