· 5 years ago · May 27, 2020, 06:12 PM
1import { Gender, prisma, User, KudaLog } from "../schema/generated/prisma-client";
2const dateFormat = require("dateformat");
3const bcrypt = require("bcryptjs");
4import { sign } from "jsonwebtoken";
5import { salt } from "../const";
6import mail from "../functions/mail";
7import { verifyToken } from "../middleware/utils";
8require("dotenv").config();
9
10const fs = require("fs");
11const Kuda = require('kuda-node');
12
13const publicKey = fs.readFileSync(__dirname + "/key/publickey.xml"); // or path to your kuda public key
14const privateKey = fs.readFileSync(__dirname + "/key/31BGNW8Y2eIb6nw49oOr.xml"); // or path to your kuda kuda private key
15const clientKey = "31BGNW8Y2eIb6nw49oOr"; // name of private key file without the .xml suffix (extension)
16
17const kuda = Kuda({
18 publicKey,
19 privateKey,
20 clientKey
21});
22
23/**
24 * Function to validate email address
25 * @param {String} email {Required} The email to be validated
26 * @return {Boolean} A Boolean value indicating if the email is valid
27 * N/B
28 * This isn't fool proof and there is no fool proof way of
29 * validating an email address.
30 */
31const validateEmail = (email: string) => {
32 const pattern = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/;
33 if (!email.match(pattern)) {
34 throw new Error("Email address not supported");
35 }
36};
37
38
39
40const createVirtualAccount = async function kudaCreateAccount(
41 email,
42 phoneNumber,
43 firstName,
44 lastName,
45 trackingReference
46) {
47 try {
48 // console.log(firstName, lastName)
49 const response = await kuda({
50 serviceType: "CREATE_VIRTUAL_ACCOUNT",
51 requestRef: Math.floor(Math.random() * 1000000000000 + 1),
52 data: { email, phoneNumber, firstName, lastName, trackingReference }
53 });
54 // console.log("Kuda Virtual Created \n", response.Data);
55 return response;
56 } catch (error) {
57 console.error("Error Kuda Virtual Creation", error);
58 }
59 return true;
60}
61
62// Retrieve virtual account
63const retrieveVirtualAccount = async function retrieveAccount(trackingReference) {
64 try {
65 const response = await kuda(
66 {
67 serviceType: "RETRIEVE_VIRTUAL_ACCOUNT",
68 requestRef: Math.floor(Math.random() * 1000000000000 + 1),
69 data: {
70 trackingReference: trackingReference
71 }
72 });
73 return response;
74 } catch (error) {
75 console.error("Error Kuda Virtual Creation", error);
76 }
77 return true;
78};
79
80const nameEnquiry = async (
81 beneficiaryAccountNumber, // beneficiary accont number
82 bankCode,
83 senderTrackingReference // sender tracking reference
84) => {
85 kuda(
86 {
87 serviceType: "NAME_ENQUIRY",
88 requestRef: Math.floor(Math.random() * 1000000000000 + 1), // you can generate your random number your own way. This is just an example.
89 data: {
90 beneficiaryAccountNumber: beneficiaryAccountNumber,
91 bankCode: bankCode,
92 senderTrackingReference: senderTrackingReference
93 }
94 },
95 data => {
96 // data => decrypted response from Kuda API
97 // do anything with your data
98 console.log(JSON.stringify(data, null, 2));
99 return data.Data.nameEnquiryID;
100 }
101 );
102};
103
104export async function queryTrackingReference(trackingReference: string) {
105
106 const trackingRf = await prisma.user({
107 trackingReference
108 });
109 // If it is null, does not exist
110 if (trackingRf == null) {
111 return {
112 trackingReference,
113 status: "false"
114 };
115 }
116 // If it is not null, exists
117 if (trackingRf != null) {
118 return {
119 trackingReference,
120 status: "true"
121 };
122 }
123}
124
125const validateTransactionPin = (pin: string, repeatPin: string) => {
126 const pattern = /^[0-9]*$/gm;
127 if (pin.length !== 4) {
128 throw new Error("Invalid transaction pin");
129 }
130 if (pin !== repeatPin) {
131 throw new Error("Your pin is not the same");
132 }
133 if (!pin.match(pattern)) {
134 throw new Error("Invalid transaction pin");
135 }
136};
137
138const validateFullName = (fullname: string) => {
139 const pattern1 = /^[a-zA-Z]+ [a-zA-Z]+ [a-zA-Z]+$/;
140 const pattern2 = /^[a-zA-Z]+ [a-zA-Z]+$/;
141 if (fullname.match(pattern1) || fullname.match(pattern2)) {
142 return true;
143 } else {
144 throw new Error("Invalid name");
145 }
146};
147
148export async function authenticateUser(phonenumber: string) {
149 // check if phone number is an actual phone number
150 if (phonenumber.length < 11) {
151 throw new Error("Your phone number is incomplete");
152 }
153 // convert phone number to +234 format
154 if (phonenumber.startsWith("0")) {
155 let tel = phonenumber;
156 phonenumber = "+234" + tel.substr(1);
157 }
158 const user = await prisma.user({
159 phonenumber
160 });
161 if (user == null) {
162 return {
163 phonenumber,
164 status: "register"
165 };
166 }
167 if (!user.verified) {
168 return {
169 phonenumber,
170 status: "verify"
171 };
172 }
173 return {
174 phonenumber,
175 status: "login"
176 };
177}
178
179export async function createUser(data: User) {
180 // extract the date of birth and password for modifications
181 let { DOB, password, email, phonenumber, fullname, profile_picture, trackingReference } = data;
182 // let { timestamp, endpoint, status, message } = kudaLogData;
183 // check if phone number is an actual phone number
184 if (phonenumber.length < 11) {
185 throw new Error("Your phone number is incomplete");
186 }
187
188 const splitFullname = fullname.split(' ');
189 let firstname = splitFullname[0];
190 let lastname = splitFullname[1];
191
192 // validate the geniunity of email address
193 await validateEmail(email);
194
195 // validate users name
196 await validateFullName(fullname);
197
198 // convert phone number to +234 format
199 if (phonenumber.startsWith("0")) {
200 let tel = phonenumber;
201 phonenumber = "+234" + tel.substr(1);
202 }
203
204 // check if password is greater than 7 characters
205 if (password.length < 8) {
206 throw new Error("Your password should be greater than 7 characters");
207 }
208
209 let formatDate;
210 // format the date
211 formatDate = dateFormat(DOB, "yyyy-mm-dd HH:MM:ss");
212 // put in a format the database understands
213 formatDate = new Date(formatDate);
214 // hash password
215 password = bcrypt.hashSync(password, salt);
216
217 // add it back to the data object
218 data.DOB = formatDate;
219 data.password = password;
220 data.phonenumber = phonenumber;
221 data.trackingReference = trackingReference;
222
223 // const virtual_account = await createVirtualAccount(email, phonenumber, firstname, lastname, trackingReference);
224
225 // if (virtual_account.Status === false && virtual_account.Data == null) {
226 // let logData = {
227 // timestamp: new Date().toISOString(),
228 // endpoint: 'CREATE_VIRTUAL_ACCOUNT',
229 // status: false,
230 // message: 'Error from Kuda Bank'
231 // }
232 // await prisma.createKudaLog(logData);
233 // throw new Error("Account could not be created. Please try again!");
234 // } else {
235
236 // const getAccountNumber = await retrieveVirtualAccount('046ehddg-ebk');
237 // data.accountNumber = getAccountNumber.Data.accountNo
238 const user = await prisma.createUser(data);
239 // Kuda log data
240
241 // let logData = {
242 // timestamp: new Date().toISOString(),
243 // endpoint: 'CREATE_VIRTUAL_ACCOUNT',
244 // status: virtual_account.Status,
245 // message: virtual_account.Message
246 // }
247
248 // console.log('====================================');
249 // console.log(getAccountNumber);
250 // console.log('====================================');
251 // console.log(virtual_account);
252
253 // await prisma.createKudaLog(logData);
254
255 return sendVerificationCode(user.phonenumber);
256 // }
257}
258
259export async function setTransactionPin(
260 token: string,
261 // tslint:disable-next-line: variable-name
262 transaction_pin: string,
263 repeat_transaction_pin: string
264) {
265 // validate the transaction pin
266 await validateTransactionPin(transaction_pin, repeat_transaction_pin);
267 // hash transaction pin
268 transaction_pin = bcrypt.hashSync(transaction_pin, salt);
269}
270
271export async function sendVerificationCode(phonenumber: string, code?: number) {
272 // convert phone number to +234 format
273 if (phonenumber.startsWith("0")) {
274 let tel = phonenumber;
275 phonenumber = "+234" + tel.substr(1);
276 }
277 const user = await prisma.user({
278 phonenumber
279 });
280 // check if it has been verified
281 if (user.verified) {
282 throw new Error("User has been verified");
283 }
284 // generate a 6 digit number for verification if code is not present
285 if (!code) {
286 code = Math.floor(Math.random() * 900000) + 100000;
287 }
288 if (String(code).length !== 6) {
289 throw new Error("Code must be 6 digits");
290 }
291
292 // check if an activation Code exists before for the user
293 const verificationCodes = await prisma.verificationCodes({
294 where: {
295 user: {
296 phonenumber
297 }
298 }
299 });
300
301 let verificationCode;
302 // if it exists delete the verification code
303 if (verificationCodes.length > 0) {
304 verificationCode = verificationCodes[0];
305 await prisma.deleteVerificationCode({
306 id: verificationCode.id
307 });
308 }
309
310 // create the verification
311 const newVerificationCode = await prisma.createVerificationCode({
312 code,
313 user: {
314 connect: {
315 phonenumber
316 }
317 }
318 });
319
320 console.log('====================================');
321 console.log(user);
322 console.log('====================================');
323
324 const template = `
325 <html>
326
327 <head>
328 <title></title>
329 <link href='https://fonts.googleapis.com/css?family=Rubik' rel='stylesheet'>
330 <style>
331 @import url('https://fonts.googleapis.com/css?family=Rubik');
332 </style>
333 </head>
334
335 <body>
336 <div style="background-color:#f1f3f5;color:#233858;font-family:'Rubik';margin:0">
337 <div style="background-color:white;display:block;margin:0 auto;max-width:720px">
338 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
339 <tbody>
340 <tr>
341 <td
342 style="font-size:0!important;line-height:100%;padding-left:16px;padding-right:16px;padding-top:36px;text-align:center">
343
344 <div
345 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
346 <table width="100%" border="0" cellspacing="0" cellpadding="0"
347 style="min-width:100%;width:100%">
348 <tbody>
349 <tr>
350 <td
351 style="line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
352 <a href="#m_2661994423616798564_m_222366038327339295_"
353 style="color:#233858;font-family:'Rubik';text-decoration:underline">
354 <img src="https://img.techpowerup.org/200427/vector.png" width="64"
355 height="24" style="height:auto;max-width:200px;width:auto"
356 class="CToWUd">
357 <br />
358 <img src="https://img.techpowerup.org/200427/frame.png" width="64"
359 height="24"
360 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
361 class="CToWUd">
362 </a>
363 </td>
364 </tr>
365 </tbody>
366 </table>
367 <table align="center" width="100%" border="0" cellspacing="0" cellpadding="0"
368 style="display:table;margin-left:auto;margin-right:auto">
369 <tbody>
370 <tr>
371 <td
372 style="background-color:transparent!important;border-bottom:1px solid rgba(60,60,60,0.07);border-bottom-color:rgba(60,60,60,0.07);font-size:0;height:2px;line-height:1px;min-height:1px;overflow:hidden;padding-bottom:24px">
373 </td>
374 </tr>
375 </tbody>
376 </table>
377 </div>
378
379 </td>
380 </tr>
381 </tbody>
382 </table>
383
384 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
385 <tbody>
386 <tr>
387 <td
388 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
389
390 <div
391 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
392 <table width="100%" border="0" cellspacing="0" cellpadding="0"
393 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
394 <tbody>
395 <tr>
396 <td
397 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
398 <h1
399 style="color: #000000;text-align:center;font-family:'Rubik'!important;font-size:22px;font-weight:800;line-height:44px;margin-bottom:14px;margin-left:0;margin-right:0;margin-top:32px;padding:0">
400 Complete Your Registration Request</h1>
401 <p
402 style="color: #82859A;text-align:center;font-family:'Rubik';font-size:12px;line-height:1.6;margin-bottom:30px;margin-top:0;">
403 Dear ${user.fullname}, Please use the OTP: <span
404 style="color: #F26A21;">${newVerificationCode.code}</span> to complete your
405 registration</p>
406
407 <p
408 style="color: #82859A;font-family:'Rubik';font-size:13px;line-height:1.6;margin-top:0;padding-top:36px">
409 Thanks,</p>
410 <p
411 style="color: #82859A;font-family:'Rubik';font-size:13px!important;margin-top:10px">
412 The Ebucks Team.</p>
413 </td>
414 </tr>
415 </tbody>
416 </table>
417 </div>
418
419 </td>
420 </tr>
421 </tbody>
422 </table>
423
424 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
425 <tbody>
426 <tr>
427 <td
428 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
429 <div
430 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
431 <table width="100%" border="0" cellspacing="0" cellpadding="0"
432 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
433 <tbody>
434 <tr>
435 <td
436 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
437 <p
438 style="border-top:1px solid rgba(60,60,60,0.07);color: #82859A;font-family:'Rubik';font-size:13px;letter-spacing: 0.02em;line-height:1.6;margin-bottom:20px;margin-top:100px;padding-top:20px">
439 Fund Wallet & Purchase with ease with our app today, availabe on
440 <a href="#">Android</a> and <a href="#">iOS</a> (Coming Soon) </p>
441 </td>
442 </tr>
443 </tbody>
444 </table>
445 </div>
446
447 </td>
448 </tr>
449 </tbody>
450 </table>
451
452
453
454 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
455 <tbody>
456 <tr>
457 <td
458 style="background-color:#0041C4;display:block;font-size:0!important;height:270px;line-height:100%;margin-top:20px;padding-left:8px;padding-right:8px;text-align:center">
459
460 <div
461 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
462 <table width="100%" border="0" cellspacing="0" cellpadding="0"
463 style="min-width:100%;width:100%">
464 <tbody>
465 <tr>
466 <td
467 style="min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%">
468 <div
469 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
470 <table width="100%" border="0" cellspacing="0" cellpadding="0"
471 style="min-width:100%;padding-top:32px;width:100%">
472 <tbody>
473 <tr>
474 <td
475 style="color:#233858;font-size:16px;line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
476 <a href="#"
477 style="color:#233858;font-family:'Rubik';text-decoration:underline">
478 <img src="https://img.techpowerup.org/200427/frame-1.png"
479 width="64" height="24"
480 style="height:24px;max-width:200px;width:auto;"
481 class="CToWUd"> <br />
482 <img src="https://img.techpowerup.org/200427/frame-2.png"
483 width="64" height="24"
484 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
485 class="CToWUd">
486 </a>
487 </td>
488 </tr>
489 </tbody>
490 </table>
491 </div>
492 <div
493 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
494 <table width="100%" border="0" cellspacing="0" cellpadding="0"
495 style="margin-left:auto;margin-right:0;min-width:100%;padding-top:32px;text-align:right;width:100%">
496 <tbody>
497 <tr>
498 <td style="color:#233858;display:inline;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%; display: flex;
499 flex-direction: column;align-items: center;">
500 <a href="#"
501 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
502 target="_blank" data-saferedirecturl="#"><img
503 src="https://ci6.googleusercontent.com/proxy/QibhghTDk6b0hIfNEbXhPkXgN1dvldl09KWTEGXqVOqUVuIUMbye4bx_nb1fo3kXVlLdOqShZs8peXzMvw=s0-d-e1-ft#https://emery.cloudns.cx/static/img/tw.png"
504 alt="myebucks Twitter"
505 style="height:16px;margin-left:20px;max-width:200px;width:auto"
506 class="CToWUd"></a>
507 <a href="#"
508 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
509 target="_blank" data-saferedirecturl="#"><img
510 src="https://ci5.googleusercontent.com/proxy/D1G7umjs3HsEa9BlJ6D8ZYRJYHUIrFdZrWaLNQiUfInBYUQmHzcjoEsaCqSoyzFUzEQ6F8n2lT0N_2Mf2A=s0-d-e1-ft#https://emery.cloudns.cx/static/img/ig.png"
511 alt="myebucks Instagram"
512 style="height:16px;margin-left:20px;max-width:200px;width:auto"
513 class="CToWUd"></a>
514 <a href="#"
515 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
516 target="_blank" data-saferedirecturl="#"><img
517 src="https://ci3.googleusercontent.com/proxy/aVFBIC7qxNzk6PsoiyvWZjHrD6VrlqJ_aUP_yC3eiSLDZmAf2ID-qBV9sJDs7UUlwcgdEfkOCYFg15JaYA=s0-d-e1-ft#https://emery.cloudns.cx/static/img/fb.png"
518 alt="myebucks Facebook"
519 style="height:16px;margin-left:20px;max-width:200px;width:auto"
520 class="CToWUd"></a>
521 </td>
522 </tr>
523 </tbody>
524 </table>
525 </div>
526
527 <div
528 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
529 <table width="100%" border="0" cellspacing="0" cellpadding="0"
530 style="min-width:100%;padding-top:32px;width:100%">
531 <tbody>
532 <tr>
533 <td
534 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
535 <a href=""
536 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
537 target="_blank">Links</a>
538 <a href=""
539 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
540 target="_blank">About Us</a>
541 <a href=""
542 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
543 target="_blank">Careers</a>
544 <a href=""
545 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
546 target="_blank">Contact</a>
547 </td>
548 </tr>
549 </tbody>
550 </table>
551 </div>
552 <div
553 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
554 <table width="100%" border="0" cellspacing="0" cellpadding="0"
555 style="min-width:100%;padding-top:32px;width:100%">
556 <tbody>
557 <tr>
558 <td
559 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
560 <p
561 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
562 Office</p>
563 <p
564 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
565 23 Adekunle Akala Street,</p>
566 <p
567 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
568 Ajao Estate, Oshodi/Isolo.</p>
569 <p
570 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
571 Lagos State</p>
572 </td>
573 </tr>
574 </tbody>
575 </table>
576 </div>
577
578
579
580 <table align="center" width="100%" border="0" cellspacing="0"
581 cellpadding="0"
582 style="display:table;margin-left:auto;margin-right:auto;padding-top:32px">
583 <tbody>
584 <tr>
585 <td
586 style="background-color:transparent!important;border-bottom:1px solid rgba(255,255,255,0.07);color:#233858;font-size:16px;height:2px;line-height:1px;min-height:1px;overflow:hidden">
587 </td>
588 </tr>
589 </tbody>
590 </table>
591 </td>
592 </tr>
593 </tbody>
594 </table>
595 </div>
596
597 </td>
598 </tr>
599 </tbody>
600 </table>
601
602 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width: 100%; width: 100%;">
603 <tbody>
604 <tr>
605 <td
606 style="display: block; font-size: 0 !important;height: 20px;margin-top: 20px;padding-left: 8px;padding-right: 8px;">
607 <div
608 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;">
609 <table width="100%" border="0" cellspacing="0" cellpadding="0"
610 style="min-width:100%;width:100%">
611 <tbody>
612 <tr>
613 <td>
614 <p style="color: #595959;font-family: Rubik;
615 font-style: normal;
616 font-weight: bold;
617 font-size: 12px;
618 line-height: 12px;">Powered By <span><img width="64" height="24"
619 style="height:auto;width:auto;"
620 src="https://img.techpowerup.org/200503/group-135.png" /></span>
621 </p>
622 </td>
623 </tr>
624 </tbody>
625 </table>
626 </div>
627 </td>
628 </tr>
629 </tbody>
630 </table>
631 <div class="yj6qo"></div>
632 <div class="adL">
633 </div>
634 </div>
635 <div class="adL">
636 </div>
637 </div>
638 </body>
639
640 </html>`;
641
642 await mail({
643 user,
644 // message: `Hello ${user.fullname}. Welcome to Payment App. Enter this ${
645 // newVerificationCode.code
646 // }, to verify your account`,
647 message: template,
648 subject: `Welcome to myebucks App`
649 });
650 return {
651 user,
652 status: "successful",
653 message: "Please verify with the code sent to you"
654 };
655}
656
657export async function verifyUser(phonenumber: string, code?: number) {
658 // convert phone number to +234 format
659 if (phonenumber.startsWith("0")) {
660 let tel = phonenumber;
661 phonenumber = "+234" + tel.substr(1);
662 }
663
664 // check if an activation Code exists before for the user
665 const verificationCodes = await prisma.verificationCodes({
666 where: {
667 user: {
668 phonenumber
669 }
670 }
671 });
672
673 if (verificationCodes.length < 1) {
674 throw new Error("Error occured while trying to verify");
675 }
676
677 const verificationCode = verificationCodes[0];
678
679 if (verificationCode.code === code) {
680 const expTime = new Date(verificationCode.updatedAt);
681 let now = new Date();
682 // subtract date
683 let diffMs = now.getTime() - expTime.getTime();
684 let diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000); // minutes
685 if (diffMins <= 60) {
686 // update the user verified status to true
687 await prisma.updateUser({
688 where: {
689 phonenumber
690 },
691 data: {
692 verified: true
693 }
694 });
695 // create Wallet
696 await prisma.createWallet({
697 amount: 0,
698 user: {
699 connect: {
700 phonenumber
701 }
702 }
703 });
704
705 // delete verification code
706 await prisma.deleteVerificationCode({
707 id: verificationCode.id
708 });
709
710 const user = await prisma.user({
711 phonenumber
712 });
713
714 const template = `<html>
715
716 <head>
717 <title></title>
718 <link href='https://fonts.googleapis.com/css?family=Rubik' rel='stylesheet'>
719 <style>
720 @import url('https://fonts.googleapis.com/css?family=Rubik');
721 </style>
722 </head>
723
724 <body>
725 <div style="background-color:#f1f3f5;color:#233858;font-family:'Rubik';margin:0">
726 <div style="background-color:white;display:block;margin:0 auto;max-width:720px">
727 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
728 <tbody>
729 <tr>
730 <td
731 style="font-size:0!important;line-height:100%;padding-left:16px;padding-right:16px;padding-top:36px;text-align:center">
732
733 <div
734 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
735 <table width="100%" border="0" cellspacing="0" cellpadding="0"
736 style="min-width:100%;width:100%">
737 <tbody>
738 <tr>
739 <td
740 style="line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
741 <a href="#m_2661994423616798564_m_222366038327339295_"
742 style="color:#233858;font-family:'Rubik';text-decoration:underline">
743 <img src="https://img.techpowerup.org/200427/vector.png" width="64"
744 height="24" style="height:auto;max-width:200px;width:auto"
745 class="CToWUd">
746 <br />
747 <img src="https://img.techpowerup.org/200427/frame.png" width="64"
748 height="24"
749 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
750 class="CToWUd">
751 </a>
752 </td>
753 </tr>
754 </tbody>
755 </table>
756 <table align="center" width="100%" border="0" cellspacing="0" cellpadding="0"
757 style="display:table;margin-left:auto;margin-right:auto">
758 <tbody>
759 <tr>
760 <td
761 style="background-color:transparent!important;border-bottom:1px solid rgba(60,60,60,0.07);border-bottom-color:rgba(60,60,60,0.07);font-size:0;height:2px;line-height:1px;min-height:1px;overflow:hidden;padding-bottom:24px">
762 </td>
763 </tr>
764 </tbody>
765 </table>
766 </div>
767
768 </td>
769 </tr>
770 </tbody>
771 </table>
772
773 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
774 <tbody>
775 <tr>
776 <td
777 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
778
779 <div
780 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
781 <table width="100%" border="0" cellspacing="0" cellpadding="0"
782 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
783 <tbody>
784 <tr>
785 <td
786 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
787 <h1
788 style="color: #000000;font-family:'Rubik'!important;font-size:22px;font-weight:800;line-height:44px;margin-bottom:14px;margin-left:0;margin-right:0;margin-top:32px;padding:0">
789 Hi ${user.fullname}, </h1>
790 <p
791 style="color: #82859A;font-family:'Rubik';font-size:12px;line-height:1.6;margin-bottom:30px;margin-top:0">
792 Thank you for creating your account on myebucks. You can now pay
793 your bills and make airtime and data purchase seamleassly.</p>
794
795 <p
796 style="color: #82859A;font-family:'Rubik';font-size:13px;line-height:1.6;margin-top:0;padding-top:36px">
797 Sincerely,</p>
798 <p
799 style="color: #82859A;font-family:'Rubik';font-size:13px!important;margin-top:10px">
800 The Ebucks Team.</p>
801 </td>
802 </tr>
803 </tbody>
804 </table>
805 </div>
806
807 </td>
808 </tr>
809 </tbody>
810 </table>
811
812 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
813 <tbody>
814 <tr>
815 <td
816 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
817 <div
818 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
819 <table width="100%" border="0" cellspacing="0" cellpadding="0"
820 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
821 <tbody>
822 <tr>
823 <td
824 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
825 <p
826 style="border-top:1px solid rgba(60,60,60,0.07);color: #82859A;font-family:'Rubik';font-size:13px;letter-spacing: 0.02em;line-height:1.6;margin-bottom:20px;margin-top:100px;padding-top:20px">
827 Fund Wallet & Purchase with ease with our app today, availabe on
828 <a href="#">Android</a> and <a href="#">iOS</a> (Coming Soon) </p>
829 </td>
830 </tr>
831 </tbody>
832 </table>
833 </div>
834
835 </td>
836 </tr>
837 </tbody>
838 </table>
839
840
841
842 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
843 <tbody>
844 <tr>
845 <td
846 style="background-color:#0041C4;display:block;font-size:0!important;height:270px;line-height:100%;margin-top:20px;padding-left:8px;padding-right:8px;text-align:center">
847
848 <div
849 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
850 <table width="100%" border="0" cellspacing="0" cellpadding="0"
851 style="min-width:100%;width:100%">
852 <tbody>
853 <tr>
854 <td
855 style="min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%">
856 <div
857 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
858 <table width="100%" border="0" cellspacing="0" cellpadding="0"
859 style="min-width:100%;padding-top:32px;width:100%">
860 <tbody>
861 <tr>
862 <td
863 style="color:#233858;font-size:16px;line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
864 <a href="#"
865 style="color:#233858;font-family:'Rubik';text-decoration:underline">
866 <img src="https://img.techpowerup.org/200427/frame-1.png"
867 width="64" height="24"
868 style="height:24px;max-width:200px;width:auto;"
869 class="CToWUd"> <br />
870 <img src="https://img.techpowerup.org/200427/frame-2.png"
871 width="64" height="24"
872 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
873 class="CToWUd">
874 </a>
875 </td>
876 </tr>
877 </tbody>
878 </table>
879 </div>
880 <div
881 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
882 <table width="100%" border="0" cellspacing="0" cellpadding="0"
883 style="margin-left:auto;margin-right:0;min-width:100%;padding-top:32px;text-align:right;width:100%">
884 <tbody>
885 <tr>
886 <td style="color:#233858;display:inline;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%; display: flex;
887 flex-direction: column;align-items: center;">
888 <a href="#"
889 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
890 target="_blank" data-saferedirecturl="#"><img
891 src="https://ci6.googleusercontent.com/proxy/QibhghTDk6b0hIfNEbXhPkXgN1dvldl09KWTEGXqVOqUVuIUMbye4bx_nb1fo3kXVlLdOqShZs8peXzMvw=s0-d-e1-ft#https://emery.cloudns.cx/static/img/tw.png"
892 alt="myebucks Twitter"
893 style="height:16px;margin-left:20px;max-width:200px;width:auto"
894 class="CToWUd"></a>
895 <a href="#"
896 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
897 target="_blank" data-saferedirecturl="#"><img
898 src="https://ci5.googleusercontent.com/proxy/D1G7umjs3HsEa9BlJ6D8ZYRJYHUIrFdZrWaLNQiUfInBYUQmHzcjoEsaCqSoyzFUzEQ6F8n2lT0N_2Mf2A=s0-d-e1-ft#https://emery.cloudns.cx/static/img/ig.png"
899 alt="myebucks Instagram"
900 style="height:16px;margin-left:20px;max-width:200px;width:auto"
901 class="CToWUd"></a>
902 <a href="#"
903 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
904 target="_blank" data-saferedirecturl="#"><img
905 src="https://ci3.googleusercontent.com/proxy/aVFBIC7qxNzk6PsoiyvWZjHrD6VrlqJ_aUP_yC3eiSLDZmAf2ID-qBV9sJDs7UUlwcgdEfkOCYFg15JaYA=s0-d-e1-ft#https://emery.cloudns.cx/static/img/fb.png"
906 alt="myebucks Facebook"
907 style="height:16px;margin-left:20px;max-width:200px;width:auto"
908 class="CToWUd"></a>
909 </td>
910 </tr>
911 </tbody>
912 </table>
913 </div>
914
915 <div
916 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
917 <table width="100%" border="0" cellspacing="0" cellpadding="0"
918 style="min-width:100%;padding-top:32px;width:100%">
919 <tbody>
920 <tr>
921 <td
922 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
923 <a href=""
924 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
925 target="_blank">Links</a>
926 <a href=""
927 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
928 target="_blank">About Us</a>
929 <a href=""
930 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
931 target="_blank">Careers</a>
932 <a href=""
933 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
934 target="_blank">Contact</a>
935 </td>
936 </tr>
937 </tbody>
938 </table>
939 </div>
940 <div
941 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
942 <table width="100%" border="0" cellspacing="0" cellpadding="0"
943 style="min-width:100%;padding-top:32px;width:100%">
944 <tbody>
945 <tr>
946 <td
947 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
948 <p
949 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
950 Office</p>
951 <p
952 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
953 23 Adekunle Akala Street,</p>
954 <p
955 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
956 Ajao Estate, Oshodi/Isolo.</p>
957 <p
958 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
959 Lagos State</p>
960 </td>
961 </tr>
962 </tbody>
963 </table>
964 </div>
965
966
967
968 <table align="center" width="100%" border="0" cellspacing="0"
969 cellpadding="0"
970 style="display:table;margin-left:auto;margin-right:auto;padding-top:32px">
971 <tbody>
972 <tr>
973 <td
974 style="background-color:transparent!important;border-bottom:1px solid rgba(255,255,255,0.07);color:#233858;font-size:16px;height:2px;line-height:1px;min-height:1px;overflow:hidden">
975 </td>
976 </tr>
977 </tbody>
978 </table>
979 </td>
980 </tr>
981 </tbody>
982 </table>
983 </div>
984
985 </td>
986 </tr>
987 </tbody>
988 </table>
989
990 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width: 100%; width: 100%;">
991 <tbody>
992 <tr>
993 <td
994 style="display: block; font-size: 0 !important;height: 20px;margin-top: 20px;padding-left: 8px;padding-right: 8px;">
995 <div
996 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;">
997 <table width="100%" border="0" cellspacing="0" cellpadding="0"
998 style="min-width:100%;width:100%">
999 <tbody>
1000 <tr>
1001 <td>
1002 <p style="color: #595959;font-family: Rubik;
1003 font-style: normal;
1004 font-weight: bold;
1005 font-size: 12px;
1006 line-height: 12px;">Powered By <span><img width="64"
1007 height="24" style="height:auto;width:auto;"
1008 src="https://img.techpowerup.org/200503/group-135.png" /></span>
1009 </p>
1010 </td>
1011 </tr>
1012 </tbody>
1013 </table>
1014 </div>
1015 </td>
1016 </tr>
1017 </tbody>
1018 </table>
1019 <div class="yj6qo"></div>
1020 <div class="adL">
1021 </div>
1022 </div>
1023 <div class="adL">
1024 </div>
1025 </div>
1026 </body>
1027
1028 </html>`;
1029
1030 mail({
1031 user,
1032 // message: `Hello ${user.fullname}. Welcome to Payment App. Enter this ${
1033 // newVerificationCode.code
1034 // }, to verify your account`,
1035 message: template,
1036 subject: `Welcome to myebucks App`
1037 });
1038
1039
1040 return {
1041 user: user,
1042 status: "successful",
1043 token: sign(
1044 {
1045 id: user.id,
1046 email: user.email,
1047 user: "user"
1048 },
1049 process.env.JWT_SECRET
1050 )
1051 };
1052 }
1053 throw new Error("Verification code expired");
1054 }
1055 throw new Error("Incorrect verification code");
1056}
1057
1058interface LoginData {
1059 phonenumber: string;
1060 password: string;
1061}
1062
1063export async function login(loginData: LoginData) {
1064 let { phonenumber, password } = loginData;
1065 // convert phone number to +234 format
1066 if (phonenumber.startsWith("0")) {
1067 let tel = phonenumber;
1068 phonenumber = "+234" + tel.substr(1);
1069 }
1070 const user = await prisma.user({
1071 phonenumber
1072 });
1073 // if no user
1074 if (!user) {
1075 throw new Error("Invalid Details");
1076 }
1077 // Confirm Password
1078 const valid = await bcrypt.compare(password, user.password);
1079 if (!valid) {
1080 throw new Error("Invalid Details");
1081 }
1082
1083 const retrieve = await retrieveVirtualAccount(user.trackingReference);
1084 // let accountNo = retrieve,d
1085 // await prisma.createKudaDetail(retrieve.data)
1086
1087 // return json web token
1088 return {
1089 retrieve,
1090 user,
1091 token: sign(
1092 {
1093 id: user.id,
1094 email: user.email,
1095 phonenumber: user.phonenumber,
1096 user: "user"
1097 },
1098 process.env.JWT_SECRET
1099 )
1100 };
1101}
1102
1103export async function sendPasswordResetCode(
1104 phonenumber: string,
1105 code?: number
1106) {
1107 // convert phone number to +234 format
1108 if (phonenumber.startsWith("0")) {
1109 let tel = phonenumber;
1110 phonenumber = "+234" + tel.substr(1);
1111 }
1112 if (!code) {
1113 code = Math.floor(Math.random() * 900000) + 100000;
1114 }
1115
1116 if (String(code).length !== 6) {
1117 throw new Error("Code must be 6 digits");
1118 }
1119
1120 // fetch user
1121 const user = await prisma.user({
1122 phonenumber
1123 });
1124
1125 // password reset codes
1126 const passwordResetCodes = await prisma.passwordResetCodes({
1127 where: {
1128 user: {
1129 phonenumber
1130 }
1131 }
1132 });
1133
1134 // check if reset code exist before
1135 if (passwordResetCodes.length > 0) {
1136 // password reset code
1137 const passwordResetCode = passwordResetCodes[0];
1138
1139 await prisma.deletePasswordResetCode({
1140 id: passwordResetCode.id
1141 });
1142 }
1143
1144 await prisma.createPasswordResetCode({
1145 code,
1146 user: {
1147 connect: {
1148 phonenumber
1149 }
1150 }
1151 });
1152
1153 // Mask email address
1154 const maskEmail = user.email.replace(/^(.)(.*)(.@.*)$/,
1155 (_, a, b, c) => a + b.replace(/./g, '*') + c
1156 );
1157
1158 const d = new Date();
1159 const today = ((d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear());
1160 const time = d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
1161
1162 const template = `
1163 <html>
1164
1165<head>
1166 <title></title>
1167 <link href='https://fonts.googleapis.com/css?family=Rubik' rel='stylesheet'>
1168 <style>
1169 @import url('https://fonts.googleapis.com/css?family=Rubik');
1170 </style>
1171</head>
1172
1173<body>
1174 <div style="background-color:#f1f3f5;color:#233858;font-family:'Rubik';margin:0">
1175 <div style="background-color:white;display:block;margin:0 auto;max-width:720px">
1176 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
1177 <tbody>
1178 <tr>
1179 <td
1180 style="font-size:0!important;line-height:100%;padding-left:16px;padding-right:16px;padding-top:36px;text-align:center">
1181
1182 <div
1183 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
1184 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1185 style="min-width:100%;width:100%">
1186 <tbody>
1187 <tr>
1188 <td
1189 style="line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
1190 <a href="#m_2661994423616798564_m_222366038327339295_"
1191 style="color:#233858;font-family:'Rubik';text-decoration:underline">
1192 <img src="https://img.techpowerup.org/200427/vector.png" width="64"
1193 height="24" style="height:auto;max-width:200px;width:auto"
1194 class="CToWUd">
1195 <br />
1196 <img src="https://img.techpowerup.org/200427/frame.png" width="64"
1197 height="24"
1198 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
1199 class="CToWUd">
1200 </a>
1201 </td>
1202 </tr>
1203 </tbody>
1204 </table>
1205 <table align="center" width="100%" border="0" cellspacing="0" cellpadding="0"
1206 style="display:table;margin-left:auto;margin-right:auto">
1207 <tbody>
1208 <tr>
1209 <td
1210 style="background-color:transparent!important;border-bottom:1px solid rgba(60,60,60,0.07);border-bottom-color:rgba(60,60,60,0.07);font-size:0;height:2px;line-height:1px;min-height:1px;overflow:hidden;padding-bottom:24px">
1211 </td>
1212 </tr>
1213 </tbody>
1214 </table>
1215 </div>
1216
1217 </td>
1218 </tr>
1219 </tbody>
1220 </table>
1221
1222 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
1223 <tbody>
1224 <tr>
1225 <td
1226 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
1227
1228 <div
1229 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
1230 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1231 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
1232 <tbody>
1233 <tr>
1234 <td
1235 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
1236 <h1
1237 style="color: #000000;font-family:'Rubik'!important;font-size:22px;font-weight:800;line-height:44px;margin-bottom:14px;margin-left:0;margin-right:0;margin-top:32px;padding:0">
1238 No Hassle, its alright to forget</h1>
1239 <p
1240 style="color: #82859A;font-family:'Rubik';font-size:12px;line-height:1.6;margin-bottom:30px;margin-top:0;">
1241 Hi ${user.fullname}, you asked to reset your password for your
1242 myebucks acccount <span
1243 style="color: #044CC5;">${maskEmail}</span> on ${today} ${time}</p>
1244 <p
1245 style="color: #82859A;font-family:'Rubik';font-size:12px;line-height:1.6;margin-bottom:30px;margin-top:0;">
1246 Use this code <strong>${code}</strong></p>
1247
1248 <p
1249 style="color: #82859A;font-family:'Rubik';font-size:13px;line-height:1.6;margin-top:0;padding-top:36px">
1250 Sincerely,</p>
1251 <p
1252 style="color: #82859A;font-family:'Rubik';font-size:13px!important;margin-top:10px">
1253 The Ebucks Team.</p>
1254 </td>
1255 </tr>
1256 </tbody>
1257 </table>
1258 </div>
1259
1260 </td>
1261 </tr>
1262 </tbody>
1263 </table>
1264
1265 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
1266 <tbody>
1267 <tr>
1268 <td
1269 style="font-size:0!important;line-height:100%;padding-left:8px;padding-right:8px;text-align:center">
1270 <div
1271 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
1272 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1273 style="border:2px solid;border-color:transparent;border-radius:6px;min-width:100%;width:100%">
1274 <tbody>
1275 <tr>
1276 <td
1277 style="background-position:50% 0;background-repeat:no-repeat;border:0;border-radius:3px;min-width:100%;padding-left:8px;padding-right:8px;padding-top:32px;text-align:left;vertical-align:top;width:100%">
1278 <p
1279 style="border-top:1px solid rgba(60,60,60,0.07);color: #82859A;font-family:'Rubik';font-size:13px;letter-spacing: 0.02em;line-height:1.6;margin-bottom:20px;margin-top:100px;padding-top:20px">
1280 Fund Wallet & Purchase with ease with our app today, availabe on
1281 <a href="#">Android</a> and <a href="#">iOS</a> (Coming Soon) </p>
1282 </td>
1283 </tr>
1284 </tbody>
1285 </table>
1286 </div>
1287
1288 </td>
1289 </tr>
1290 </tbody>
1291 </table>
1292
1293
1294
1295 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width:100%;width:100%">
1296 <tbody>
1297 <tr>
1298 <td
1299 style="background-color:#0041C4;display:block;font-size:0!important;height:270px;line-height:100%;margin-top:20px;padding-left:8px;padding-right:8px;text-align:center">
1300
1301 <div
1302 style="display:inline-block;font-size:0;margin:0 auto;max-width:660px;min-width:0!important;text-align:center;vertical-align:top;width:100%">
1303 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1304 style="min-width:100%;width:100%">
1305 <tbody>
1306 <tr>
1307 <td
1308 style="min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%">
1309 <div
1310 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
1311 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1312 style="min-width:100%;padding-top:32px;width:100%">
1313 <tbody>
1314 <tr>
1315 <td
1316 style="color:#233858;font-size:16px;line-height:100%;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
1317 <a href="#"
1318 style="color:#233858;font-family:'Rubik';text-decoration:underline">
1319 <img src="https://img.techpowerup.org/200427/frame-1.png"
1320 width="64" height="24"
1321 style="height:24px;max-width:200px;width:auto;"
1322 class="CToWUd"> <br />
1323 <img src="https://img.techpowerup.org/200427/frame-2.png"
1324 width="64" height="24"
1325 style="height:auto;max-width:65px;width:auto;margin-top: 5px;"
1326 class="CToWUd">
1327 </a>
1328 </td>
1329 </tr>
1330 </tbody>
1331 </table>
1332 </div>
1333 <div
1334 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
1335 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1336 style="margin-left:auto;margin-right:0;min-width:100%;padding-top:32px;text-align:right;width:100%">
1337 <tbody>
1338 <tr>
1339 <td style="color:#233858;display:inline;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;vertical-align:top;width:100%; display: flex;
1340 flex-direction: column;align-items: center;">
1341 <a href="#"
1342 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
1343 target="_blank" data-saferedirecturl="#"><img
1344 src="https://ci6.googleusercontent.com/proxy/QibhghTDk6b0hIfNEbXhPkXgN1dvldl09KWTEGXqVOqUVuIUMbye4bx_nb1fo3kXVlLdOqShZs8peXzMvw=s0-d-e1-ft#https://emery.cloudns.cx/static/img/tw.png"
1345 alt="myebucks Twitter"
1346 style="height:16px;margin-left:20px;max-width:200px;width:auto"
1347 class="CToWUd"></a>
1348 <a href="#"
1349 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
1350 target="_blank" data-saferedirecturl="#"><img
1351 src="https://ci5.googleusercontent.com/proxy/D1G7umjs3HsEa9BlJ6D8ZYRJYHUIrFdZrWaLNQiUfInBYUQmHzcjoEsaCqSoyzFUzEQ6F8n2lT0N_2Mf2A=s0-d-e1-ft#https://emery.cloudns.cx/static/img/ig.png"
1352 alt="myebucks Instagram"
1353 style="height:16px;margin-left:20px;max-width:200px;width:auto"
1354 class="CToWUd"></a>
1355 <a href="#"
1356 style="color:#233858;font-family:'Rubik';text-decoration:underline; margin-top: 15px;"
1357 target="_blank" data-saferedirecturl="#"><img
1358 src="https://ci3.googleusercontent.com/proxy/aVFBIC7qxNzk6PsoiyvWZjHrD6VrlqJ_aUP_yC3eiSLDZmAf2ID-qBV9sJDs7UUlwcgdEfkOCYFg15JaYA=s0-d-e1-ft#https://emery.cloudns.cx/static/img/fb.png"
1359 alt="myebucks Facebook"
1360 style="height:16px;margin-left:20px;max-width:200px;width:auto"
1361 class="CToWUd"></a>
1362 </td>
1363 </tr>
1364 </tbody>
1365 </table>
1366 </div>
1367
1368 <div
1369 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;width:25%">
1370 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1371 style="min-width:100%;padding-top:32px;width:100%">
1372 <tbody>
1373 <tr>
1374 <td
1375 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
1376 <a href=""
1377 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
1378 target="_blank">Links</a>
1379 <a href=""
1380 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
1381 target="_blank">About Us</a>
1382 <a href=""
1383 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
1384 target="_blank">Careers</a>
1385 <a href=""
1386 style="color:white;display:block;font-family:'Rubik';font-size:13px;margin-bottom:15px;text-decoration:none!important"
1387 target="_blank">Contact</a>
1388 </td>
1389 </tr>
1390 </tbody>
1391 </table>
1392 </div>
1393 <div
1394 style="display:inline-block;float:right;font-size:0;min-width:0!important;vertical-align:top;width:25%">
1395 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1396 style="min-width:100%;padding-top:32px;width:100%">
1397 <tbody>
1398 <tr>
1399 <td
1400 style="color:#233858;font-size:16px;min-width:100%;padding-left:8px;padding-right:8px;text-align:left;vertical-align:top;width:100%">
1401 <p
1402 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
1403 Office</p>
1404 <p
1405 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
1406 23 Adekunle Akala Street,</p>
1407 <p
1408 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
1409 Ajao Estate, Oshodi/Isolo.</p>
1410 <p
1411 style="color:white;display:block;font-family:'Rubik';font-size:13px;line-height:1.6;margin-bottom:10px;margin-top:0;">
1412 Lagos State</p>
1413 </td>
1414 </tr>
1415 </tbody>
1416 </table>
1417 </div>
1418
1419
1420
1421 <table align="center" width="100%" border="0" cellspacing="0"
1422 cellpadding="0"
1423 style="display:table;margin-left:auto;margin-right:auto;padding-top:32px">
1424 <tbody>
1425 <tr>
1426 <td
1427 style="background-color:transparent!important;border-bottom:1px solid rgba(255,255,255,0.07);color:#233858;font-size:16px;height:2px;line-height:1px;min-height:1px;overflow:hidden">
1428 </td>
1429 </tr>
1430 </tbody>
1431 </table>
1432 </td>
1433 </tr>
1434 </tbody>
1435 </table>
1436 </div>
1437
1438 </td>
1439 </tr>
1440 </tbody>
1441 </table>
1442
1443 <table width="100%" border="0" cellspacing="0" cellpadding="0" style="min-width: 100%; width: 100%;">
1444 <tbody>
1445 <tr>
1446 <td
1447 style="display: block; font-size: 0 !important;height: 20px;margin-top: 20px;padding-left: 8px;padding-right: 8px;">
1448 <div
1449 style="display:inline-block;float:left;font-size:0;min-width:0!important;vertical-align:top;">
1450 <table width="100%" border="0" cellspacing="0" cellpadding="0"
1451 style="min-width:100%;width:100%">
1452 <tbody>
1453 <tr>
1454 <td>
1455 <p style="color: #595959;font-family: Rubik;
1456 font-style: normal;
1457 font-weight: bold;
1458 font-size: 12px;
1459 line-height: 12px;">Powered By <span><img width="64"
1460 height="24" style="height:auto;width:auto;"
1461 src="https://img.techpowerup.org/200503/group-135.png" /></span>
1462 </p>
1463 </td>
1464 </tr>
1465 </tbody>
1466 </table>
1467 </div>
1468 </td>
1469 </tr>
1470 </tbody>
1471 </table>
1472 <div class="yj6qo"></div>
1473 <div class="adL">
1474 </div>
1475 </div>
1476 <div class="adL">
1477 </div>
1478 </div>
1479</body>
1480
1481</html>`;
1482
1483 try {
1484 await mail({
1485 user,
1486 // message: `Hi ${
1487 // user.fullname
1488 // }. Use this code: ${code} to reset your password`,
1489 message: template,
1490 subject: "myebucks App Password Reset"
1491 });
1492
1493 return {
1494 user,
1495 status: "successful",
1496 message: "Please reset your password with the code sent to you"
1497 };
1498 } catch (error) { }
1499}
1500
1501export async function resetPassword(
1502 phonenumber: string,
1503 code: number,
1504 password: string
1505) {
1506 // convert phone number to +234 format
1507 if (phonenumber.startsWith("0")) {
1508 let tel = phonenumber;
1509 phonenumber = "+234" + tel.substr(1);
1510 }
1511
1512 const passwordResetCodes = await prisma.passwordResetCodes({
1513 where: {
1514 user: {
1515 phonenumber
1516 }
1517 }
1518 });
1519
1520 if (passwordResetCodes.length === 0) {
1521 throw new Error("Request for a password reset");
1522 }
1523
1524 const passwordResetCode = passwordResetCodes[0];
1525
1526 // if code align change the password
1527 if (passwordResetCode.code === code) {
1528 const expTime = new Date(passwordResetCode.updatedAt);
1529 let now = new Date();
1530 // subtract date
1531 let diffMs = now.getTime() - expTime.getTime();
1532 let diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000); // minutes
1533
1534 if (diffMins <= 60) {
1535 const user = await prisma.updateUser({
1536 where: {
1537 phonenumber
1538 },
1539 data: {
1540 password: await bcrypt.hashSync(password, salt)
1541 }
1542 });
1543
1544 return {
1545 user,
1546 token: sign(
1547 {
1548 id: user.id,
1549 email: user.email,
1550 user: "user"
1551 },
1552 process.env.JWT_SECRET
1553 )
1554 };
1555 }
1556 throw new Error("Password reset code expired");
1557 }
1558 throw new Error("Wrong password reset code");
1559}
1560
1561export async function user(token?: string, phonenumber?: string) {
1562 if (token) {
1563 const { id, user } = verifyToken(token) as any;
1564 if (user === "user") {
1565 return prisma.user({
1566 id
1567 });
1568 }
1569 throw new Error("Not Authorized");
1570 } else if (phonenumber) {
1571 if (phonenumber.length < 11) {
1572 throw new Error("Your phone number is incomplete");
1573 }
1574 // convert phone number to +234 format
1575 if (phonenumber.startsWith("0")) {
1576 let tel = phonenumber;
1577 phonenumber = "+234" + tel.substr(1);
1578 }
1579 return prisma.user({
1580 phonenumber
1581 });
1582 }
1583 throw new Error("Not Authorized");
1584}
1585
1586export async function updatePassword(
1587 token: string,
1588 oldPassword: string,
1589 newPassword: string
1590) {
1591 const { id, email, user } = verifyToken(token) as any;
1592
1593 // checks if the type of user is a user
1594 if (user === "user") {
1595 const person = await prisma.user({
1596 email
1597 });
1598 // Confirm Old Password
1599 const valid = await bcrypt.compare(oldPassword, person.password);
1600 if (!valid) {
1601 throw new Error("Old Password Incorrect");
1602 }
1603
1604 // confirm user is not using the same password
1605 const newValid = await bcrypt.compare(newPassword, person.password);
1606 if (newValid) {
1607 throw new Error("Choose a new password");
1608 }
1609
1610 await prisma.updateUser({
1611 where: {
1612 email
1613 },
1614 data: {
1615 password: await bcrypt.hashSync(newPassword, salt)
1616 }
1617 });
1618
1619 return {
1620 user: person,
1621 token: sign(
1622 {
1623 id: user.id,
1624 email: user.email,
1625 user: "user"
1626 },
1627 process.env.JWT_SECRET
1628 )
1629 };
1630 }
1631 throw new Error("Not Authorized");
1632}
1633
1634export async function updateProfile(
1635 token: string,
1636 fullname: string,
1637 gender: Gender
1638) {
1639 const { id, email, user } = verifyToken(token) as any;
1640 console.log(fullname);
1641
1642 // checks if the type of user is a user
1643 if (user === "user") {
1644 const person = await prisma.user({
1645 email
1646 });
1647
1648 const newUser = await prisma.updateUser({
1649 where: {
1650 email
1651 },
1652 data: {
1653 fullname,
1654 gender
1655 }
1656 });
1657
1658 return {
1659 user: newUser,
1660 status: "successful",
1661 message: "Your profile has been updated"
1662 };
1663 }
1664 throw new Error("Not Authorized");
1665}