-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.js
978 lines (960 loc) · 29.2 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
const express = require('express')
const jwt = require('jsonwebtoken')
const { Configuration, OpenAIApi } = require('openai')
const server = express()
const cron = require('node-cron')
const { OPENAI_API_KEY, mongoDBinfo } = require('./passwords.js')
const cors = require('cors')
server.use(cors())
let mongoDBConnection = false
const { MongoClient, ServerApiVersion } = require('mongodb')
const uri = mongoDBinfo // Connection URI
// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const client = new MongoClient(uri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
},
})
//mongodb run function to handle the connection
//establish the database connection when your application
//starts or when your server initializes, and keep the
//connection open as long as your application is running.
async function run() {
try {
// Connect the client to the server (optional starting in v4.7)
await client.connect()
console.log('Connected to MongoDB')
mongoDBConnection = true
// Send a ping to confirm a successful connection
//await client.db('admin').command({ ping: 1 })
// console.log(
// 'Pinged your deployment. You successfully connected to MongoDB!'
// )
} catch (err) {
console.log('Failed to connect to MongoDB' + err)
mongoDBConnection = false
}
}
//call the function from a global scope
run().catch(console.dir)
async function close() {
try {
await client.close()
console.log('Connection closed')
} catch (err) {
console.log('Failed to close MongoDB connection' + err)
}
}
//--------------------------------------------------
//database functions
//--------------------------------------------------
const db = client.db('fambankapi')
//each account/user is a document which is an object stored in the designated collection
const usersCollection = db.collection('users')
const accountsCollection = db.collection('accounts')
async function insertUser(user) {
const result = await usersCollection.insertOne(user)
return result.acknowledged
}
async function insertAccount(account) {
const result = await accountsCollection.insertOne(account)
return result.acknowledged
}
//returns a promise, null if not found
async function findUserByID(id) {
const result = await usersCollection.findOne({ id })
return result
}
//returns a promise
async function findAccountByID(id) {
const result = await accountsCollection.findOne({ id })
return result
}
async function isUserDuplicate(id) {
const existingUser = await usersCollection.findOne({ id })
return !!existingUser // Returns true if the user exists, false if not
}
async function isAccountDuplicate(id) {
const existingAccount = await accountsCollection.findOne({ id })
return !!existingAccount // Returns true if the account exists, false if not
}
async function isUniqueEmailMobile(email, mobileNumber) {
const existingUser = await usersCollection.findOne({ email })
const existingUserTwo = await usersCollection.findOne({ mobileNumber })
return !existingUser && !existingUserTwo // Returns true if user does not exist //!null && !null = true
}
async function findUserByEmailPassword(email, password) {
const result = await usersCollection.findOne({ email, password })
return result
}
async function updateUserByID(id, updatedData) {
const result = await usersCollection.updateOne(
{ id: id }, // Filter to match the user by ID
{ $set: updatedData } // Update the user with the new data
)
return result.modifiedCount // Number of documents modified
}
async function insertAccountToUser(id, item) {
const result = await usersCollection.updateOne(
{ id: id }, // Filter to match the user by ID
{ $push: { accounts: item } } // Push the item to the "accounts" array field
)
return result.modifiedCount // Number of documents modified
}
async function insertUserToAccount(id, newUserId, mainUser) {
let result = 0
if (mainUser == true) {
result = await accountsCollection.updateOne(
{ id: id }, // Filter to match the account by ID
{ $push: { mainUsersIDs: newUserId } }
) // Push the item to the "users" array field
} else {
result = await accountsCollection.updateOne(
{ id: id }, // Filter to match the account by ID
{ $push: { subUsersIDs: newUserId } }
) // Push the item to the "users" array field
}
return result.modifiedCount // Number of documents modified
}
async function insertTransaction(id, transaction) {
const result = await accountsCollection.updateOne(
{ id: id }, // Filter to match the account by ID
{ $push: { transactions: transaction } }
)
return result.modifiedCount // Number of documents modified
}
async function updateBalance(id, userId, amount) {
const result = await accountsCollection.updateOne(
{ id: id },
{ $inc: { balance: -1 * amount } }
)
const resultTwo = await usersCollection.updateOne(
{ id: userId, 'accounts.accId': id },
{ $inc: { 'accounts.$.balance': -1 * amount } }
)
return result.modifiedCount + resultTwo.modifiedCount // Number of documents modified
}
async function findUserByEmail(email) {
const result = await usersCollection.findOne({ email })
return result
}
//--------------------------------------------------
//TESTING DB
//--------------------------------------------------
// findUserByID('123')
// .then((user) =>
// console.log(user)
// })
// .catch((error) => {
// console.error('error' + error)
// })
//better approach: async/await
// try {
// const user = await findUserByID('123')
// console.log(user)
// } catch (error) {
// console.error('Error:', error)
// }
//middlewares
server.use(express.json())
//--
//Middleware for mongodb
//--
// Middleware to verify token
const verifyToken = (req, res, next) => {
const authHeader = req.headers['authorization']
if (!authHeader) {
res
.status(401)
.json({ status: false, message: 'Access denied. Token missing.' })
return
}
const [scheme, token] = authHeader.split(' ')
if (scheme !== 'Bearer' || !token) {
res
.status(401)
.json({ status: false, message: 'Access denied. Invalid token.' })
return
}
try {
const decoded = jwt.verify(token, 'yourSecretKey')
req.userId = decoded.id
next()
} catch (error) {
res
.status(401)
.json({ status: false, message: 'Access denied. Invalid token.' })
}
}
//Middleware for openai
const callprompt = async (req, res, next) => {
const configuration = new Configuration({
apiKey: OPENAI_API_KEY,
})
let account = ''
let user = ''
try {
//get user and account
account = await findAccountByID(req.params.id)
user = await findUserByID(req.userId)
if (!account || !user) {
res.status(404).send('Account or User not found')
return
}
} catch (error) {
res.status(404).send('Account or User not found' + error)
return
}
//openai
try {
const openai = new OpenAIApi(configuration)
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt: `suppose you are acting as a virtual assistant for a bank (fambank). user's name is ${user.name}, phone number is ${user.mobileNumber} and email is ${user.email}. the user says ${req.query.text}`,
temperature: 0,
max_tokens: 1000,
})
if (response.data.choices && response.data.choices.length > 0) {
res
.status(200)
.json({ status: true, message: response.data.choices[0].text })
} else {
res.status(404).json({ status: false, message: 'Chat Bot Unavailable' })
}
} catch (error) {
console.error('Error:', error)
res.status(404).json({ status: false, message: 'Chat Bot Unavailable' })
}
}
//--------------------------------------------------
//--------------------------------------------------
//function to generate id
generateUniqueId = () => {
// Generate a random 6-digit ID
return Math.floor(Math.random() * 1000000).toString()
}
generateUniqueCreditCardNumber = () => {
// Generate a random 6-digit ID
return Math.floor(Math.random() * 10000000000000000)
}
//------------------------------
server.get('/', (req, res) => {
res.end('homepage')
})
//signup
// {
// "name" : "ahmed",
// "password" : "password123",
// "dateOfBirth" : "17/01/2023",
// "mobileNumber" : "0508242474",
// "email": "[email protected]",
// }
server.post('/api/signup', async (req, res) => {
const { name, password, dateOfBirth, mobileNumber, email } = req.body
let id = generateUniqueId()
//check if id is duplicate
const isDuplicate = await isUserDuplicate(id)
while (isDuplicate) {
id = generateUniqueId()
}
//check if anything is duplicate
//check if id is duplicate
const isUniqueEmailMobileRet = await isUniqueEmailMobile(email, mobileNumber) //true if unique
if (!isUniqueEmailMobileRet) {
res.status(400).json({
status: false,
message: 'Email or Mobile Number already exists',
})
return
}
//DO THIS IN FRONTEND
//---------------------------------
//check if any field is empty
if (!name || !dateOfBirth || !mobileNumber || !email || !password) {
res
.status(400)
.json({ status: false, message: 'Please fill all the details' })
return
}
//check if password is less than 8 characters
if (password.length < 8) {
res.status(400).json({
status: false,
message: 'Password should be atleast 8 characters',
})
return
}
//check if email is valid
if (!email.includes('@')) {
res
.status(400)
.json({ status: false, message: 'Please enter a valid email' })
return
}
//---------------------------------
const newUser = {
id,
name,
password,
dateOfBirth,
mobileNumber,
email,
accounts: [],
}
const newUserInserted = await insertUser(newUser)
if (!newUserInserted) {
res.status(400).json({
status: false,
message: 'Error occurred while creating user',
})
return
}
//generate token
const token = jwt.sign({ id: newUser.id }, 'yourSecretKey')
res
.status(200)
.json({ status: true, message: 'User created successfully', id, token })
})
//login
// {
// "email": "[email protected]",
// "password" : "password123"
// }
//--------------------------
server.post('/api/login', async (req, res) => {
const { email, password } = req.body
if (!email || !password) {
res
.status(404)
.json({ status: false, message: 'Please fill all the details' })
return
}
const user = await findUserByEmailPassword(email, password)
if (!user) {
res.status(400).json({ status: false, message: 'Invalid credentials' })
return
}
const token = jwt.sign({ id: user.id }, 'yourSecretKey')
res.status(200).json({
status: true,
message: 'Login successful',
id: user.id,
token,
name: user.name,
})
})
//create account
server.post('/api/createAccount', verifyToken, async (req, res) => {
const userId = req.userId
const balance = Number(req.body.balance)
const accId = generateUniqueId()
//check if id is duplicate
const isDuplicate = await isAccountDuplicate(accId)
while (isDuplicate) {
accId = generateUniqueId()
}
const currentDate = new Date()
// Calculate the date seven years from today
const futureDate = new Date()
futureDate.setFullYear(currentDate.getFullYear() + 7)
// Format the date as dd/mm/yyyy
const formattedDate = `${futureDate.getDate()}/${
futureDate.getMonth() + 1
}/${futureDate.getFullYear()}`
const account = {
id: accId,
mainUsersIDs: [userId],
subUsersIDs: [],
balance,
transactions: [],
creditCard: {
number: generateUniqueCreditCardNumber(),
expiryDate: formattedDate, //seven years from today
cvv: Math.floor(Math.random() * 1000),
},
}
//add account to account collection
const accountInserted = await insertAccount(account)
if (!accountInserted) {
res.status(400).json({
status: false,
message: 'Error occurred while creating account',
})
return
}
//add account to user collection
//note that this approach does not provide strong exception guarantee
const addAccCount = await insertAccountToUser(userId, {
accId: accId,
status: 'main',
balance: balance,
})
if (addAccCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while creating account',
})
return
}
res.status(200).json({
status: true,
message: 'Account created successfully',
id: accId,
// userId,
})
})
//get all accounts (minimal details) (select account frontend view)
server.get('/api/getAllAccounts', verifyToken, async (req, res) => {
const userId = req.userId
const user = await findUserByID(userId)
if (!user) {
//would never happen since token is verified
res.status(404).json({ status: false, message: 'User not found' })
return
}
const userAccounts = user.accounts
res.status(200).json({
status: true,
message: 'Accounts fetched successfully',
accounts: userAccounts,
userName: user.name,
})
})
//get 'one' account full details
server.get('/api/getAccountDetails/:id', verifyToken, async (req, res) => {
const userId = req.userId
const accId = req.params.id
const account = await findAccountByID(accId)
if (!account) {
res.status(404).json({ status: false, message: 'Account not found' })
return
}
if (
!account.mainUsersIDs.includes(userId) &&
!account.subUsersIDs.includes(userId)
) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
const user = await findUserByID(userId)
//not necessary
if (!user) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!userAccount) {
//access denied
res.status(401).json({ status: false, message: 'Access denied' })
return
}
res.status(200).json({
status: true,
message: 'Account details fetched successfully',
account,
userStatus: userAccount.status,
userBalance: userAccount.balance,
userName: user.name,
})
})
// add user to account
server.post('/api/addUser/:id', verifyToken, async (req, res) => {
const accId = req.params.id
const userId = req.userId
const email = req.body.email
const newStatus = req.body.newStatus
const newBalance = Number(req.body.newBalance)
// const newUser =
const account = await findAccountByID(accId)
if (!account || !account.mainUsersIDs.includes(userId)) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
const newUser = await findUserByEmail(email)
if (!newUser) {
res.status(404).json({ status: false, message: 'User not found' })
return
}
const addedID = newUser.id
//check if newUser is same as main user
if (addedID === userId) {
res.status(400).json({
status: false,
message: 'You are already the main user of this account',
})
return
}
//check if newUser is already a user of this account
if (
account.mainUsersIDs.includes(addedID) ||
account.subUsersIDs.includes(addedID)
) {
res.status(400).json({
status: false,
message: 'User is already a user of this account',
})
return
}
if (newBalance > account.balance) {
res.status(404).json({ status: false, message: 'Insufficient balance' })
return
}
//add to user with addedID
if (newStatus === 'main') {
//add User to Account
const addUserCount = await insertUserToAccount(accId, addedID, true)
if (addUserCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while adding user to account',
})
return
}
} else if (newStatus === 'sub') {
const addUserCountSub = await insertUserToAccount(accId, addedID, false)
if (addUserCountSub === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while adding user to account',
})
return
}
} else {
res.status(400).json({ status: false, message: 'Invalid Status' })
return
}
const addAccCount = await insertAccountToUser(addedID, {
accId: accId,
status: newStatus,
balance: newBalance,
})
res.status(200).json({
status: true,
message: 'User added successfully',
})
})
server.post('/api/billPayment/:type/:id', verifyToken, async (req, res) => {
const userId = req.userId
const type = req.params.type
const accId = req.params.id
const amount = Number(req.body.amount)
const monthlyRepeat = req.body.monthlyRepeat
//not necessary given that we are using jwt
// if (!account) {
// res.status(404).json({ status: false, message: 'Account not found' })
// return
// }
// if (!user) {
// res.status(404).json({ status: false, message: 'User not found' })
// return
// }
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
if (!account || !account.mainUsersIDs.includes(userId)) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
if (!user) {
res.status(401).json({ status: false, message: 'User not found' })
return
}
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!userAccount) {
res.status(401).json({ status: false, message: 'User not found' })
return
}
if (amount > account.balance || amount < 0 || userAccount.balance < amount) {
res.status(404).json({ status: false, message: 'Insufficient balance' })
return
}
//add transaction
const transaction = {
type: type,
desc: new Date().toLocaleDateString('en-GB'),
amount: amount,
userId: userId,
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while adding transaction',
})
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while updating balance',
})
return
}
if (monthlyRepeat == 'false') {
res.status(200).json({
status: true,
message: 'Bill paid successfully (one time)',
})
return
}
//execute function every month
const today = new Date()
const endDate = new Date(today.setDate(today.getDate() + 30))
const endDateDay = endDate.getDate()
const endDateMonth = endDate.getMonth() + 1
const endDateYear = endDate.getFullYear()
const cronExpression = `0 0 1 ${endDateDay} ${endDateMonth} *`
cron.schedule(cronExpression, async () => {
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!account || !user || !userAccount) {
cron.stop()
return
}
if (amount > account.balance || userAccount.balance < amount) {
cron.stop()
return
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
cron.stop()
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
cron.stop()
return
}
})
res.status(200).json({
status: true,
message: 'Bill paid successfully',
})
})
server.post('/api/addDebit/:id', verifyToken, async (req, res) => {
const userId = req.userId
const accId = req.params.id
const amount = Number(req.body.amount)
const title = req.body.title
const endDateDay = req.body.day
const endDateMonth = req.body.month - 1 //months are 0-11
const endDateYear = req.body.year
const endDate = new Date(
Number(endDateYear),
Number(endDateMonth),
Number(endDateDay)
)
console.log(endDateDay, endDateMonth, endDateYear)
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
const userAccount = user.accounts.find((acc) => acc.accId === accId)
//not necessary given that we are using jwt
if (!account || !user) {
res
.status(404)
.json({ status: false, message: 'Account or User not found' })
return
}
if (!account.mainUsersIDs.includes(userId)) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
if (amount > account.balance || amount < 0 || userAccount.balance < amount) {
res.status(404).json({ status: false, message: 'Invalid amount' })
return
}
const transaction = {
type: title,
desc: new Date().toLocaleDateString('en-GB'),
amount: amount,
userId: userId,
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while adding transaction',
})
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while updating balance',
})
return
}
//if enddate is less than 30 days from today
let currentDate = new Date()
let futureDate = new Date()
futureDate.setDate(currentDate.getDate() + 30)
if (endDate.getTime() < futureDate.getTime()) {
res.status(200).json({
status: true,
message: 'Debit added successfully (one time)',
})
return
}
//else.. execute function every month until the end date
const today = new Date()
const endDateX = new Date(today.setDate(today.getDate() + 30))
const endDateDayX = endDateX.getDate()
const endDateMonthX = endDateX.getMonth() + 1
const endDateYearX = endDateX.getFullYear()
const cronExpression = `0 0 1 ${endDateDayX} ${endDateMonthX} *`
cron.schedule(cronExpression, async () => {
//stop if end date is reached or has been passed or less than 30 days from today
let currentDate = new Date()
let futureDate = new Date()
futureDate.setDate(currentDate.getDate() + 30)
if (
endDate.getTime() < currentDate.getTime() ||
endDate == currentDate ||
endDate.getTime() < futureDate.getTime()
) {
cron.stop()
return
}
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
const userAccount = user.accounts.find((acc) => acc.accId === accId)
//not necessary given that we are using jwt
if (!account || !user) {
cron.stop()
return
}
if (!account.mainUsersIDs.includes(userId)) {
cron.stop()
return
}
if (
amount > account.balance ||
amount < 0 ||
userAccount.balance < amount
) {
cron.stop()
return
}
const transaction = {
type: title,
desc: new Date().toLocaleDateString('en-GB'),
amount: amount,
userId: userId,
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
cron.stop()
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
cron.stop()
return
}
})
res.status(200).json({
status: true,
message: 'Debit added successfully',
})
})
server.post('/api/allowance/:id', verifyToken, async (req, res) => {
const userId = req.userId
const accId = req.params.id
const amount = Number(req.body.amount)
const transferToEmail = req.body.transferToEmail
const instantTransfer = req.body.instantTransfer
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
//not necessary given that we are using jwt
if (!account || !user) {
res
.status(404)
.json({ status: false, message: 'Account or User not found' })
return
}
if (!account.mainUsersIDs.includes(userId)) {
res.status(401).json({ status: false, message: 'Access denied' })
return
}
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!userAccount) {
res.status(404).json({ status: false, message: 'Account not found' })
return
}
if (amount > account.balance || amount < 0 || userAccount.balance < amount) {
res.status(404).json({ status: false, message: 'Invalid amount' })
return
}
const transferToUser = await findUserByEmail(transferToEmail)
if (!transferToUser) {
res
.status(404)
.json({ status: false, message: 'Transfer to user ID invalid' })
return
}
//check if you are transferring to yourself
if (transferToUser.id === userId) {
res.status(400).json({
status: false,
message: 'You cannot transfer to yourself',
})
return
}
//check if transferToUser is a main user or sub user
if (
!account.mainUsersIDs.includes(transferToUser.id) &&
!account.subUsersIDs.includes(transferToUser.id)
) {
res.status(404).json({ status: false, message: 'User not found' })
return
}
const transaction = {
type: 'transfer from ' + user.name,
desc: new Date().toLocaleDateString('en-GB'),
amount: amount,
userId: userId,
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while adding transaction',
})
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while updating balance',
})
return
}
//update balance from recepient user (no function used here)
const result = await usersCollection.updateOne(
{ id: transferToUser.id, 'accounts.accId': accId },
{ $inc: { 'accounts.$.balance': amount } }
)
if (result.modifiedCount === 0) {
res.status(400).json({
status: false,
message: 'Error occurred while updating balance',
})
return
}
if (instantTransfer == 'true') {
res.status(200).json({
status: true,
message: 'Allowance added successfully (instant transfer)',
})
return
}
//else.. execute function every month
const today = new Date()
const endDate = new Date(today.setDate(today.getDate() + 30))
const endDateDay = endDate.getDate()
const endDateMonth = endDate.getMonth() + 1
const endDateYear = endDate.getFullYear()
const cronExpression = `0 0 1 ${endDateDay} ${endDateMonth} *`
cron.schedule(cronExpression, async () => {
//stop if balance is insufficient
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!account || !user || !userAccount) {
cron.stop()
return
}
if (amount > account.balance || userAccount.balance < amount) {
cron.stop()
return
}
const transaction = {
type: 'transfer from ' + user.name,
desc: new Date().toLocaleDateString('en-GB'),
amount: amount,
userId: userId,
}
const insertTransactionCount = await insertTransaction(accId, transaction)
if (insertTransactionCount === 0) {
cron.stop()
return
}
//update balance from account and user
const updateBalanceCount = await updateBalance(accId, userId, amount)
if (updateBalanceCount === 0) {
cron.stop()
return
}
//update balance from recepient user (no function used here)
const result = await usersCollection.updateOne(
{ id: transferToUser.id, 'accounts.accId': accId },
{ $inc: { 'accounts.$.balance': amount } }
)
if (result.modifiedCount === 0) {
cron.stop()
return
}
})
res.status(200).json({
status: true,
message: 'Allowance added successfully',
})
})
//extra -----------------------
server.get(
'/api/getNameFromID/:accId/:userId',
verifyToken,
async (req, res) => {
const accId = req.params.accId
const userId = req.params.userId
const account = await findAccountByID(accId)
const user = await findUserByID(userId)
if (!account || !user) {
res
.status(404)
.json({ status: false, message: 'Account or User not found' })
return
}
const userAccount = user.accounts.find((acc) => acc.accId === accId)
if (!userAccount) {
res.status(401).json({ status: false, message: 'Access Denied' })
return
}
res.status(200).json({ status: true, name: user.name })
}
)
//chat bot when logged in..
//example : http://localhost:3000/api/chatbot/1224323?text=sayhi
server.get('/api/chatbot/:id', verifyToken, callprompt, (req, res) => {})
//--------------------404 ROUTES--------------------
server.get('*', (req, res) => {
res.status(404).json({ status: false, message: 'Invalid route' })
})
server.post('*', (req, res) => {
res.status(404).json({ status: false, message: 'Invalid route' })
})
server.put('*', (req, res) => {
res.status(404).json({ status: false, message: 'Invalid route' })
})
server.delete('*', (req, res) => {
res.status(404).json({ status: false, message: 'Invalid route' })
})
//--------------------END OF ROUTES--------------------
//development server
const port = 3000
server.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`)
})
// to do :
//integration with frontend
//2fa