Firebase Angular Web Frameworks Codelab

۱. آنچه خلق خواهید کرد

در این آزمایشگاه کد، شما یک وبلاگ مسافرتی با یک نقشه مشارکتی بلادرنگ با استفاده از جدیدترین کتابخانه Angular ما، AngularFire ، خواهید ساخت. برنامه وب نهایی شامل یک وبلاگ مسافرتی خواهد بود که در آن می‌توانید تصاویر مربوط به هر مکانی که به آن سفر کرده‌اید را آپلود کنید.

AngularFire برای ساخت برنامه وب، Emulator Suite برای آزمایش محلی، Authentication برای پیگیری داده‌های کاربر، Firestore و Storage برای ذخیره داده‌ها و رسانه‌ها، با پشتیبانی Cloud Functions و در نهایت، Firebase Hosting برای استقرار برنامه استفاده خواهد شد.

آنچه یاد خواهید گرفت

  • نحوه توسعه محصولات Firebase به صورت محلی با Emulator Suite
  • چگونه برنامه وب خود را با AngularFire بهبود بخشیم؟
  • چگونه داده‌های خود را در Firestore ذخیره کنیم؟
  • نحوه‌ی ذخیره‌ی دائمی رسانه‌ها در حافظه
  • نحوه استقرار برنامه خود در Firebase Hosting
  • نحوه استفاده از توابع ابری برای تعامل با پایگاه‌های داده و APIهای شما

آنچه نیاز دارید

  • Node.js نسخه ۱۰ یا بالاتر
  • یک حساب گوگل برای ایجاد و مدیریت پروژه فایربیس شما
  • نسخه 11.14.2 یا بالاتر از رابط خط فرمان فایربیس
  • یک مرورگر دلخواه مثل کروم
  • آشنایی اولیه با Angular و Javascript

۲. کد نمونه را دریافت کنید

مخزن گیت‌هاب codelab را از خط فرمان کلون کنید:

git clone https://github.com/firebase/codelab-friendlychat-web

از طرف دیگر، اگر git را نصب ندارید، می‌توانید مخزن را به صورت یک فایل ZIP دانلود کنید .

مخزن گیت‌هاب شامل پروژه‌های نمونه برای پلتفرم‌های مختلف است.

این codelab فقط از مخزن webframework استفاده می‌کند:

  • 📁 وب‌فریم‌ورک : کد اولیه‌ای که در طول این آزمایشگاه کدنویسی بر اساس آن کار خواهید کرد.

نصب وابستگی‌ها

پس از کلون کردن، قبل از ساخت برنامه وب، وابستگی‌ها را در پوشه ریشه و functions نصب کنید.

cd webframework && npm install
cd functions && npm install

نصب رابط خط فرمان فایربیس

با استفاده از این دستور در ترمینال، Firebase CLI را نصب کنید:

npm install -g firebase-tools

با استفاده از دستور زیر، دوباره بررسی کنید که نسخه Firebase CLI شما بیشتر از ۱۱.۱۴.۲ باشد:

firebase  --version

اگر نسخه شما پایین‌تر از ۱۱.۱۴.۲ است، لطفاً با استفاده از دستور زیر به‌روزرسانی کنید:

npm update firebase-tools

۳. ایجاد و راه‌اندازی یک پروژه Firebase

ایجاد یک پروژه فایربیس

  1. با استفاده از حساب گوگل خود وارد کنسول فایربیس شوید.
  2. برای ایجاد یک پروژه جدید، روی دکمه کلیک کنید و سپس نام پروژه را وارد کنید (برای مثال، FriendlyChat ).
  3. روی ادامه کلیک کنید.
  4. در صورت درخواست، شرایط Firebase را مرور و قبول کنید و سپس روی ادامه کلیک کنید.
  5. (اختیاری) دستیار هوش مصنوعی را در کنسول Firebase (با نام "Gemini در Firebase") فعال کنید.
  6. برای این codelab، به گوگل آنالیتیکس نیاز ندارید ، بنابراین گزینه گوگل آنالیتیکس را غیرفعال کنید .
  7. روی ایجاد پروژه کلیک کنید، منتظر بمانید تا پروژه شما آماده شود و سپس روی ادامه کلیک کنید.

