@edgedev/firebase 2.2.81 → 2.2.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "2.2.81",
3
+ "version": "2.2.82",
4
4
  "description": "Vue 3 / Nuxt 3 Plugin or Nuxt 3 plugin for firebase authentication and firestore.",
5
5
  "main": "index.ts",
6
6
  "scripts": {
package/src/cms.js CHANGED
@@ -1839,12 +1839,18 @@ const buildBlockAiPrompt = ({
1839
1839
  ].join('\n')
1840
1840
  }
1841
1841
 
1842
+ const assertCallableUser = (request) => {
1843
+ if (!request?.auth?.uid)
1844
+ throw new HttpsError('unauthenticated', 'Authentication required.')
1845
+ if (request?.data?.uid !== request.auth.uid)
1846
+ throw new HttpsError('permission-denied', 'UID mismatch.')
1847
+ }
1848
+
1842
1849
  exports.updateSeoFromAi = onCall({ timeoutSeconds: 180 }, async (request) => {
1850
+ assertCallableUser(request)
1843
1851
  const data = request.data || {}
1844
1852
  const auth = request.auth
1845
- const { orgId, siteId, pageId, uid } = data
1846
- if (!auth?.uid || auth.uid !== uid)
1847
- throw new HttpsError('permission-denied', 'Unauthorized')
1853
+ const { orgId, siteId, pageId } = data
1848
1854
  if (!orgId || !siteId || !pageId)
1849
1855
  throw new HttpsError('invalid-argument', 'Missing orgId, siteId, or pageId')
1850
1856
  const allowed = await permissionCheck(auth.uid, 'write', `organizations/${orgId}/sites/${siteId}/pages`)
@@ -1910,9 +1916,7 @@ exports.updateSeoFromAi = onCall({ timeoutSeconds: 180 }, async (request) => {
1910
1916
  })
1911
1917
 
1912
1918
  exports.getCloudflarePagesProject = onCall(async (request) => {
1913
- if (!request?.auth) {
1914
- throw new HttpsError('unauthenticated', 'Authentication required.')
1915
- }
1919
+ assertCallableUser(request)
1916
1920
 
1917
1921
  if (!CLOUDFLARE_PAGES_PROJECT) {
1918
1922
  logger.warn('CLOUDFLARE_PAGES_PROJECT is not set.')
@@ -1923,12 +1927,10 @@ exports.getCloudflarePagesProject = onCall(async (request) => {
1923
1927
  })
1924
1928
 
1925
1929
  exports.generateBlockFields = onCall({ timeoutSeconds: 180 }, async (request) => {
1930
+ assertCallableUser(request)
1926
1931
  const data = request.data || {}
1927
1932
  const auth = request.auth
1928
- const { orgId, uid, blockId, blockName, content, fields, currentValues, meta, instructions } = data
1929
-
1930
- if (!auth?.uid || auth.uid !== uid)
1931
- throw new HttpsError('permission-denied', 'Unauthorized')
1933
+ const { orgId, blockId, blockName, content, fields, currentValues, meta, instructions } = data
1932
1934
  if (!orgId || !blockId)
1933
1935
  throw new HttpsError('invalid-argument', 'Missing orgId or blockId')
1934
1936
  if (!Array.isArray(fields) || fields.length === 0)
@@ -14,6 +14,13 @@ function formatPhoneNumber(phone) {
14
14
  return `+1${numericPhone}`
15
15
  }
16
16
 
17
+ const assertCallableUser = (request) => {
18
+ if (!request?.auth?.uid)
19
+ throw new HttpsError('unauthenticated', 'Authentication required.')
20
+ if (request?.data?.uid !== request.auth.uid)
21
+ throw new HttpsError('permission-denied', 'UID mismatch.')
22
+ }
23
+
17
24
  exports.uploadDocumentDeleted = onDocumentDeleted(
18
25
  { document: 'organizations/{orgId}/files/{docId}', timeoutSeconds: 180 },
19
26
  async (event) => {
@@ -34,21 +41,19 @@ exports.uploadDocumentDeleted = onDocumentDeleted(
34
41
  )
35
42
 
36
43
  exports.addUpdateFileDoc = onCall(async (request) => {
44
+ assertCallableUser(request)
37
45
  const data = request.data
38
- const auth = request.auth
39
46
  let docId = data?.docId
40
- if (data.uid === auth.uid) {
41
- console.log(data)
42
- const orgId = data.orgId
43
- if (docId) {
44
- const docRef = db.collection(`organizations/${orgId}/files`).doc(docId)
45
- await docRef.set(data, { merge: true })
46
- }
47
- else {
48
- const docRef = db.collection(`organizations/${orgId}/files`).doc()
49
- await docRef.set(data)
50
- docId = docRef.id
51
- }
47
+ console.log(data)
48
+ const orgId = data.orgId
49
+ if (docId) {
50
+ const docRef = db.collection(`organizations/${orgId}/files`).doc(docId)
51
+ await docRef.set(data, { merge: true })
52
+ }
53
+ else {
54
+ const docRef = db.collection(`organizations/${orgId}/files`).doc()
55
+ await docRef.set(data)
56
+ docId = docRef.id
52
57
  }
53
58
  console.log(docId)
54
59
  return { docId }
@@ -426,91 +431,87 @@ exports.initFirestore = onCall(async (request) => {
426
431
  })
427
432
 
428
433
  exports.removeNonRegisteredUser = onCall(async (request) => {
434
+ assertCallableUser(request)
429
435
  const data = request.data
430
- const auth = request.auth
431
- if (data.uid === auth.uid) {
432
- const stagedUser = await db.collection('staged-users').doc(data.docId).get()
433
- if (stagedUser.exists) {
434
- const stagedUserData = stagedUser.data()
435
-
436
- const rolesExist = stagedUserData.roles && Object.keys(stagedUserData.roles).length !== 0
437
- const specialPermissionsExist = stagedUserData.specialPermissions && Object.keys(stagedUserData.specialPermissions).length !== 0
438
- const userIdExistsAndNotBlank = stagedUserData.userId && stagedUserData.userId !== ''
439
-
440
- if (!rolesExist && !specialPermissionsExist && !userIdExistsAndNotBlank) {
441
- await db.collection('staged-users').doc(data.docId).delete()
442
- return { success: true, message: '' }
436
+ const stagedUser = await db.collection('staged-users').doc(data.docId).get()
437
+ if (stagedUser.exists) {
438
+ const stagedUserData = stagedUser.data()
439
+
440
+ const rolesExist = stagedUserData.roles && Object.keys(stagedUserData.roles).length !== 0
441
+ const specialPermissionsExist = stagedUserData.specialPermissions && Object.keys(stagedUserData.specialPermissions).length !== 0
442
+ const userIdExistsAndNotBlank = stagedUserData.userId && stagedUserData.userId !== ''
443
+
444
+ if (!rolesExist && !specialPermissionsExist && !userIdExistsAndNotBlank) {
445
+ await db.collection('staged-users').doc(data.docId).delete()
446
+ return { success: true, message: '' }
447
+ }
448
+ else {
449
+ let message = ''
450
+ if (rolesExist && specialPermissionsExist) {
451
+ message = 'Cannot delete because the non-registered user still has roles and special permissions assigned.'
443
452
  }
444
- else {
445
- let message = ''
446
- if (rolesExist && specialPermissionsExist) {
447
- message = 'Cannot delete because the non-registered user still has roles and special permissions assigned.'
448
- }
449
- else if (rolesExist) {
450
- message = 'Cannot delete because the non-registered user still has roles assigned.'
451
- }
452
- else if (specialPermissionsExist) {
453
- message = 'Cannot delete because the non-registered user still has special permissions assigned.'
454
- }
455
- else if (userIdExistsAndNotBlank) {
456
- message = 'Cannot delete because the user is registered.'
457
- }
458
- return { success: false, message }
453
+ else if (rolesExist) {
454
+ message = 'Cannot delete because the non-registered user still has roles assigned.'
455
+ }
456
+ else if (specialPermissionsExist) {
457
+ message = 'Cannot delete because the non-registered user still has special permissions assigned.'
458
+ }
459
+ else if (userIdExistsAndNotBlank) {
460
+ message = 'Cannot delete because the user is registered.'
459
461
  }
462
+ return { success: false, message }
460
463
  }
461
464
  }
462
465
  return { success: false, message: 'Non-registered user not found.' }
463
466
  })
464
467
 
465
468
  exports.currentUserRegister = onCall(async (request) => {
469
+ assertCallableUser(request)
466
470
  const data = request.data
467
- const auth = request.auth
468
- if (data.uid === auth.uid) {
469
- const stagedUser = await db.collection('staged-users').doc(data.registrationCode).get()
470
- if (!stagedUser.exists) {
471
- return { success: false, message: 'Registration code not found.' }
471
+ const stagedUser = await db.collection('staged-users').doc(data.registrationCode).get()
472
+ if (!stagedUser.exists) {
473
+ return { success: false, message: 'Registration code not found.' }
474
+ }
475
+ else {
476
+ const stagedUserData = await stagedUser.data()
477
+ let process = false
478
+ if (stagedUserData.isTemplate) {
479
+ process = true
472
480
  }
473
- else {
474
- const stagedUserData = await stagedUser.data()
475
- let process = false
476
- if (stagedUserData.isTemplate) {
477
- process = true
478
- }
479
- if (!stagedUserData.isTemplate && stagedUserData.userId === '') {
480
- process = true
481
- }
482
- if (!process) {
483
- return { success: false, message: 'Registration code not valid.' }
484
- }
485
- const newRoles = stagedUserData.roles || {}
486
- const currentUser = await db.collection('users').doc(data.uid).get()
487
- const currentUserData = await currentUser.data()
488
- const currentRoles = currentUserData.roles || {}
489
- const currentUserCollectionPaths = currentUserData.collectionPaths || []
490
- let newRole = {}
491
- if (stagedUserData.subCreate && Object.keys(stagedUserData.subCreate).length !== 0 && stagedUserData.isTemplate) {
492
- if (!data.dynamicDocumentFieldValue) {
493
- return { success: false, message: 'Dynamic document field value is required.' }
494
- }
495
- const rootPath = stagedUserData.subCreate.rootPath
496
- const newDoc = stagedUserData.subCreate.documentStructure
497
- newDoc[stagedUserData.subCreate.dynamicDocumentField] = data.dynamicDocumentFieldValue
498
- const addedDoc = await db.collection(rootPath).add(newDoc)
499
- await db.collection(rootPath).doc(addedDoc.id).update({ docId: addedDoc.id })
500
- newRole = { [`${rootPath}-${addedDoc.id}`]: { collectionPath: `${rootPath}-${addedDoc.id}`, role: stagedUserData.subCreate.role } }
481
+ if (!stagedUserData.isTemplate && stagedUserData.userId === '') {
482
+ process = true
483
+ }
484
+ if (!process) {
485
+ return { success: false, message: 'Registration code not valid.' }
486
+ }
487
+ const newRoles = stagedUserData.roles || {}
488
+ const currentUser = await db.collection('users').doc(data.uid).get()
489
+ const currentUserData = await currentUser.data()
490
+ const currentRoles = currentUserData.roles || {}
491
+ const currentUserCollectionPaths = currentUserData.collectionPaths || []
492
+ let newRole = {}
493
+ if (stagedUserData.subCreate && Object.keys(stagedUserData.subCreate).length !== 0 && stagedUserData.isTemplate) {
494
+ if (!data.dynamicDocumentFieldValue) {
495
+ return { success: false, message: 'Dynamic document field value is required.' }
501
496
  }
502
- const combinedRoles = { ...currentRoles, ...newRoles, ...newRole }
503
- Object.values(combinedRoles).forEach((role) => {
504
- if (!currentUserCollectionPaths.includes(role.collectionPath)) {
505
- currentUserCollectionPaths.push(role.collectionPath)
506
- }
507
- })
508
- await db.collection('staged-users').doc(currentUserData.stagedDocId).update({ roles: combinedRoles, collectionPaths: currentUserCollectionPaths })
509
- if (!stagedUserData.isTemplate) {
510
- await db.collection('staged-users').doc(data.registrationCode).delete()
497
+ const rootPath = stagedUserData.subCreate.rootPath
498
+ const newDoc = stagedUserData.subCreate.documentStructure
499
+ newDoc[stagedUserData.subCreate.dynamicDocumentField] = data.dynamicDocumentFieldValue
500
+ const addedDoc = await db.collection(rootPath).add(newDoc)
501
+ await db.collection(rootPath).doc(addedDoc.id).update({ docId: addedDoc.id })
502
+ newRole = { [`${rootPath}-${addedDoc.id}`]: { collectionPath: `${rootPath}-${addedDoc.id}`, role: stagedUserData.subCreate.role } }
503
+ }
504
+ const combinedRoles = { ...currentRoles, ...newRoles, ...newRole }
505
+ Object.values(combinedRoles).forEach((role) => {
506
+ if (!currentUserCollectionPaths.includes(role.collectionPath)) {
507
+ currentUserCollectionPaths.push(role.collectionPath)
511
508
  }
512
- return { success: true, message: '' }
509
+ })
510
+ await db.collection('staged-users').doc(currentUserData.stagedDocId).update({ roles: combinedRoles, collectionPaths: currentUserCollectionPaths })
511
+ if (!stagedUserData.isTemplate) {
512
+ await db.collection('staged-users').doc(data.registrationCode).delete()
513
513
  }
514
+ return { success: true, message: '' }
514
515
  }
515
516
  })
516
517
 
@@ -522,52 +523,51 @@ exports.checkOrgIdExists = onCall(async (request) => {
522
523
  })
523
524
 
524
525
  exports.deleteSelf = onCall(async (request) => {
525
- if (request.data.uid === request.auth.uid) {
526
- try {
527
- const userDoc = await db.collection('staged-users').doc(request.auth.uid).get()
528
- const userData = userDoc.data()
529
- const userCollectionPaths = userData.collectionPaths || []
530
-
531
- for (const path of userCollectionPaths) {
532
- const usersWithSamePath = await db.collection('staged-users').where('collectionPaths', 'array-contains', path).get()
533
-
534
- // If no other users have the same collection path, delete the path and all documents and collections under it
535
- if (usersWithSamePath.size <= 1) {
536
- const adjustedPath = path.replace(/-/g, '/')
537
- const docRef = db.doc(adjustedPath)
538
- const doc = await docRef.get()
539
-
540
- if (doc.exists) {
541
- // If the path is a document, delete it directly
542
- await docRef.delete()
543
- }
544
- else {
545
- // If the path is a collection, delete all documents under it
546
- const docsToDelete = await db.collection(adjustedPath).get()
547
- const batch = db.batch()
548
- docsToDelete.docs.forEach((doc) => {
549
- batch.delete(doc.ref)
550
- })
551
- await batch.commit()
552
- }
526
+ assertCallableUser(request)
527
+ try {
528
+ const userDoc = await db.collection('staged-users').doc(request.auth.uid).get()
529
+ const userData = userDoc.data()
530
+ const userCollectionPaths = userData.collectionPaths || []
531
+
532
+ for (const path of userCollectionPaths) {
533
+ const usersWithSamePath = await db.collection('staged-users').where('collectionPaths', 'array-contains', path).get()
534
+
535
+ // If no other users have the same collection path, delete the path and all documents and collections under it
536
+ if (usersWithSamePath.size <= 1) {
537
+ const adjustedPath = path.replace(/-/g, '/')
538
+ const docRef = db.doc(adjustedPath)
539
+ const doc = await docRef.get()
540
+
541
+ if (doc.exists) {
542
+ // If the path is a document, delete it directly
543
+ await docRef.delete()
544
+ }
545
+ else {
546
+ // If the path is a collection, delete all documents under it
547
+ const docsToDelete = await db.collection(adjustedPath).get()
548
+ const batch = db.batch()
549
+ docsToDelete.docs.forEach((doc) => {
550
+ batch.delete(doc.ref)
551
+ })
552
+ await batch.commit()
553
553
  }
554
554
  }
555
+ }
555
556
 
556
- // Delete from 'staged-users' collection
557
- await db.collection('staged-users').doc(request.data.uid).delete()
557
+ // Delete from 'staged-users' collection
558
+ await db.collection('staged-users').doc(request.data.uid).delete()
558
559
 
559
- // Delete from 'users' collection
560
- await db.collection('users').doc(request.data.uid).delete()
560
+ // Delete from 'users' collection
561
+ await db.collection('users').doc(request.data.uid).delete()
561
562
 
562
- // Delete the user from Firebase
563
- await admin.auth().deleteUser(request.data.uid)
563
+ // Delete the user from Firebase
564
+ await admin.auth().deleteUser(request.data.uid)
564
565
 
565
- return { success: true }
566
- }
567
- catch (error) {
568
- console.error('Error deleting user:', error)
569
- return { success: false, error }
570
- }
566
+ return { success: true }
567
+ }
568
+ catch (error) {
569
+ console.error('Error deleting user:', error)
570
+ return { success: false, error }
571
571
  }
572
572
  })
573
573