Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions firestore/angular-rewrite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ Follow these steps to have a working version of the quickstart running with the
ng serve
```

11. (Optional) Populate production Firestore with mock data

Now that the application is live on the Firebase console, you likely want to add some data to your production Firestore database so that you can see the application in action. Rather than manually adding restaurants and reviews, a convenice script is available to populate your production Firestore database. Run the following command (defined in the `Firestore/` directory's `package.json`) to add mock data:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: let's note that this requires your configuration to exist in the config file


```bash
npm run populate-production
```

> **Note:** To ensure that the script runs as intended, make sure that you have correctly populated the `environemnt.prod.ts` file with your Firebase credentials.

## Support

- [Firebase Support](https://firebase.google.com/support/)
Expand Down
2 changes: 2 additions & 0 deletions firestore/angular-rewrite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"scripts": {
"ng": "ng",
"start": "(cd functions && npm run build) && firebase --project demo-friendly-eats emulators:exec --import ./imported-firebase-data 'ng serve'",
"populate-emulators": "cp src/environments/environment.ts scripts/environment.js && node scripts/PopulateFirestore.js",
"populate-production": "cp src/environments/environment.prod.ts scripts/environment.js && node scripts/PopulateFirestore.js",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
Expand Down
5 changes: 5 additions & 0 deletions firestore/angular-rewrite/scripts/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"parserOptions": {
"sourceType": "module"
}
}
106 changes: 106 additions & 0 deletions firestore/angular-rewrite/scripts/MockRestaurantData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


/** If connecting to a live Firebase project (one that you set up in the
* Firebase console) put your config vars into the `prod` field object here
* and change the `initializeApp` value in `app.module.ts` to `environment.prod`.
* Otherwise, leave untouched to enable connection to demo project and emulators.
*/

export const data = {
words: [
'Bar',
'Fire',
'Grill',
'Drive Thru',
'Place',
'Best',
'Spot',
'Prime',
'Eatin\'',
],
cities: [
'Albuquerque',
'Arlington',
'Atlanta',
'Austin',
'Baltimore',
'Boston',
'Charlotte',
'Chicago',
'Cleveland',
'Colorado Springs',
'Columbus',
'Dallas',
'Denver',
'Detroit',
'El Paso',
'Fort Worth',
'Fresno',
'Houston',
'Indianapolis',
'Jacksonville',
'Kansas City',
'Las Vegas',
'Long Island',
'Los Angeles',
'Louisville',
'Memphis',
'Mesa',
'Miami',
'Milwaukee',
'Nashville',
'New York',
'Oakland',
'Oklahoma',
'Omaha',
'Philadelphia',
'Phoenix',
'Portland',
'Raleigh',
'Sacramento',
'San Antonio',
'San Diego',
'San Francisco',
'San Jose',
'Tucson',
'Tulsa',
'Virginia Beach',
'Washington',
],
categories: [
'Brunch',
'Burgers',
'Coffee',
'Deli',
'Dim Sum',
'Indian',
'Italian',
'Mediterranean',
'Mexican',
'Pizza',
'Ramen',
'Sushi',
],
ratingsTexts: {
1: 'Would never eat here again!',
2: 'Not my cup of tea.',
3: 'Exactly okay :/',
4: 'Actually pretty good, would recommend!',
5: 'This is my favorite place. Literally.',
},
};
174 changes: 174 additions & 0 deletions firestore/angular-rewrite/scripts/PopulateFirestore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* Copyright 2023 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* This script creates a set of fake restaurants with fake reviews and
* populates the Firestore database with them. An `Anonymous` user is
* created for this (in `signInWithAnonCredentials`) since the rules
* defined in `../../firestore.rules` prevent unauthenticated users from
* modifying the contents of the firestore database.
*/

import { initializeApp } from 'firebase/app';
import {
getFirestore,
connectFirestoreEmulator,
addDoc,
collection,
} from 'firebase/firestore/lite';
import {
getAuth,
connectAuthEmulator,
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
} from 'firebase/auth';

import { projectConfig } from './environment.js';
import { data } from './MockRestaurantData.js';

const app = initializeApp(projectConfig);
const auth = getAuth(app);
const db = getFirestore(app);

/**
* Connect to emulators if a `demo` configuration hasn been pulled from
* environment.js.
*/
if (app.options.projectId.indexOf('demo-') == 0) {
connectFirestoreEmulator(db, '127.0.0.1', 8080);
connectAuthEmulator(auth, 'http://127.0.0.1:9099');
}

/**
* Signs into an `Anonymous` user with which to post restaurants and comments.
*/
const signInWithAnonCredentials = async () => {
try {
await signInWithEmailAndPassword(
auth,
'[email protected]',
'AnonymousPassword'
);
} catch (userNotCreatedError) {
await createUserWithEmailAndPassword(
auth,
'[email protected]',
'AnonymousPassword'
);
}
};

/**
* Adds a single mock restaurant, and an associated rating, to the Firestore
* database.
*/
const addFakeRestaurant = async (restaurant) => {
const restaurantRef = await addDoc(collection(db, 'restaurants'), restaurant);
addMockRating(restaurantRef.id, restaurant.avgRating);
};

/**
* A function to generate 20 random `Restaurant` objects. The definiton
* for a `Restaurant` is given in `../types/restaurant.ts`.
* @returns A list of 20 mock `Restaurant` objects to send to firestore
*/
const generateMockRestaurants = () => {
var restaurants = [];

for (var i = 0; i < 20; i++) {
var name = getRandomItem(data.words) + ' ' + getRandomItem(data.words);
var category = getRandomItem(data.categories);
var city = getRandomItem(data.cities);
var price = Math.floor(Math.random() * 4) + 1;
var photoID = Math.floor(Math.random() * 22) + 1;
// TODO(abradham): Modify to be able to use local emulated storage bucket
var photo =
'https://storage.googleapis.com/firestorequickstarts.appspot.com/food_' +
photoID +
'.png';
var numRatings = 0;
var avgRating = Math.floor(Math.random() * 5) + 1;

restaurants.push({
name: name,
category: category,
price: price,
city: city,
numRatings: numRatings,
avgRating: avgRating,
photo: photo,
});
}

return restaurants;
};

/**
* Adds a list of generated restaurants to Firestore database.
* @param {Restaurant[]} restaurntsArr
* @returns {Promise[]} List of promises
*/
const addMockRestaurants = async (restaurntsArr) => {
let promises = [];
for (var i = 0; i < restaurntsArr.length; i++) {
let promise = addFakeRestaurant(restaurntsArr[i]);
if (!promise) {
console.debug('Couldn\'t add a restaurant to firestore');
return Promise.reject();
} else {
promises.push(promise);
}
}

await Promise.all(promises);
};

const getRandomItem = (arr) => {
return arr[Math.floor(Math.random() * arr.length)];
};

/**
*
* @param {string} restaurantId: Firebase document id of relevant restaurant object
* @param {number} avgRating: # of stars given to the restaurant
*/
const addMockRating = async (restaurantId, avgRating) => {
// Create new `rating` obj
const newRating = {
rating: avgRating,
text: data.ratingsTexts[avgRating],
userName: 'Anonymous (Bot)',
};

// Add new rating to given restaurant's `ratings/` subcollection
await addDoc(
collection(db, `restaurants/${restaurantId}/ratings`),
newRating
);
};

const main = async () => {
// Connect to emulators if a `demo` environment is pulled
if (app.options.projectId.indexOf('demo-') == 0) {
connectFirestoreEmulator(db, '127.0.0.1', 8080);
connectAuthEmulator(auth, 'http://127.0.0.1:9099');
}

await signInWithAnonCredentials();
await addMockRestaurants(generateMockRestaurants());
};

main();
13 changes: 13 additions & 0 deletions firestore/angular-rewrite/scripts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions firestore/angular-rewrite/scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "scripts",
"version": "1.0.0",
"description": "A script to send mock data to the prod firebase console",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this package.json anymore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so; I'm importing node modules using the import syntax in PopulateFirestore.js, and when I attempt to run the script after removing the package.json, I get an error that reads

SyntaxError: Cannot use import statement outside a module

"main": "PopulateFirestore.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "Apache-2.0",
"type": "module"
}
4 changes: 2 additions & 2 deletions firestore/angular-rewrite/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { provideAuth, getAuth, connectAuthEmulator } from '@angular/fire/auth';
import { provideFirestore, getFirestore } from '@angular/fire/firestore';
import { provideFunctions, getFunctions } from '@angular/fire/functions';
import { provideStorage, getStorage } from '@angular/fire/storage'
import { environment } from 'src/environments/environment';
import { projectConfig } from 'src/environments/environment';
import { HomepageComponent } from './homepage/homepage.component';
import { RestuarantPageComponent } from './restuarant-page/restuarant-page.component';
import { MatIconModule } from '@angular/material/icon';
Expand Down Expand Up @@ -76,7 +76,7 @@ import { SignInModalComponent } from './sign-in-modal/sign-in-modal.component';
MatInputModule,
MatButtonModule,
BrowserAnimationsModule,
provideFirebaseApp(() => initializeApp(environment.local)),
provideFirebaseApp(() => initializeApp(projectConfig)),
FormsModule,
provideAuth(() => {
const auth = getAuth();
Expand Down
10 changes: 4 additions & 6 deletions firestore/angular-rewrite/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@
* and change the `initializeApp` value in `app.module.ts` to `environment.prod`.
* Otherwise, leave untouched to enable connection to demo project and emulators.
*/
export const environment = {
local: {
projectId: 'demo-friendly-eats',
apiKey: '[FIREBASE_API_KEY]'
},
prod: {}

export const projectConfig = {
projectId: 'demo-friendly-eats',
apiKey: 'API_KEY_UNUSED'
}