یک برنامه وب Firebase به پروژه اضافه کنید

  1. برای ایجاد یک برنامه وب جدید Firebase، روی آیکون وب کلیک کنید.
  2. در مرحله بعد، یک شیء پیکربندی (configuration object) مشاهده خواهید کرد. محتویات این شیء را در فایل environments/environment.ts کپی کنید.

راه اندازی محصولات فایربیس

برنامه‌ای که قرار است بسازیم از محصولات Firebase که برای برنامه‌های وب در دسترس هستند استفاده می‌کند:

  • احراز هویت فایربیس برای اینکه به راحتی به کاربران خود اجازه دهید وارد برنامه شما شوند.
  • Cloud Firestore برای ذخیره داده‌های ساختاریافته روی ابر و دریافت اعلان فوری هنگام تغییر داده‌ها.
  • فضای ذخیره‌سازی ابری برای فایربیس جهت ذخیره فایل‌ها در فضای ابری.
  • میزبانی فایربیس برای میزبانی و ارائه خدمات به دارایی‌های شما.
  • توابعی برای تعامل با APIهای داخلی و خارجی.

برخی از این محصولات به تنظیمات خاصی نیاز دارند یا باید با استفاده از کنسول Firebase فعال شوند.

فعال کردن ورود به سیستم گوگل برای احراز هویت فایربیس

برای اینکه کاربران بتوانند با حساب‌های گوگل خود وارد برنامه وب شوند، از متد ورود به سیستم گوگل استفاده خواهیم کرد.

برای فعال کردن ورود به سیستم گوگل :

  1. در کنسول Firebase، بخش Build را در پنل سمت چپ پیدا کنید.
  2. روی تأیید هویت کلیک کنید، سپس روی برگه روش ورود کلیک کنید (یا برای رفتن مستقیم به آنجا اینجا کلیک کنید ).
  3. ارائه‌دهنده ورود به سیستم گوگل را فعال کنید، سپس روی ذخیره کلیک کنید.
  4. نام عمومی برنامه خود را <your-project-name> قرار دهید و از منوی کشویی، یک ایمیل پشتیبانی پروژه انتخاب کنید.

فعال کردن کلود فایر استور

  1. در بخش Build کنسول Firebase، روی Firestore Database کلیک کنید.
  2. روی ایجاد پایگاه داده در پنل Cloud Firestore کلیک کنید.
  3. مکانی را که داده‌های Cloud Firestore شما ذخیره می‌شود، تنظیم کنید. می‌توانید این را به صورت پیش‌فرض رها کنید یا منطقه‌ای نزدیک به خود را انتخاب کنید.

فعال کردن فضای ذخیره‌سازی ابری

این برنامه وب از فضای ذخیره‌سازی ابری برای فایربیس جهت ذخیره، آپلود و اشتراک‌گذاری تصاویر استفاده می‌کند.

  1. در بخش Build کنسول Firebase، روی Storage کلیک کنید.
  2. اگر دکمه‌ی «شروع به کار» وجود ندارد، به این معنی است که فضای ذخیره‌سازی ابری از قبل فعال است.

فعال شده است و نیازی به دنبال کردن مراحل زیر نیست.

  1. روی شروع کار کلیک کنید.
  2. سلب مسئولیت مربوط به قوانین امنیتی پروژه Firebase خود را بخوانید، سپس روی Next کلیک کنید.
  3. محل ذخیره‌سازی ابری از قبل با همان منطقه‌ای که برای پایگاه داده Cloud Firestore خود انتخاب کرده‌اید، انتخاب شده است. برای تکمیل تنظیمات، روی «انجام شد» کلیک کنید.

با قوانین امنیتی پیش‌فرض، هر کاربر احراز هویت شده‌ای می‌تواند هر چیزی را در فضای ذخیره‌سازی ابری بنویسد. ما بعداً در این آزمایشگاه کد، فضای ذخیره‌سازی خود را ایمن‌تر خواهیم کرد.

