@@ -4,45 +4,68 @@ import { backupFirestore } from './backup'
4
4
import { checkFirestoreBackupStatus } from './status'
5
5
import { Response } from 'express'
6
6
import { getCollections } from './collections'
7
+ import * as functions from 'firebase-functions'
7
8
8
- export type FirestoreBackupOptions = {
9
+ export interface FirestoreBackupOptions {
9
10
bucketsAllowlist ?: string [ ]
10
11
projectId : string
11
12
}
12
13
13
- export type FirestoreBackupRequestOptions = {
14
+ export type FirestoreBackupRequestBody =
15
+ | FirestoreBackupRequestBodyComplete
16
+ | FirestoreBackupRequestBodySelective
17
+
18
+ export interface FirestoreBackupRequestBodyBase {
14
19
storageId : string
15
20
path : string
16
- } & (
17
- | {
18
- mode : 'complete'
19
- }
20
- | {
21
- mode : 'selective'
22
- ignoreCollections ?: string [ ]
23
- collectionGroups ?: string [ ]
24
- }
25
- )
21
+ }
22
+
23
+ export interface FirestoreBackupRequestBodyComplete
24
+ extends FirestoreBackupRequestBodyBase {
25
+ mode : 'complete'
26
+ }
27
+
28
+ export interface FirestoreBackupRequestBodySelective
29
+ extends FirestoreBackupRequestBodyBase {
30
+ mode : 'selective'
31
+ ignoreCollections ?: string [ ]
32
+ collectionGroups ?: string [ ]
33
+ }
26
34
27
35
export function backupFirestoreMiddleware ( {
28
36
bucketsAllowlist,
29
37
projectId,
30
38
} : FirestoreBackupOptions ) {
31
39
return asyncMiddleware ( async ( request , response ) => {
32
- // TODO: Validate options
33
- const options = request . body as FirestoreBackupRequestOptions
40
+ // TODO: Validate body
41
+ const body = request . body as FirestoreBackupRequestBody
42
+
43
+ if ( body . mode === 'selective' ) {
44
+ functions . logger . info ( 'Requested Firestore backup' , {
45
+ // NOTE: Do not ...body here to avoid logging sensitive data
46
+ mode : body . mode ,
47
+ ignoreCollections : body . ignoreCollections ,
48
+ collectionGroups : body . collectionGroups ,
49
+ bucketsAllowlist,
50
+ projectId,
51
+ } )
34
52
35
- if ( options . mode === 'selective' ) {
36
53
// Get all root-level collections
37
54
const allCollections = await getCollections ( )
38
- const { ignoreCollections, collectionGroups } = options
39
- const exportedCollections = ( ignoreCollections
40
- ? allCollections . filter ( ( coll ) => ! ignoreCollections . includes ( coll ) )
41
- : allCollections
55
+ const { ignoreCollections, collectionGroups } = body
56
+ const exportedCollections = (
57
+ ignoreCollections
58
+ ? allCollections . filter ( ( coll ) => ! ignoreCollections . includes ( coll ) )
59
+ : allCollections
42
60
) . concat ( collectionGroups || [ ] )
43
61
62
+ functions . logger . info ( 'Initiating selective Firestore backup' , {
63
+ exportedCollections,
64
+ ignoreCollections,
65
+ } )
66
+
44
67
// Request selective Firestore backup
45
- const id = await backupFirestore ( projectId , exportedCollections , options )
68
+ const id = await backupFirestore ( projectId , exportedCollections , body )
46
69
47
70
if ( id ) {
48
71
return respondWithStatus ( response , id , {
@@ -53,8 +76,18 @@ export function backupFirestoreMiddleware({
53
76
return respondWithMissingId ( response )
54
77
}
55
78
} else {
79
+ functions . logger . info ( 'Requested Firestore backup' , {
80
+ // NOTE: Do not ...body here to avoid logging sensitive data
81
+ mode : body . mode ,
82
+ bucketsAllowlist,
83
+ projectId,
84
+ } )
85
+
86
+ // NOTE: Back-to-back logging here is to reflect the selective backup logging
87
+ functions . logger . info ( 'Initiating complete Firestore backup' )
88
+
56
89
// Request complete Firestore backup
57
- const id = await backupFirestore ( projectId , undefined , options )
90
+ const id = await backupFirestore ( projectId , undefined , body )
58
91
59
92
if ( id ) {
60
93
return respondWithStatus ( response , id )
@@ -65,15 +98,19 @@ export function backupFirestoreMiddleware({
65
98
} )
66
99
}
67
100
68
- export type FirestoreCheckBackupStatusRequestOptions = {
101
+ export interface FirestoreCheckBackupStatusRequestOptions {
69
102
id : string
70
103
}
71
104
72
105
export function checkFirestoreBackupStatusMiddleware ( ) {
73
106
return asyncMiddleware ( async ( request , response ) => {
74
- // TODO: Validate options
75
- const options = request . query as FirestoreCheckBackupStatusRequestOptions
76
- return respondWithStatus ( response , options . id )
107
+ // TODO: Validate query
108
+ const query =
109
+ request . query as unknown as FirestoreCheckBackupStatusRequestOptions
110
+
111
+ functions . logger . info ( 'Requested Firestore backup status' )
112
+
113
+ return respondWithStatus ( response , query . id )
77
114
} )
78
115
}
79
116
@@ -82,14 +119,22 @@ async function respondWithStatus(
82
119
id : string ,
83
120
extraData : object = { }
84
121
) {
122
+ functions . logger . info ( 'Checking the backup status' , { id } )
123
+
85
124
const status = await checkFirestoreBackupStatus ( id )
125
+ const state = status . done ? 'completed' : 'pending'
126
+
127
+ functions . logger . info ( 'Responding with the backup status' , { id, state } )
128
+
86
129
operationResponse ( response , {
87
- state : status . done ? 'completed' : 'pending' ,
130
+ state,
88
131
data : Object . assign ( { id, status } , extraData ) ,
89
132
} )
90
133
}
91
134
92
135
function respondWithMissingId ( response : Response ) {
136
+ functions . logger . info ( 'Responding with missing id error' )
137
+
93
138
operationResponse ( response , {
94
139
state : 'failed' ,
95
140
data : {
@@ -101,7 +146,14 @@ function respondWithMissingId(response: Response) {
101
146
102
147
export function getCollectionsMiddleware ( ) {
103
148
return asyncMiddleware ( async ( _request , response ) => {
149
+ functions . logger . info ( 'Requested Firestore collections' )
150
+
104
151
const collections = await getCollections ( )
152
+
153
+ functions . logger . info ( 'Responding with Firestore collections' , {
154
+ collections,
155
+ } )
156
+
105
157
response . send ( collections )
106
158
} )
107
159
}
0 commit comments