Skip to content

Commit 54465c7

Browse files
authored
Add script to generate mock data for FriendlyEats quickstart (#728)
* Start script * Script to add data to app on init * Added ESLINTRC * Removed double quotes * Added 1 line in .eslintrc.json * Started changes * Moved script to outside of src/ and adjusted package.json accordingly * Update README.md * Remove unneccesary file * Header * Addressed Comments * Removed unneccesary file
1 parent 3703d46 commit 54465c7

File tree

9 files changed

+328
-8
lines changed

9 files changed

+328
-8
lines changed

firestore/angular-rewrite/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ Follow these steps to have a working version of the quickstart running with the
103103
ng serve
104104
```
105105
106+
11. (Optional) Populate production Firestore with mock data
107+
108+
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:
109+
110+
```bash
111+
npm run populate-production
112+
```
113+
114+
> **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.
115+
106116
## Support
107117
108118
- [Firebase Support](https://firebase.google.com/support/)

firestore/angular-rewrite/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
"scripts": {
55
"ng": "ng",
66
"start": "(cd functions && npm run build) && firebase --project demo-friendly-eats emulators:exec --import ./imported-firebase-data 'ng serve'",
7+
"populate-emulators": "cp src/environments/environment.ts scripts/environment.js && node scripts/PopulateFirestore.js",
8+
"populate-production": "cp src/environments/environment.prod.ts scripts/environment.js && node scripts/PopulateFirestore.js",
79
"build": "ng build",
810
"watch": "ng build --watch --configuration development",
911
"test": "ng test",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"parserOptions": {
3+
"sourceType": "module"
4+
}
5+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* Copyright 2023 Google LLC
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+
/** If connecting to a live Firebase project (one that you set up in the
19+
* Firebase console) put your config vars into the `prod` field object here
20+
* and change the `initializeApp` value in `app.module.ts` to `environment.prod`.
21+
* Otherwise, leave untouched to enable connection to demo project and emulators.
22+
*/
23+
24+
export const data = {
25+
words: [
26+
'Bar',
27+
'Fire',
28+
'Grill',
29+
'Drive Thru',
30+
'Place',
31+
'Best',
32+
'Spot',
33+
'Prime',
34+
'Eatin\'',
35+
],
36+
cities: [
37+
'Albuquerque',
38+
'Arlington',
39+
'Atlanta',
40+
'Austin',
41+
'Baltimore',
42+
'Boston',
43+
'Charlotte',
44+
'Chicago',
45+
'Cleveland',
46+
'Colorado Springs',
47+
'Columbus',
48+
'Dallas',
49+
'Denver',
50+
'Detroit',
51+
'El Paso',
52+
'Fort Worth',
53+
'Fresno',
54+
'Houston',
55+
'Indianapolis',
56+
'Jacksonville',
57+
'Kansas City',
58+
'Las Vegas',
59+
'Long Island',
60+
'Los Angeles',
61+
'Louisville',
62+
'Memphis',
63+
'Mesa',
64+
'Miami',
65+
'Milwaukee',
66+
'Nashville',
67+
'New York',
68+
'Oakland',
69+
'Oklahoma',
70+
'Omaha',
71+
'Philadelphia',
72+
'Phoenix',
73+
'Portland',
74+
'Raleigh',
75+
'Sacramento',
76+
'San Antonio',
77+
'San Diego',
78+
'San Francisco',
79+
'San Jose',
80+
'Tucson',
81+
'Tulsa',
82+
'Virginia Beach',
83+
'Washington',
84+
],
85+
categories: [
86+
'Brunch',
87+
'Burgers',
88+
'Coffee',
89+
'Deli',
90+
'Dim Sum',
91+
'Indian',
92+
'Italian',
93+
'Mediterranean',
94+
'Mexican',
95+
'Pizza',
96+
'Ramen',
97+
'Sushi',
98+
],
99+
ratingsTexts: {
100+
1: 'Would never eat here again!',
101+
2: 'Not my cup of tea.',
102+
3: 'Exactly okay :/',
103+
4: 'Actually pretty good, would recommend!',
104+
5: 'This is my favorite place. Literally.',
105+
},
106+
};
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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();

firestore/angular-rewrite/scripts/package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "scripts",
3+
"version": "1.0.0",
4+
"description": "A script to send mock data to the prod firebase console",
5+
"main": "PopulateFirestore.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"author": "",
10+
"license": "Apache-2.0",
11+
"type": "module"
12+
}

firestore/angular-rewrite/src/app/app.module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { provideAuth, getAuth, connectAuthEmulator } from '@angular/fire/auth';
3030
import { provideFirestore, getFirestore } from '@angular/fire/firestore';
3131
import { provideFunctions, getFunctions } from '@angular/fire/functions';
3232
import { provideStorage, getStorage } from '@angular/fire/storage'
33-
import { environment } from 'src/environments/environment';
33+
import { projectConfig } from 'src/environments/environment';
3434
import { HomepageComponent } from './homepage/homepage.component';
3535
import { RestuarantPageComponent } from './restuarant-page/restuarant-page.component';
3636
import { MatIconModule } from '@angular/material/icon';
@@ -76,7 +76,7 @@ import { SignInModalComponent } from './sign-in-modal/sign-in-modal.component';
7676
MatInputModule,
7777
MatButtonModule,
7878
BrowserAnimationsModule,
79-
provideFirebaseApp(() => initializeApp(environment.local)),
79+
provideFirebaseApp(() => initializeApp(projectConfig)),
8080
FormsModule,
8181
provideAuth(() => {
8282
const auth = getAuth();

firestore/angular-rewrite/src/environments/environment.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
* and change the `initializeApp` value in `app.module.ts` to `environment.prod`.
2121
* Otherwise, leave untouched to enable connection to demo project and emulators.
2222
*/
23-
export const environment = {
24-
local: {
25-
projectId: 'demo-friendly-eats',
26-
apiKey: '[FIREBASE_API_KEY]'
27-
},
28-
prod: {}
23+
24+
export const projectConfig = {
25+
projectId: 'demo-friendly-eats',
26+
apiKey: 'API_KEY_UNUSED'
2927
}

0 commit comments

Comments
 (0)