1 /**
2 	Parameter validation types transparently supported for web interface methods.
3 
4 	Copyright: © 2014 RejectedSoftware e.K.
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Sönke Ludwig
7 */
8 module hb.web.validation;
9 
10 import vibe.utils.validation;
11 
12 import std.array : appender;
13 import std.typecons : Nullable;
14 
15 
16 /**
17 	Validated e-mail parameter type.
18 
19 	See_also: $(D vibe.utils.validation.validateEmail)
20 */
21 struct ValidEmail {
22 	private string m_value;
23 
24 	private this(string value) { m_value = value; }
25 	@disable this();
26 
27 	string toString() const pure nothrow @safe { return m_value; }
28 	alias toString this;
29 
30 	static Nullable!ValidEmail fromStringValidate(string str, string* error)
31 	{
32 		// work around disabled default construction
33 		Nullable!ValidEmail ret = Nullable!ValidEmail(ValidEmail(null));
34 		ret.nullify();
35 
36 		auto err = appender!string(); // TODO: avoid allocations when possible
37 		if (validateEmail(err, str)) ret = ValidEmail(str);
38 		else *error = err.data;
39 		return ret;
40 	}
41 }
42 
43 ///
44 unittest {
45 	class WebService {
46 		void setEmail(ValidEmail email)
47 		{
48 			// email is enforced to be valid here
49 		}
50 
51 		void updateProfileInfo(Nullable!ValidEmail email, Nullable!string full_name)
52 		{
53 			// email is optional, but always valid
54 			// full_name is optional and not validated
55 		}
56 	}
57 }
58 
59 
60 /**
61 	Validated user name parameter type.
62 
63 	See_also: $(D vibe.utils.validation.validateUsername)
64 */
65 struct ValidUsername {
66 	private string m_value;
67 
68 	private this(string value) { m_value = value; }
69 	@disable this();
70 
71 	string toString() const pure nothrow @safe { return m_value; }
72 	alias toString this;
73 
74 	static Nullable!ValidUsername fromStringValidate(string str, string* error)
75 	{
76 		// work around disabled default construction
77 		Nullable!ValidUsername ret = Nullable!ValidUsername(ValidUsername(null));
78 		ret.nullify();
79 
80 		auto err = appender!string(); // TODO: avoid allocations when possible
81 		if (validateUserName(err, str)) ret = ValidUsername(str);
82 		else *error = err.data;
83 		return ret;
84 	}
85 }
86 
87 ///
88 unittest {
89 	class WebService {
90 		void setUsername(ValidUsername username)
91 		{
92 			// username is enforced to be valid here
93 		}
94 
95 		void updateProfileInfo(Nullable!ValidUsername username, Nullable!string full_name)
96 		{
97 			// username is optional, but always valid
98 			// full_name is optional and not validated
99 		}
100 	}
101 }
102 
103 
104 /**
105 	Validated password parameter.
106 
107 	See_also: $(D vibe.utils.validation.validatePassword)
108 */
109 struct ValidPassword {
110 	private string m_value;
111 
112 	private this(string value) { m_value = value; }
113 	@disable this();
114 
115 	string toString() const pure nothrow @safe { return m_value; }
116 	alias toString this;
117 
118 	static Nullable!ValidPassword fromStringValidate(string str, string* error)
119 	{
120 		// work around disabled default construction
121 		Nullable!ValidPassword ret = Nullable!ValidPassword(ValidPassword(null));
122 		ret.nullify();
123 
124 		auto err = appender!string(); // TODO: avoid allocations when possible
125 		if (validatePassword(err, str, str)) ret = ValidPassword(str);
126 		else *error = err.data;
127 		return ret;
128 	}
129 }
130 
131 
132 /**
133 	Ensures that the parameter value matches that of another parameter.
134 */
135 struct Confirm(string CONFIRMED_PARAM)
136 {
137 	enum confirmedParameter = CONFIRMED_PARAM;
138 
139 	private string m_value;
140 
141 	string toString() const pure nothrow @safe { return m_value; }
142 	alias toString this;
143 
144 	static Confirm fromString(string str) { return Confirm(str); }
145 }
146 
147 ///
148 unittest {
149 	class WebService {
150 		void setPassword(ValidPassword password, Confirm!"password" password_confirmation)
151 		{
152 			// password is valid and guaranteed to equal password_confirmation
153 		}
154 
155 		void setProfileInfo(string full_name, Nullable!ValidPassword password, Nullable!(Confirm!"password") password_confirmation)
156 		{
157 			// Password is valid and guaranteed to equal password_confirmation
158 			// It is allowed for both, password and password_confirmation
159 			// to be absent at the same time, but not for only one of them.
160 		}
161 	}
162 }