@@ -177,13 +177,292 @@ to make sure certain aspects are available to us without breaking existing markd
177
177
### grouped code blocks
178
178
{{group: code }}
179
179
``` js
180
- javascript goes here
181
- ```
182
- ``` dart
183
- dart goes here
180
+ const functions = require (' firebase-functions/v2' );
181
+ const admin = require (' firebase-admin' );
182
+ const { getFirestore } = require (' firebase-admin/firestore' );
183
+ const { getDatabase } = require (' firebase-admin/database' );
184
+ const { getStorage } = require (' firebase-admin/storage' );
185
+ const { getMessaging } = require (' firebase-admin/messaging' );
186
+ const nodemailer = require (' nodemailer' );
187
+ const { v4: uuidv4 } = require (' uuid' );
188
+
189
+ // Initialize Firebase Admin SDK
190
+ admin .initializeApp ();
191
+
192
+ const db = getFirestore ();
193
+ const rtdb = getDatabase ();
194
+ const storage = getStorage ();
195
+ const messaging = getMessaging ();
196
+
197
+ exports .complexFunction = functions .https .onRequest (async (req , res ) => {
198
+ try {
199
+ const { userId , actionType , payload } = req .body ;
200
+
201
+ // Input validation
202
+ if (! userId || ! actionType || ! payload) {
203
+ res .status (400 ).send (' Missing required fields' );
204
+ return ;
205
+ }
206
+
207
+ // Firestore operation
208
+ const userDoc = await db .collection (' users' ).doc (userId).get ();
209
+ if (! userDoc .exists ) {
210
+ res .status (404 ).send (' User not found' );
211
+ return ;
212
+ }
213
+ const userData = userDoc .data ();
214
+
215
+ // Realtime Database operation
216
+ const userRTDBRef = rtdb .ref (` users/${ userId} ` );
217
+ const userRTDBData = (await userRTDBRef .get ()).val ();
218
+
219
+ // Cloud Storage operation
220
+ const filePath = ` user_data/${ userId} /profile_picture.jpg` ;
221
+ const file = storage .bucket ().file (filePath);
222
+ const [exists ] = await file .exists ();
223
+ let downloadURL = null ;
224
+ if (exists) {
225
+ downloadURL = await file .getSignedUrl ({
226
+ action: ' read' ,
227
+ expires: ' 03-17-2025'
228
+ });
229
+ }
230
+
231
+ // Handle different action types
232
+ switch (actionType) {
233
+ case ' UPDATE_PROFILE' :
234
+ await handleProfileUpdate (userId, payload);
235
+ break ;
236
+ case ' SEND_NOTIFICATION' :
237
+ await sendNotification (userData, payload);
238
+ break ;
239
+ case ' PROCESS_ORDER' :
240
+ await processOrder (userId, payload);
241
+ break ;
242
+ default :
243
+ res .status (400 ).send (' Invalid action type' );
244
+ return ;
245
+ }
246
+
247
+ // Send response
248
+ res .status (200 ).send ({
249
+ message: ' Action processed successfully' ,
250
+ userData,
251
+ userRTDBData,
252
+ downloadURL
253
+ });
254
+ } catch (error) {
255
+ console .error (' Error processing request:' , error);
256
+ res .status (500 ).send (' Internal server error' );
257
+ }
258
+ });
259
+
260
+ async function handleProfileUpdate (userId , payload ) {
261
+ try {
262
+ await db .collection (' users' ).doc (userId).update (payload);
263
+ console .log (' Profile updated successfully for user:' , userId);
264
+ } catch (error) {
265
+ console .error (' Error updating profile:' , error);
266
+ throw new functions.https.HttpsError (' internal' , ' Error updating profile' );
267
+ }
268
+ }
269
+
270
+ async function sendNotification (userData , payload ) {
271
+ try {
272
+ const message = {
273
+ notification: {
274
+ title: payload .title ,
275
+ body: payload .body
276
+ },
277
+ token: userData .fcmToken
278
+ };
279
+ await messaging .send (message);
280
+ console .log (' Notification sent successfully to user:' , userData .userId );
281
+ } catch (error) {
282
+ console .error (' Error sending notification:' , error);
283
+ throw new functions.https.HttpsError (' internal' , ' Error sending notification' );
284
+ }
285
+ }
286
+
287
+ async function processOrder (userId , payload ) {
288
+ try {
289
+ const orderId = uuidv4 ();
290
+ await db .collection (' orders' ).doc (orderId).set ({
291
+ userId,
292
+ ... payload,
293
+ status: ' Processing' ,
294
+ createdAt: admin .firestore .FieldValue .serverTimestamp ()
295
+ });
296
+ console .log (' Order processed successfully for user:' , userId);
297
+
298
+ // Send confirmation email
299
+ await sendConfirmationEmail (userId, orderId);
300
+ } catch (error) {
301
+ console .error (' Error processing order:' , error);
302
+ throw new functions.https.HttpsError (' internal' , ' Error processing order' );
303
+ }
304
+ }
305
+
306
+ async function sendConfirmationEmail (userId , orderId ) {
307
+ try {
308
+ const userDoc = await db .collection (' users' ).doc (userId).get ();
309
+ const userData = userDoc .data ();
310
+
311
+ const transporter = nodemailer .createTransport ({
312
+ service: ' gmail' ,
313
+ auth: {
314
+ user: process .env .GMAIL_USER ,
315
+ pass: process .env .GMAIL_PASS
316
+ }
317
+ });
318
+
319
+ const mailOptions = {
320
+ from: process .env .GMAIL_USER ,
321
+ to: userData .email ,
322
+ subject: ' Order Confirmation' ,
323
+ text: ` Your order with ID ${ orderId} has been received and is being processed.`
324
+ };
325
+
326
+ await transporter .sendMail (mailOptions);
327
+ console .log (' Confirmation email sent to user:' , userId);
328
+ } catch (error) {
329
+ console .error (' Error sending confirmation email:' , error);
330
+ throw new functions.https.HttpsError (' internal' , ' Error sending confirmation email' );
331
+ }
332
+ }
184
333
```
185
- ``` py
186
- python goes here
334
+ ``` python
335
+ import os
336
+ import firebase_admin
337
+ from firebase_admin import firestore, db, storage, messaging
338
+ from flask import Flask, request, jsonify
339
+ import uuid
340
+ import smtplib
341
+ from email.mime.text import MIMEText
342
+ from google.cloud import tasks_v2
343
+
344
+ # Initialize Firebase Admin SDK
345
+ firebase_admin.initialize_app(options = {
346
+ ' storageBucket' : os.getenv(' GCP_STORAGE_BUCKET' )
347
+ })
348
+
349
+ # Firestore, Realtime Database, Storage, and FCM initialization
350
+ firestore_client = firestore.client()
351
+ rtdb_ref = db.reference()
352
+ storage_bucket = storage.bucket()
353
+ app = Flask(__name__ )
354
+
355
+ @app.route (' /complex-function' , methods = [' POST' ])
356
+ def complex_function ():
357
+ try :
358
+ data = request.get_json()
359
+ user_id = data.get(' userId' )
360
+ action_type = data.get(' actionType' )
361
+ payload = data.get(' payload' )
362
+
363
+ # Input validation
364
+ if not user_id or not action_type or not payload:
365
+ return jsonify({' error' : ' Missing required fields' }), 400
366
+
367
+ # Firestore operation
368
+ user_doc = firestore_client.collection(' users' ).document(user_id).get()
369
+ if not user_doc.exists:
370
+ return jsonify({' error' : ' User not found' }), 404
371
+ user_data = user_doc.to_dict()
372
+
373
+ # Realtime Database operation
374
+ user_rtdb_data = rtdb_ref.child(f ' users/ { user_id} ' ).get()
375
+
376
+ # Cloud Storage operation
377
+ file_path = f ' user_data/ { user_id} /profile_picture.jpg '
378
+ blob = storage_bucket.blob(file_path)
379
+ download_url = None
380
+ if blob.exists():
381
+ download_url = blob.generate_signed_url(expiration = 3600 )
382
+
383
+ # Handle different action types
384
+ if action_type == ' UPDATE_PROFILE' :
385
+ handle_profile_update(user_id, payload)
386
+ elif action_type == ' SEND_NOTIFICATION' :
387
+ send_notification(user_data, payload)
388
+ elif action_type == ' PROCESS_ORDER' :
389
+ process_order(user_id, payload)
390
+ else :
391
+ return jsonify({' error' : ' Invalid action type' }), 400
392
+
393
+ # Send response
394
+ return jsonify({
395
+ ' message' : ' Action processed successfully' ,
396
+ ' userData' : user_data,
397
+ ' userRTDBData' : user_rtdb_data,
398
+ ' downloadURL' : download_url
399
+ }), 200
400
+ except Exception as e:
401
+ print (f ' Error processing request: { e} ' )
402
+ return jsonify({' error' : ' Internal server error' }), 500
403
+
404
+ def handle_profile_update (user_id , payload ):
405
+ try :
406
+ firestore_client.collection(' users' ).document(user_id).update(payload)
407
+ print (f ' Profile updated successfully for user: { user_id} ' )
408
+ except Exception as e:
409
+ print (f ' Error updating profile: { e} ' )
410
+ raise
411
+
412
+ def send_notification (user_data , payload ):
413
+ try :
414
+ message = messaging.Message(
415
+ notification = messaging.Notification(
416
+ title = payload.get(' title' ),
417
+ body = payload.get(' body' )
418
+ ),
419
+ token = user_data.get(' fcmToken' )
420
+ )
421
+ messaging.send(message)
422
+ print (f ' Notification sent successfully to user: { user_data.get(" userId" )} ' )
423
+ except Exception as e:
424
+ print (f ' Error sending notification: { e} ' )
425
+ raise
426
+
427
+ def process_order (user_id , payload ):
428
+ try :
429
+ order_id = str (uuid.uuid4())
430
+ firestore_client.collection(' orders' ).document(order_id).set({
431
+ ' userId' : user_id,
432
+ ' status' : ' Processing' ,
433
+ ' createdAt' : firestore.SERVER_TIMESTAMP ,
434
+ ** payload
435
+ })
436
+ print (f ' Order processed successfully for user: { user_id} ' )
437
+
438
+ # Send confirmation email
439
+ send_confirmation_email(user_id, order_id)
440
+ except Exception as e:
441
+ print (f ' Error processing order: { e} ' )
442
+ raise
443
+
444
+ def send_confirmation_email (user_id , order_id ):
445
+ try :
446
+ user_doc = firestore_client.collection(' users' ).document(user_id).get()
447
+ user_data = user_doc.to_dict()
448
+
449
+ msg = MIMEText(f ' Your order with ID { order_id} has been received and is being processed. ' )
450
+ msg[' Subject' ] = ' Order Confirmation'
451
+ msg[' From' ] = os.getenv(' GMAIL_USER' )
452
+ msg[' To' ] = user_data.get(' email' )
453
+
454
+ with smtplib.SMTP_SSL(' smtp.gmail.com' , 465 ) as server:
455
+ server.login(os.getenv(' GMAIL_USER' ), os.getenv(' GMAIL_PASS' ))
456
+ server.send_message(msg)
457
+
458
+ print (f ' Confirmation email sent to user: { user_id} ' )
459
+ except Exception as e:
460
+ print (f ' Error sending confirmation email: { e} ' )
461
+ raise
462
+
463
+ if __name__ == ' __main__' :
464
+ app.run(debug = True )
465
+
187
466
```
188
467
{{endgroup}}
189
468
0 commit comments