|
| 1 | +/** |
| 2 | + * Copyright 2023 Google Inc. All Rights Reserved. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the 'License'); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an 'AS IS' BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +/** |
| 18 | + * This script creates a set of fake restaurants with fake reviews and |
| 19 | + * populates the Firestore database with them. An `Anonymous` user is |
| 20 | + * created for this (in `signInWithAnonCredentials`) since the rules |
| 21 | + * defined in `../../firestore.rules` prevent unauthenticated users from |
| 22 | + * modifying the contents of the firestore database. |
| 23 | + */ |
| 24 | + |
| 25 | +import { initializeApp } from 'firebase/app'; |
| 26 | +import { |
| 27 | + getFirestore, |
| 28 | + connectFirestoreEmulator, |
| 29 | + addDoc, |
| 30 | + collection, |
| 31 | +} from 'firebase/firestore/lite'; |
| 32 | +import { |
| 33 | + getAuth, |
| 34 | + connectAuthEmulator, |
| 35 | + createUserWithEmailAndPassword, |
| 36 | + signInWithEmailAndPassword, |
| 37 | +} from 'firebase/auth'; |
| 38 | + |
| 39 | +import { projectConfig } from './environment.js'; |
| 40 | +import { data } from './MockRestaurantData.js'; |
| 41 | + |
| 42 | +const app = initializeApp(projectConfig); |
| 43 | +const auth = getAuth(app); |
| 44 | +const db = getFirestore(app); |
| 45 | + |
| 46 | +/** |
| 47 | + * Connect to emulators if a `demo` configuration hasn been pulled from |
| 48 | + * environment.js. |
| 49 | + */ |
| 50 | +if (app.options.projectId.indexOf('demo-') == 0) { |
| 51 | + connectFirestoreEmulator(db, '127.0.0.1', 8080); |
| 52 | + connectAuthEmulator(auth, 'http://127.0.0.1:9099'); |
| 53 | +} |
| 54 | + |
| 55 | +/** |
| 56 | + * Signs into an `Anonymous` user with which to post restaurants and comments. |
| 57 | + */ |
| 58 | +const signInWithAnonCredentials = async () => { |
| 59 | + try { |
| 60 | + await signInWithEmailAndPassword( |
| 61 | + auth, |
| 62 | + |
| 63 | + 'AnonymousPassword' |
| 64 | + ); |
| 65 | + } catch (userNotCreatedError) { |
| 66 | + await createUserWithEmailAndPassword( |
| 67 | + auth, |
| 68 | + |
| 69 | + 'AnonymousPassword' |
| 70 | + ); |
| 71 | + } |
| 72 | +}; |
| 73 | + |
| 74 | +/** |
| 75 | + * Adds a single mock restaurant, and an associated rating, to the Firestore |
| 76 | + * database. |
| 77 | + */ |
| 78 | +const addFakeRestaurant = async (restaurant) => { |
| 79 | + const restaurantRef = await addDoc(collection(db, 'restaurants'), restaurant); |
| 80 | + addMockRating(restaurantRef.id, restaurant.avgRating); |
| 81 | +}; |
| 82 | + |
| 83 | +/** |
| 84 | + * A function to generate 20 random `Restaurant` objects. The definiton |
| 85 | + * for a `Restaurant` is given in `../types/restaurant.ts`. |
| 86 | + * @returns A list of 20 mock `Restaurant` objects to send to firestore |
| 87 | + */ |
| 88 | +const generateMockRestaurants = () => { |
| 89 | + var restaurants = []; |
| 90 | + |
| 91 | + for (var i = 0; i < 20; i++) { |
| 92 | + var name = getRandomItem(data.words) + ' ' + getRandomItem(data.words); |
| 93 | + var category = getRandomItem(data.categories); |
| 94 | + var city = getRandomItem(data.cities); |
| 95 | + var price = Math.floor(Math.random() * 4) + 1; |
| 96 | + var photoID = Math.floor(Math.random() * 22) + 1; |
| 97 | + // TODO(abradham): Modify to be able to use local emulated storage bucket |
| 98 | + var photo = |
| 99 | + 'https://storage.googleapis.com/firestorequickstarts.appspot.com/food_' + |
| 100 | + photoID + |
| 101 | + '.png'; |
| 102 | + var numRatings = 0; |
| 103 | + var avgRating = Math.floor(Math.random() * 5) + 1; |
| 104 | + |
| 105 | + restaurants.push({ |
| 106 | + name: name, |
| 107 | + category: category, |
| 108 | + price: price, |
| 109 | + city: city, |
| 110 | + numRatings: numRatings, |
| 111 | + avgRating: avgRating, |
| 112 | + photo: photo, |
| 113 | + }); |
| 114 | + } |
| 115 | + |
| 116 | + return restaurants; |
| 117 | +}; |
| 118 | + |
| 119 | +/** |
| 120 | + * Adds a list of generated restaurants to Firestore database. |
| 121 | + * @param {Restaurant[]} restaurntsArr |
| 122 | + * @returns {Promise[]} List of promises |
| 123 | + */ |
| 124 | +const addMockRestaurants = async (restaurntsArr) => { |
| 125 | + let promises = []; |
| 126 | + for (var i = 0; i < restaurntsArr.length; i++) { |
| 127 | + let promise = addFakeRestaurant(restaurntsArr[i]); |
| 128 | + if (!promise) { |
| 129 | + console.debug('Couldn\'t add a restaurant to firestore'); |
| 130 | + return Promise.reject(); |
| 131 | + } else { |
| 132 | + promises.push(promise); |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + await Promise.all(promises); |
| 137 | +}; |
| 138 | + |
| 139 | +const getRandomItem = (arr) => { |
| 140 | + return arr[Math.floor(Math.random() * arr.length)]; |
| 141 | +}; |
| 142 | + |
| 143 | +/** |
| 144 | + * |
| 145 | + * @param {string} restaurantId: Firebase document id of relevant restaurant object |
| 146 | + * @param {number} avgRating: # of stars given to the restaurant |
| 147 | + */ |
| 148 | +const addMockRating = async (restaurantId, avgRating) => { |
| 149 | + // Create new `rating` obj |
| 150 | + const newRating = { |
| 151 | + rating: avgRating, |
| 152 | + text: data.ratingsTexts[avgRating], |
| 153 | + userName: 'Anonymous (Bot)', |
| 154 | + }; |
| 155 | + |
| 156 | + // Add new rating to given restaurant's `ratings/` subcollection |
| 157 | + await addDoc( |
| 158 | + collection(db, `restaurants/${restaurantId}/ratings`), |
| 159 | + newRating |
| 160 | + ); |
| 161 | +}; |
| 162 | + |
| 163 | +const main = async () => { |
| 164 | + // Connect to emulators if a `demo` environment is pulled |
| 165 | + if (app.options.projectId.indexOf('demo-') == 0) { |
| 166 | + connectFirestoreEmulator(db, '127.0.0.1', 8080); |
| 167 | + connectAuthEmulator(auth, 'http://127.0.0.1:9099'); |
| 168 | + } |
| 169 | + |
| 170 | + await signInWithAnonCredentials(); |
| 171 | + await addMockRestaurants(generateMockRestaurants()); |
| 172 | +}; |
| 173 | + |
| 174 | +main(); |
0 commit comments