۴. به پروژه Firebase خود متصل شوید

رابط خط فرمان (CLI) فایربیس به شما امکان می‌دهد از Firebase Hosting برای ارائه برنامه وب خود به صورت محلی و همچنین استقرار برنامه وب خود در پروژه فایربیس خود استفاده کنید.

مطمئن شوید که خط فرمان شما به دایرکتوری محلی webframework برنامه‌تان دسترسی دارد.

کد برنامه وب را به پروژه Firebase خود متصل کنید. ابتدا، در خط فرمان به Firebase CLI وارد شوید:

firebase login

سپس دستور زیر را برای ایجاد یک نام مستعار پروژه اجرا کنید. به جای $YOUR_PROJECT_ID ، شناسه پروژه Firebase خود را قرار دهید.

firebase  use  $YOUR_PROJECT_ID

اضافه کردن انگولار فایر

برای افزودن AngularFire به برنامه، دستور زیر را اجرا کنید:

ng add @angular/fire

سپس، دستورالعمل‌های خط فرمان را دنبال کنید و ویژگی‌هایی را که در پروژه Firebase شما وجود دارد، انتخاب کنید.

مقداردهی اولیه فایربیس

برای مقداردهی اولیه پروژه Firebase، دستور زیر را اجرا کنید:

firebase init

سپس، با دنبال کردن دستورات خط فرمان، ویژگی‌ها و شبیه‌سازهایی را که در پروژه Firebase شما استفاده شده‌اند، انتخاب کنید.

شبیه‌سازها را شروع کنید

از دایرکتوری webframework ، دستور زیر را برای شروع شبیه‌سازها اجرا کنید:

firebase  emulators:start

در نهایت باید چیزی شبیه به این را ببینید:

$  firebase  emulators:start

i  emulators:  Starting  emulators:  auth,  functions,  firestore,  hosting,  functions

i  firestore:  Firestore  Emulator  logging  to  firestore-debug.log

i  hosting:  Serving  hosting  files  from:  public

  hosting:  Local  server:  http://localhost:5000

i  ui:  Emulator  UI  logging  to  ui-debug.log

i  functions:  Watching  "/functions"  for  Cloud  Functions...

  functions[updateMap]:  firestore  function  initialized.

  

┌─────────────────────────────────────────────────────────────┐

    All  emulators  ready!  It  is  now  safe  to  connect  your  app.  

  i  View  Emulator  UI  at  http://localhost:4000  

└─────────────────────────────────────────────────────────────┘

  

┌────────────────┬────────────────┬─────────────────────────────────┐

  Emulator    Host:Port    View  in  Emulator  UI  

├────────────────┼────────────────┼─────────────────────────────────┤

  Authentication    localhost:9099    http://localhost:4000/auth  

├────────────────┼────────────────┼─────────────────────────────────┤

  Functions    localhost:5001    http://localhost:4000/functions  

├────────────────┼────────────────┼─────────────────────────────────┤

  Firestore    localhost:8080    http://localhost:4000/firestore  

├────────────────┼────────────────┼─────────────────────────────────┤

  Hosting    localhost:5000    n/a  

└────────────────┴────────────────┴─────────────────────────────────┘

Emulator  Hub  running  at  localhost:4400

Other  reserved  ports:  4500

  

Issues?  Report  them  at  https://github.com/firebase/firebase-tools/issues  and  attach  the  *-debug.log  files.

به محض اینکه پیام ✔All emulators ready! را مشاهده کردید، شبیه‌سازها آماده استفاده هستند.

شما باید رابط کاربری برنامه سفر خود را ببینید، که (هنوز!) کار نمی‌کند:

حالا بیایید شروع به ساختن کنیم!

۵. برنامه وب را به شبیه‌سازها وصل کنید

بر اساس جدول موجود در گزارش‌های شبیه‌ساز، شبیه‌ساز Cloud Firestore روی پورت ۸۰۸۰ و شبیه‌ساز Authentication روی پورت ۹۰۹۹ در حال گوش دادن هستند.

