/Sample Apps/TodoApp/TodoApp/Oak/Validation.cs

https://github.com/lefthandedgoat/Oak · C# · 408 lines · 287 code · 121 blank · 0 comment · 75 complexity · cf2eec05ff5d6be738a4c2a3296a0b0a MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using Massive;
  6. using System.Text.RegularExpressions;
  7. namespace Oak
  8. {
  9. public class Validations
  10. {
  11. dynamic @this;
  12. List<dynamic> rules;
  13. List<dynamic> errors;
  14. public Validations(dynamic mixWith)
  15. {
  16. rules = new List<dynamic>();
  17. errors = new List<dynamic>();
  18. @this = mixWith;
  19. if (HasValidationCapabilities(mixWith))
  20. {
  21. mixWith.SetMember("Errors", new DynamicFunction(Errors));
  22. mixWith.SetMember("IsValid", new DynamicFunctionWithParam(IsValid));
  23. mixWith.SetMember("FirstError", new DynamicFunction(FirstError));
  24. IEnumerable<dynamic> validationRules = @this.Validates();
  25. foreach (var validationRule in validationRules)
  26. {
  27. validationRule.Init(mixWith);
  28. AddRule(validationRule);
  29. }
  30. }
  31. }
  32. public bool HasValidationCapabilities(dynamic mixWith)
  33. {
  34. return mixWith.GetType().GetMethod("Validates") != null || mixWith.RespondsTo("Validates");
  35. }
  36. public void AddError(string property, string message)
  37. {
  38. errors.Add(new KeyValuePair<string, string>(property, message));
  39. }
  40. public void AddRule(dynamic rule)
  41. {
  42. rules.Add(rule);
  43. }
  44. public dynamic Errors()
  45. {
  46. return errors;
  47. }
  48. public virtual dynamic IsValid(dynamic property)
  49. {
  50. if(property == null) return IsValid(s => true);
  51. return IsValid(s => s.Property == property);
  52. }
  53. public virtual bool IsValid(Func<dynamic, bool> filter)
  54. {
  55. errors.Clear();
  56. bool isValid = true;
  57. foreach (var rule in rules.Where(filter)) isValid = Validate(rule) && isValid;
  58. return isValid;
  59. }
  60. public bool Validate(dynamic rule)
  61. {
  62. if (rule.Before != null) rule.Before();
  63. if (rule.If != null && !rule.If()) return true;
  64. if (rule.Unless != null && rule.Unless()) return true;
  65. bool isValid = rule.Validate(@this);
  66. if (rule.After != null) rule.After();
  67. if (!isValid) AddError(rule.Property, rule.Message());
  68. return isValid;
  69. }
  70. public dynamic FirstError()
  71. {
  72. return errors.First().Value;
  73. }
  74. }
  75. public class Validation
  76. {
  77. public string Property { get; set; }
  78. public string ErrorMessage { get; set; }
  79. public Validation(string property)
  80. {
  81. Property = property;
  82. }
  83. public virtual void Init(dynamic entity)
  84. {
  85. AddProperty(entity, Property);
  86. }
  87. public void AddProperty(dynamic entity, string property)
  88. {
  89. if (!entity.RespondsTo(property)) entity.SetMember(property, null);
  90. }
  91. public virtual string Message()
  92. {
  93. if (!string.IsNullOrEmpty(ErrorMessage)) return ErrorMessage;
  94. return Property + " is invalid.";
  95. }
  96. public dynamic StringifyValue(dynamic entity)
  97. {
  98. var value = PropertyValueIn(entity);
  99. return (value ?? "").ToString();
  100. }
  101. public dynamic PropertyValueIn(dynamic entity)
  102. {
  103. return PropertyValueIn(Property, entity);
  104. }
  105. public dynamic PropertyValueIn(string property, dynamic entity)
  106. {
  107. return entity.GetMember(property);
  108. }
  109. public Func<bool> If { get; set; }
  110. public Func<bool> Unless { get; set; }
  111. public Action Before { get; set; }
  112. public Action After { get; set; }
  113. }
  114. public class Acceptance : Validation
  115. {
  116. public Acceptance(string property)
  117. : base(property)
  118. {
  119. Accept = true;
  120. }
  121. public dynamic Accept { get; set; }
  122. public bool Validate(dynamic entity)
  123. {
  124. return PropertyValueIn(entity).Equals(Accept);
  125. }
  126. }
  127. public class Confirmation : Validation
  128. {
  129. public Confirmation(string property)
  130. : base(property)
  131. {
  132. }
  133. public override void Init(dynamic entity)
  134. {
  135. base.Init(entity as object);
  136. AddProperty(entity, Property + "Confirmation");
  137. }
  138. public bool Validate(dynamic entity)
  139. {
  140. return PropertyValueIn(entity) == PropertyValueIn(Property + "Confirmation", entity);
  141. }
  142. }
  143. public class Exclusion : Validation
  144. {
  145. public Exclusion(string property)
  146. : base(property)
  147. {
  148. }
  149. public dynamic[] In { get; set; }
  150. public bool Validate(dynamic entity)
  151. {
  152. return !In.Contains(PropertyValueIn(entity) as object);
  153. }
  154. }
  155. public class Format : Validation
  156. {
  157. public Format(string property)
  158. : base(property)
  159. {
  160. }
  161. public string With { get; set; }
  162. public bool Validate(dynamic entity)
  163. {
  164. return Regex.IsMatch(StringifyValue(entity), With);
  165. }
  166. }
  167. public class Inclusion : Validation
  168. {
  169. public Inclusion(string property)
  170. : base(property)
  171. {
  172. }
  173. public dynamic[] In { get; set; }
  174. public bool Validate(dynamic entity)
  175. {
  176. return In.Contains(PropertyValueIn(entity) as object);
  177. }
  178. }
  179. public class Presence : Validation
  180. {
  181. public Presence(string property)
  182. : base(property)
  183. {
  184. }
  185. public override void Init(dynamic entity)
  186. {
  187. base.Init(entity as object);
  188. if (string.IsNullOrEmpty(ErrorMessage)) ErrorMessage = Property + " is required.";
  189. }
  190. public bool Validate(dynamic entity)
  191. {
  192. return !string.IsNullOrEmpty(StringifyValue(entity));
  193. }
  194. }
  195. public class Uniqueness : Validation
  196. {
  197. public Uniqueness(string property, DynamicRepository usingRepository)
  198. : base(property)
  199. {
  200. Repository = usingRepository;
  201. }
  202. public override void Init(dynamic entity)
  203. {
  204. base.Init(entity as object);
  205. if (string.IsNullOrEmpty(ErrorMessage)) ErrorMessage = Property + " is taken.";
  206. }
  207. public DynamicRepository Repository { get; set; }
  208. public bool Validate(dynamic entity)
  209. {
  210. object value = entity.GetMember(Property);
  211. var whereClause = Property + " = @0";
  212. var values = new List<object> { value };
  213. if (entity.RespondsTo(Repository.PrimaryKeyField))
  214. {
  215. whereClause += " and [" + Repository.PrimaryKeyField + "] != @1";
  216. values.Add(entity.Id);
  217. }
  218. if (Repository.SingleWhere(whereClause, values.ToArray()) != null) return false;
  219. return true;
  220. }
  221. }
  222. public class Numericality : Validation
  223. {
  224. public Numericality(string property)
  225. : base(property)
  226. {
  227. }
  228. public bool OnlyInteger { get; set; }
  229. public double? GreaterThan { get; set; }
  230. public double? GreaterThanOrEqualTo { get; set; }
  231. public double? EqualTo { get; set; }
  232. public double? LessThan { get; set; }
  233. public double? LessThanOrEqualTo { get; set; }
  234. public bool Odd { get; set; }
  235. public bool Even { get; set; }
  236. public bool Validate(dynamic entity)
  237. {
  238. string value = entity.GetMember(Property).ToString();
  239. var decimalValue = Double(value);
  240. if (decimalValue == null) return false;
  241. if (OnlyInteger == true && !IsInteger(value)) return false;
  242. if (GreaterThan != null && decimalValue <= GreaterThan) return false;
  243. if (GreaterThanOrEqualTo != null && decimalValue < GreaterThanOrEqualTo) return false;
  244. if (EqualTo != null && decimalValue != EqualTo) return false;
  245. if (LessThan != null && decimalValue >= LessThan) return false;
  246. if (LessThanOrEqualTo != null && decimalValue > LessThanOrEqualTo) return false;
  247. if (Odd == true && decimalValue % 2 == 0) return false;
  248. if (Even == true && decimalValue % 2 == 1) return false;
  249. return true;
  250. }
  251. public double? Double(string value)
  252. {
  253. double doubleResult;
  254. if (double.TryParse(value, out doubleResult)) return doubleResult;
  255. return null;
  256. }
  257. public bool IsInteger(string value)
  258. {
  259. int intResult;
  260. return int.TryParse(value, out intResult);
  261. }
  262. }
  263. public class Length : Validation
  264. {
  265. public Length(string property)
  266. : base(property)
  267. {
  268. }
  269. public int? Minimum { get; set; }
  270. public int? Maximum { get; set; }
  271. public IEnumerable<int> In { get; set; }
  272. public int? Is { get; set; }
  273. public bool IgnoreNull { get; set; }
  274. public bool Validate(dynamic entity)
  275. {
  276. dynamic value = entity.GetMember(Property);
  277. if (value == null && IgnoreNull == true) return true;
  278. if (value == null) return false;
  279. int length = value.Length;
  280. if (Minimum != null && length < Minimum) return false;
  281. if (Maximum != null && length > Maximum) return false;
  282. if (In != null && !In.Contains(length)) return false;
  283. if (Is != null && length != Is) return false;
  284. return true;
  285. }
  286. }
  287. }