1 module konnexengine.user.blueprint;
2 
3 import std.uuid : UUID, sha1UUID;
4 
5 import konnexengine.contacts.naturalperson : NaturalPersonName;
6 import konnexengine.app.data : AppData;
7 
8 /// UserInterface: `interface`	 
9 interface UserInterface
10 {
11 	@property UUID id();
12 	@property EmailAddress[UUID] email();
13 	@property string username();
14 	@property DisplayName[UUID] displayName();
15 	@property NaturalPersonName realName();
16 	@property SocialAccount[UUID] socialAccounts();
17 	@property PhoneNumber[UUID] phoneNumbers();
18 	@property PostalAddress[UUID] addresses();
19 	@property User[UUID] list();
20 }
21 
22 /// User - `class implements UserInterface`
23 class User : UserInterface
24 {
25 	this()
26 	{
27 	}
28 	// TODO: Normailse user object
29 	private
30 	{
31 		UUID u_id;
32 		EmailAddress[UUID] u_emails;
33 		string u_username;
34 		DisplayName[UUID] u_displayName;
35 		NaturalPersonName u_realName;
36 		SocialAccount[UUID] u_socials;
37 		PhoneNumber[UUID] u_numbers;
38 		PostalAddress[UUID] u_addresses;
39 		User[UUID] u_list;
40 	}
41 
42 	/// id() - `UUID`
43 	@property UUID id()
44 	{
45 		return u_id;
46 	}
47 
48 	/// id(UUID input) -`UUID`
49 	@property UUID id(UUID input)
50 	{
51 		return u_id = input;
52 	}
53 
54 	@property EmailAddress[UUID] email()
55 	{
56 		return u_emails;
57 	}
58 
59 	@property EmailAddress[UUID] email(EmailAddress input)
60 	{
61 		u_emails[input.id] = input;
62 		return u_emails;
63 	}
64 
65 	@property string username()
66 	{
67 		return u_username;
68 	}
69 
70 	@property string username(string input)
71 	{
72 		return u_username = "" ~ input;
73 	}
74 
75 	@property DisplayName[UUID] displayName()
76 	{
77 		return u_displayName;
78 	}
79 
80 	@property DisplayName[UUID] displayName(DisplayName input)
81 	{
82 		u_displayName[input.id] = input;
83 		return u_displayName;
84 	}
85 
86 	@property NaturalPersonName realName()
87 	{
88 		return u_realName;
89 	}
90 
91 	@property NaturalPersonName realName(NaturalPersonName input)
92 	{
93 		return u_realName = input;
94 	}
95 
96 	@property SocialAccount[UUID] socialAccounts()
97 	{
98 		return u_socials;
99 	}
100 
101 	@property SocialAccount[UUID] socialAccounts(SocialAccount input)
102 	{
103 		u_socials[input.id] = input;
104 		return u_socials;
105 	}
106 
107 	@property PhoneNumber[UUID] phoneNumbers()
108 	{
109 		return u_numbers;
110 	}
111 
112 	@property PhoneNumber[UUID] phoneNumbers(PhoneNumber input)
113 	{
114 		u_numbers[input.id] = input;
115 		return u_numbers;
116 	}
117 
118 	@property PostalAddress[UUID] addresses()
119 	{
120 		return u_addresses;
121 	}
122 
123 	@property PostalAddress[UUID] addresses(PostalAddress input)
124 	{
125 		u_addresses[input.id] = input;
126 		return u_addresses;
127 	}
128 
129 	@property User[UUID] list()
130 	{
131 		return u_list;
132 	}
133 
134 	@property User[UUID] list(User input)
135 	{
136 		u_list[input.id] = input;
137 		return u_list;
138 	}
139 
140 	string deleteEntry(T)(T t)
141 	{
142 		logInfo("Delete function not implemented");
143 		auto message = "" ~ typeof(t) ~ ": " ~ t.id ~ " not deleted";
144 		return "";
145 	}
146 }
147 ///
148 unittest
149 {
150 	import std.conv : to;
151 
152 	User[UUID] users;
153 	for (ushort i = 1; i <= 10; i++)
154 	{
155 		auto user = new User();
156 		auto testID = sha1UUID("test" ~ i.to!string, sha1UUID("namespace"));
157 		user.id(testID);
158 		auto testemail = new EmailAddress("test" ~ i.to!string ~ "@email.com");
159 		user.email(testemail);
160 		user.username("test" ~ i.to!string);
161 		users[user.id] = user;
162 	}
163 
164 	assert(is(typeof(users) == User[UUID]));
165 
166 	auto user = users[users.keys()[0]];
167 	assert(is(typeof(user) == User));
168 	assert(is(typeof(user.id) == UUID));
169 	assert(is(typeof(user.email) == EmailAddress[UUID]));
170 	assert(is(typeof(user.username) == string));
171 	assert(user.id() == sha1UUID(user.username, sha1UUID("namespace")));
172 	assert(user.email() == user.email());
173 	assert(user.username() == user.username);
174 	import vibe.core.log: logInfo;
175 	import std.conv: to;
176 	logInfo(user.email().values()[0].get());
177 
178 }
179 
180 /// Email Address: `class`
181 class EmailAddress
182 {
183 	UUID id;
184 	import std.array : split;
185 
186 	this(string email)
187 	{
188 		this.emailHandle = email.split("@")[0];
189 		this.emailDomain = email.split("@")[1];
190 		this.id = sha1UUID(emailHandle, sha1UUID(emailDomain));
191 		this.emailAddress = this.emailHandle ~ "@" ~ this.emailDomain;
192 	}
193 
194 	private
195 	{
196 
197 		string emailHandle;
198 		string emailDomain;
199 		string emailAddress;
200 	}
201 
202 	@property string get()
203 	{
204 		return emailAddress;
205 	}
206 
207 	@property string get(string input)
208 	{
209 		if(input == "handle")
210 		{
211 			return emailHandle;
212 		} 
213 		else if(input == "domain")
214 		{
215 			return emailDomain;
216 		}
217 		else
218 		{
219 			throw new Error("Invalid Input Argument: only accepts \"handle\" or \"domain\"");
220 		}
221 
222 		
223 	}
224 
225 }
226 ///
227 unittest
228 {
229 	auto address = new EmailAddress("test1@email.com");
230 	assert(is(typeof(address) == EmailAddress));
231 	assert(is(typeof(address.id) == UUID));
232 	assert(is(typeof(address.emailHandle) == string));
233 	assert(is(typeof(address.emailDomain) == string));
234 	assert(is(typeof(address.emailAddress) == string));
235 	assert(address.id == sha1UUID(address.emailHandle, sha1UUID(address.emailDomain)));
236 	assert(address.emailHandle == "test1");
237 	assert(address.emailDomain == "email.com");
238 	assert(address.emailAddress == "test1@email.com");
239 }
240 
241 /// PhoneNumber: `struct`
242 struct PhoneNumber
243 {
244 	UUID id;
245 	string countryCode;
246 	string phoneNumber;
247 	string extension;
248 }
249 ///
250 unittest
251 {
252 	auto number = PhoneNumber(sha1UUID("test", sha1UUID("namespace")), "44", "07999999999", "369");
253 
254 	assert(is(typeof(number) == PhoneNumber));
255 	assert(is(typeof(number.id) == UUID));
256 	assert(is(typeof(number.countryCode) == string));
257 	assert(is(typeof(number.phoneNumber) == string));
258 	assert(is(typeof(number.extension) == string));
259 	assert(number.id == sha1UUID("test", sha1UUID("namespace")));
260 	assert(number.countryCode == "44");
261 	assert(number.phoneNumber == "07999999999");
262 	assert(number.extension == "369");
263 }
264 
265 /// PostalAddress - `struct`
266 struct PostalAddress
267 {
268 	UUID id;
269 	string buildingNumber;
270 	string buildingName;
271 	string unitNumber;
272 	string[] streetAddress;
273 	string town;
274 	string city;
275 	string county;
276 	string country;
277 }
278 
279 /// SocialAccount `struct`
280 struct SocialAccount
281 {
282 	UUID id;
283 	string platform;
284 	string handle;
285 	string homepage;
286 }
287 ///
288 unittest
289 {
290 	import std.uuid : UUID, sha1UUID;
291 
292 	auto account = SocialAccount(sha1UUID("test", sha1UUID("namespace")),
293 			"facebook", "konnex-engine", "konnex");
294 	assert(is(typeof(account) == SocialAccount));
295 	assert(is(typeof(account.id) == UUID));
296 	assert(is(typeof(account.platform) == string));
297 	assert(is(typeof(account.handle) == string));
298 	assert(is(typeof(account.homepage) == string));
299 	assert(account.id == sha1UUID("test", sha1UUID("namespace")));
300 	assert(account.platform == "facebook");
301 	assert(account.handle == "konnex-engine");
302 	assert(account.homepage == "konnex");
303 
304 }
305 
306 struct DisplayName
307 {
308 	UUID id;
309 	string prefix;
310 	string value;
311 	string suffix;
312 
313 	DisplayName[] list = [];
314 }