رابط کاربری شبیه‌ساز را باز کنید

در مرورگر وب خود، به آدرس http://127.0.0.1:4000/ بروید. باید رابط کاربری Emulator Suite را ببینید.

مسیردهی برنامه برای استفاده از شبیه‌سازها

در src/app/app.module.ts ، کد زیر را به لیست ایمپورت‌های AppModule اضافه کنید:

@NgModule({
	declarations: [...],
	imports: [
		provideFirebaseApp(() =>  initializeApp(environment.firebase)),

		provideAuth(() => {
			const  auth = getAuth();
			if (location.hostname === 'localhost') {
				connectAuthEmulator(auth, 'http://127.0.0.1:9099', { disableWarnings:  true });
			}
			return  auth;
		}),

		provideFirestore(() => {
			const  firestore = getFirestore();
			if (location.hostname === 'localhost') {
				connectFirestoreEmulator(firestore, '127.0.0.1', 8080);
			}
			return  firestore;
		}),

		provideFunctions(() => {
			const  functions = getFunctions();
			if (location.hostname === 'localhost') {
				connectFunctionsEmulator(functions, '127.0.0.1', 5001);
			}
			return  functions;
		}),

		provideStorage(() => {
			const  storage = getStorage();
			if (location.hostname === 'localhost') {
				connectStorageEmulator(storage, '127.0.0.1', 5001);
			}
			return  storage;
		}),
		...
	]

اکنون برنامه برای استفاده از شبیه‌سازهای محلی پیکربندی شده است و امکان آزمایش و توسعه به صورت محلی را فراهم می‌کند.

۶. افزودن احراز هویت

اکنون که شبیه‌سازها برای برنامه تنظیم شده‌اند، می‌توانیم ویژگی‌های احراز هویت را اضافه کنیم تا اطمینان حاصل شود که هر کاربر قبل از ارسال پیام، وارد سیستم شده است.

برای انجام این کار، می‌توانیم توابع signin مستقیماً از AngularFire وارد کنیم و وضعیت احراز هویت کاربر را با تابع authState پیگیری کنیم. توابع صفحه ورود را طوری تغییر دهید که صفحه هنگام بارگذاری، وضعیت احراز هویت کاربر را بررسی کند.

تزریق احراز هویت AngularFire

در src/app/pages/login-page/login-page.component.ts ، Auth از @angular/fire/auth وارد کنید و آن را به LoginPageComponent تزریق کنید. ارائه دهندگان احراز هویت، مانند Google، و توابعی مانند signin و signout نیز می‌توان مستقیماً از همان پکیج وارد کرد و در برنامه استفاده کرد.

import { Auth, GoogleAuthProvider, signInWithPopup, signOut, user } from  '@angular/fire/auth';

export  class  LoginPageComponent  implements  OnInit {
	private  auth: Auth = inject(Auth);
	private  provider = new  GoogleAuthProvider();
	user$ = user(this.auth);
	constructor() {}  

	ngOnInit(): void {} 

	login() {
		signInWithPopup(this.auth, this.provider).then((result) => {
			const  credential = GoogleAuthProvider.credentialFromResult(result);
			return  credential;
		})
	}

	logout() {
		signOut(this.auth).then(() => {
			console.log('signed out');}).catch((error) => {
				console.log('sign out error: ' + error);
		})
	}
}

حالا صفحه ورود به سیستم فعال است! سعی کنید وارد سیستم شوید و نتایج را در شبیه‌ساز احراز هویت بررسی کنید.

۷. پیکربندی فایراستور

در این مرحله، قابلیت ارسال و به‌روزرسانی پست‌های وبلاگ سفر ذخیره‌شده در Firestore را اضافه خواهید کرد.

مشابه احراز هویت، توابع Firestore از AngularFire به صورت از پیش بسته‌بندی شده ارائه می‌شوند. هر سند متعلق به یک مجموعه است و هر سند می‌تواند مجموعه‌های تو در تو نیز داشته باشد. دانستن path سند در Firestore برای ایجاد و به‌روزرسانی یک پست وبلاگ مسافرتی لازم است.

پیاده‌سازی خدمات مسافرتی

از آنجایی که صفحات مختلف زیادی نیاز به خواندن و به‌روزرسانی اسناد Firestore در برنامه وب دارند، می‌توانیم توابع را در src/app/services/travel.service.ts پیاده‌سازی کنیم تا از تزریق مکرر توابع AngularFire یکسان در هر صفحه خودداری کنیم.

با تزریق Auth ، مشابه مرحله قبل، و همچنین Firestore به سرویس خود شروع کنید. تعریف یک شیء user$ قابل مشاهده که به وضعیت احراز هویت فعلی گوش می‌دهد نیز مفید است.

import { doc, docData, DocumentReference, Firestore, getDoc, setDoc, updateDoc, collection, addDoc, deleteDoc, collectionData, Timestamp } from  "@angular/fire/firestore";

export  class  TravelService {
	firestore: Firestore = inject(Firestore);
	auth: Auth = inject(Auth);
	user$ = authState(this.auth).pipe(filter(user  =>  user !== null), map(user  =>  user!));
	router: Router = inject(Router);

اضافه شدن پست مسافرتی

پست‌های مسافرتی به عنوان اسنادی که در Firestore ذخیره می‌شوند، وجود خواهند داشت و از آنجایی که اسناد باید در مجموعه‌ها وجود داشته باشند، مجموعه‌ای که شامل تمام پست‌های مسافرتی است travels نام خواهد گرفت. بنابراین، مسیر هر پست مسافرتی travels/ خواهد بود. travels/

با استفاده از تابع addDoc از AngularFire، می‌توان یک شیء را در یک مجموعه وارد کرد:

async  addEmptyTravel(userId: String) {
	...
	addDoc(collection(this.firestore, 'travels'), travelData).then((travelRef) => {
		collection(this.firestore, `travels/${travelRef.id}/stops`);
		setDoc(travelRef, {... travelData, id:  travelRef.id})
		this.router.navigate(['edit', `${travelRef.id}`]);
		return  travelRef;

	})
}

به‌روزرسانی و حذف داده‌ها

با داشتن شناسه کاربری (uid) هر پست مسافرتی، می‌توان مسیر سند ذخیره شده در Firestore را استنباط کرد که سپس می‌توان آن را با استفاده از توابع updateFoc و deleteDoc در AngularFire خواند، به‌روزرسانی کرد یا حذف نمود:

async  updateData(path: string, data: Partial<Travel | Stop>) {
	await  updateDoc(doc(this.firestore, path), data)
}

async  deleteData(path: string) {
	const  ref = doc(this.firestore, path);
	await  deleteDoc(ref)
}

خواندن داده‌ها به عنوان یک مشاهده‌پذیر

از آنجایی که می‌توان ایستگاه‌های مسافرتی و توقف‌های بین راه را پس از ایجاد تغییر داد، مفیدتر خواهد بود که اشیاء سند را به عنوان observable دریافت کنیم تا در هر تغییری که ایجاد می‌شود، مشترک شویم. این قابلیت توسط توابع docData و collectionData از @angular/fire/firestore ارائه می‌شود.

getDocData(path: string) {
	return  docData(doc(this.firestore, path), {idField:  'id'}) as  Observable<Travel | Stop>
}

  
getCollectionData(path: string) {
	return  collectionData(collection(this.firestore, path), {idField:  'id'}) as  Observable<Travel[] | Stop[]>
}

اضافه کردن ایستگاه به یک پست مسافرتی

حالا که عملیات پست مسافرتی راه‌اندازی شده است، وقت آن رسیده که ایستگاه‌ها را در نظر بگیریم، که تحت زیرمجموعه‌ای از یک پست مسافرتی مانند زیر وجود خواهند داشت: travels/ /stops/

این تقریباً مشابه ایجاد یک پست مسافرتی است، بنابراین خودتان را به چالش بکشید تا آن را به تنهایی پیاده‌سازی کنید، یا پیاده‌سازی زیر را بررسی کنید:

async  addStop(travelId: string) {
	...
	const  ref = await  addDoc(collection(this.firestore, `travels/${travelId}/stops`), stopData)
	setDoc(ref, {...stopData, id:  ref.id})
}

عالیه! توابع Firestore در سرویس Travel پیاده‌سازی شده‌اند، بنابراین اکنون می‌توانید آنها را در عمل مشاهده کنید.

استفاده از توابع Firestore در برنامه

به src/app/pages/my-travels/my-travels.component.ts بروید و TravelService برای استفاده از توابع آن تزریق کنید.

travelService = inject(TravelService);
travelsData$: Observable<Travel[]>;
stopsList$!: Observable<Stop[]>;
constructor() {
	this.travelsData$ = this.travelService.getCollectionData(`travels`) as  Observable<Travel[]>
}

TravelService در سازنده فراخوانی می‌شود تا آرایه‌ای از تمام سفرها را که قابل مشاهده است، دریافت کند.

در مواردی که فقط به سفرهای کاربر فعلی نیاز است، از تابع query استفاده کنید.

روش‌های دیگر برای تضمین امنیت شامل پیاده‌سازی قوانین امنیتی یا استفاده از توابع ابری با Firestore است که در مراحل اختیاری زیر بررسی شده‌اند.

سپس، به سادگی توابع پیاده‌سازی شده در TravelService را فراخوانی کنید.

async  createTravel(userId: String) {
	this.travelService.addEmptyTravel(userId);
}

deleteTravel(travelId: String) {
	this.travelService.deleteData(`travels/${travelId}`)
}

حالا صفحه «سفرهای من» باید فعال شده باشد! ببینید وقتی یک پست مسافرتی جدید ایجاد می‌کنید، در شبیه‌ساز Firestore چه اتفاقی می‌افتد.

سپس، این کار را برای توابع به‌روزرسانی در /src/app/pages/edit-travels/edit-travels.component.ts تکرار کنید:

travelService: TravelService = inject(TravelService)
travelId = this.activatedRoute.snapshot.paramMap.get('travelId');
travelData$: Observable<Travel>;
stopsData$: Observable<Stop[]>;

constructor() {
	this.travelData$ = this.travelService.getDocData(`travels/${this.travelId}`) as  Observable<Travel>
	this.stopsData$ = this.travelService.getCollectionData(`travels/${this.travelId}/stops`) as  Observable<Stop[]>
}

updateCurrentTravel(travel: Partial<Travel>) {
	this.travelService.updateData(`travels${this.travelId}`, travel)
}

  

updateCurrentStop(stop: Partial<Stop>) {
	stop.type = stop.type?.toString();
	this.travelService.updateData(`travels${this.travelId}/stops/${stop.id}`, stop)
}

  

addStop() {
	if (!this.travelId) return;
	this.travelService.addStop(this.travelId);
}

deleteStop(stopId: string) {
	if (!this.travelId || !stopId) {
		return;
	}
	this.travelService.deleteData(`travels${this.travelId}/stops/${stopId}`)
	this.stopsData$ = this.travelService.getCollectionData(`travels${this.travelId}/stops`) as  Observable<Stop[]>

}

۸. پیکربندی فضای ذخیره‌سازی

اکنون Storage را برای ذخیره تصاویر و انواع دیگر رسانه پیاده‌سازی خواهید کرد.

Cloud Firestore بهترین گزینه برای ذخیره داده‌های ساختاریافته مانند اشیاء JSON است. Cloud Storage برای ذخیره فایل‌ها یا blobs طراحی شده است. در این برنامه، از آن برای اشتراک‌گذاری تصاویر سفر کاربران استفاده خواهید کرد.

به همین ترتیب در مورد Firestore، ذخیره و به‌روزرسانی فایل‌ها با Storage به یک شناسه منحصر به فرد برای هر فایل نیاز دارد.

بیایید توابع را در TraveService پیاده‌سازی کنیم:

آپلود فایل

به src/app/services/travel.service.ts بروید و Storage را از AngularFire تزریق کنید:

export  class  TravelService {
firestore: Firestore = inject(Firestore);
auth: Auth = inject(Auth);
storage: Storage = inject(Storage);

و تابع آپلود را پیاده‌سازی کنید:

async  uploadToStorage(path: string, input: HTMLInputElement, contentType: any) {
	if (!input.files) return  null
	const  files: FileList = input.files;
		for (let  i = 0; i  <  files.length; i++) {
			const  file = files.item(i);
			if (file) {
				const  imagePath = `${path}/${file.name}`
				const  storageRef = ref(this.storage, imagePath);
				await  uploadBytesResumable(storageRef, file, contentType);
				return  await  getDownloadURL(storageRef);
			}
		}
	return  null;
}

تفاوت اصلی بین دسترسی به اسناد از Firestore و فایل‌ها از Cloud Storage این است که اگرچه هر دو از مسیرهای ساختار یافته پوشه‌ای پیروی می‌کنند، ترکیب آدرس پایه و مسیر از طریق getDownloadURL به دست می‌آید که سپس می‌تواند ذخیره شود و در ... استفاده شود. فایل.

استفاده از تابع در برنامه

به src/app/components/edit-stop/edit-stop.component.ts بروید و تابع آپلود را با استفاده از دستور زیر فراخوانی کنید:

	async  uploadFile(file: HTMLInputElement, stop: Partial<Stop>) {
	const  path = `/travels/${this.travelId}/stops/${stop.id}`
	const  url = await  this.travelService.uploadToStorage(path, file, {contentType:  'image/png'});
	stop.image = url ? url : '';
	this.travelService.updateData(path, stop);
}

وقتی تصویر آپلود می‌شود، خود فایل رسانه‌ای در فضای ذخیره‌سازی آپلود می‌شود و آدرس اینترنتی (url) مربوطه در سند موجود در Firestore ذخیره می‌شود.

۹. استقرار برنامه

حالا آماده‌ایم تا برنامه را مستقر کنیم!

پیکربندی‌های firebase را از src/environments/environment.ts به src/environments/environment.prod.ts کپی کنید و اجرا کنید:

firebase deploy

شما باید چیزی شبیه به این را ببینید:

 Browser application bundle generation complete.
 Copying assets complete.
 Index html generation complete.

=== Deploying to 'friendly-travels-b6a4b'...

i  deploying storage, firestore, hosting
i  firebase.storage: checking storage.rules for compilation errors...
  firebase.storage: rules file storage.rules compiled successfully
i  firestore: reading indexes from firestore.indexes.json...
i  cloud.firestore: checking firestore.rules for compilation errors...
  cloud.firestore: rules file firestore.rules compiled successfully
i  storage: latest version of storage.rules already up to date, skipping upload...
i  firestore: deploying indexes...
i  firestore: latest version of firestore.rules already up to date, skipping upload...
  firestore: deployed indexes in firestore.indexes.json successfully for (default) database
i  hosting[friendly-travels-b6a4b]: beginning deploy...
i  hosting[friendly-travels-b6a4b]: found 6 files in .firebase/friendly-travels-b6a4b/hosting
  hosting[friendly-travels-b6a4b]: file upload complete
  storage: released rules storage.rules to firebase.storage
  firestore: released rules firestore.rules to cloud.firestore
i  hosting[friendly-travels-b6a4b]: finalizing version...
  hosting[friendly-travels-b6a4b]: version finalized
i  hosting[friendly-travels-b6a4b]: releasing new version...
  hosting[friendly-travels-b6a4b]: release complete

  Deploy complete!

Project Console: https://console.firebase.google.com/project/friendly-travels-b6a4b/overview
Hosting URL: https://friendly-travels-b6a4b.web.app

۱۰. تبریک می‌گویم!

اکنون برنامه شما باید کامل شده و در Firebase Hosting مستقر شده باشد! اکنون تمام داده‌ها و تجزیه و تحلیل‌ها در کنسول Firebase شما قابل دسترسی خواهند بود.

برای ویژگی‌های بیشتر در مورد AngularFire، توابع، قوانین امنیتی، فراموش نکنید که مراحل اختیاری زیر و همچنین سایر آزمایشگاه‌های کد Firebase را بررسی کنید!

۱۱. اختیاری: محافظ‌های احراز هویت AngularFire

در کنار احراز هویت فایربیس، AngularFire همچنین محافظ‌های مبتنی بر احراز هویت را در مسیرها ارائه می‌دهد، به طوری که کاربرانی که دسترسی کافی ندارند می‌توانند هدایت شوند. این امر به محافظت از برنامه در برابر دسترسی کاربران به داده‌های محافظت‌شده کمک می‌کند.

در src/app/app-routing.module.ts ، فایل را وارد کنید

import {AuthGuard, redirectLoggedInTo, redirectUnauthorizedTo} from  '@angular/fire/auth-guard'

سپس می‌توانید توابعی را تعریف کنید که مشخص کنند کاربران در چه زمانی و به کجا در صفحات خاص هدایت شوند:

const  redirectUnauthorizedToLogin = () =>  redirectUnauthorizedTo(['signin']);
const  redirectLoggedInToTravels = () =>  redirectLoggedInTo(['my-travels']);

سپس آنها را به مسیرهای خود اضافه کنید:

const  routes: Routes = [
	{path:  '', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'signin', component:  LoginPageComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectLoggedInToTravels}},
	{path:  'my-travels', component:  MyTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
	{path:  'edit/:travelId', component:  EditTravelsComponent, canActivate: [AuthGuard], data: {authGuardPipe:  redirectUnauthorizedToLogin}},
];

۱۲. اختیاری: قوانین امنیتی

هم Firestore و هم Cloud Storage از قوانین امنیتی (به ترتیب firestore.rules و security.rules ) برای اجرای امنیت و اعتبارسنجی داده‌ها استفاده می‌کنند.

در حال حاضر، داده‌های Firestore و Storage دسترسی آزاد برای خواندن و نوشتن دارند، اما شما نمی‌خواهید که افراد پست‌های دیگران را تغییر دهند! می‌توانید از قوانین امنیتی برای محدود کردن دسترسی به مجموعه‌ها و اسناد خود استفاده کنید.

قوانین فایراستور

برای اینکه فقط به کاربران احراز هویت شده اجازه مشاهده پست‌های مسافرتی داده شود، به فایل firestore.rules بروید و موارد زیر را اضافه کنید:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/travels  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
	}
}

از قوانین امنیتی همچنین می‌توان برای اعتبارسنجی داده‌ها استفاده کرد:

rules_version  =  '2';
service  cloud.firestore  {
	match  /databases/{database}/posts  {
		allow  read:  if  request.auth.uid  !=  null;
		allow  write:
		if  request.auth.uid  ==  request.resource.data.userId;
		&&  "author"  in  request.resource.data
		&&  "text"  in  request.resource.data
		&&  "timestamp"  in  request.resource.data;
	}
}

قوانین ذخیره سازی

به طور مشابه، می‌توانیم از قوانین امنیتی برای اعمال دسترسی به پایگاه‌های داده ذخیره‌سازی در storage.rules استفاده کنیم. توجه داشته باشید که می‌توانیم از توابع نیز برای بررسی‌های پیچیده‌تر استفاده کنیم:

rules_version  =  '2';

function  isImageBelowMaxSize(maxSizeMB)  {
	return  request.resource.size  <  maxSizeMB  *  1024  *  1024
		&&  request.resource.contentType.matches('image/.*');
}

 service  firebase.storage  {
	match  /b/{bucket}/o  {
		match  /{userId}/{postId}/{filename}  {
			allow  write:  if  request.auth  !=  null
			&&  request.auth.uid  ==  userId  &&  isImageBelowMaxSize(5);
			allow  read;
		}
	}
}