如何订阅一个可观察对象但获取许多Firebase可观察对象

时间:2019-03-02 07:31:23

标签: angular firebase observable

由于我已经挣扎了一段时间,所以无法弄清楚以下情况:

我有一个组件“ test.ts”和一个服务“ authService”。 在组件的ngOnInit方法中,我订阅了服务的authState。效果很好。

我要实现的目标如下: 如果用户已通过身份验证,我想从Firebase数据库加载配置文件数据。然后,此Firebase数据将作为配置文件对象分配给服务的私有成员变量。

userprofile: Userprofile = null; // This is a class member
let fbUserProfile: Observable<any> = this.afDatabase.object(`${this.PATH_USER_PROFILE}/${userID}`).valueChanges();
this.userprofile = this.currentUserProfile( fbUserProfile );

authService中的私有方法currentUserProfile将创建一个新的Userprofile对象,并从给定的Observable中分配值。

并行,我想获取该用户的分配凭据列表,并将其存储到服务的私有成员变量中。

usercredentials: Map<string, Credential> = null; // This is a class member
let fbUsercredentials: Observable<any> = this.afDatabase.list<Credential>(`${this.PATH_USER_CREDENTIALS}/${userID}`).snapshotChanges().pipe(
            map(changes => changes.map(c => ({ key: c.payload.key, ...c.payload.val() }) ))
          );
    this.usercredentials = this.currentAssignedUserCredentials( fbUsercredentials )

注意:用户没有任何凭证是有效的! 在currentAssignedUserCredentials函数中,我订阅了给定的observable并构建了地图。

这是我目前无法确定的事情: 我想在服务中订阅authState,因此我希望两个成员变量都被填充。 像这样:

this.authService.authstate$.subscribe( () => {
 this.authServive.getUserprofile(); // should return a Userprofile object that is filled with the firebase information
 this.authService.getUsercredentials(); // should return the map with assigned user credentials (or null)
}

这是我的auth.service.ts文件的样子:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

import {AngularFireAuth} from '@angular/fire/auth';
import {AngularFireDatabase, AngularFireObject, AngularFireList} from '@angular/fire/database';

import { Credential } from '../items/credentials.model';
import { Userprofile } from '../items/userprofile.model';
import { Observable, of} from 'rxjs';
import { switchMap, filter, map } from 'rxjs/operators';

import { Constants } from '../core/constants.model';

@Injectable({
  providedIn: 'root'
})

export class AuthService {
  public authstate$: Observable<any | null>;

  private readonly PATH_USER_PROFILE = 'users/userprofiles';
  private readonly PATH_CREDENTIALS = 'credentials';
  private readonly PATH_USER_CREDENTIALS = 'credentials/users';

  private firebaseUser: firebase.User = null; // the firebase informations if the user is logged in
  private userprofile: Userprofile = null;
  private credentialno = 'Demo';
  private usercredential: Credential = this.updateUserCredential(null);

  private assignedUserCredentials$: Observable<any | null>;
  private credentialMap: Map<string, Credential>;
  

  constructor(private afAuth: AngularFireAuth,
              private afDatabase: AngularFireDatabase,
              private router: Router) {

    this.authstate$ = this.afAuth.authState.pipe(
      filter(fbUser => fbUser !== null),
      switchMap( (fbUser: firebase.User) => {
        if (fbUser) {
          // The user is logged in successfully.
          this.firebaseUser = fbUser;

          // return the userprofile observable depending from his user id
          let fbUserprofileObject = this.getUserprofileObjectById(this.firebaseUser.uid);
          return fbUserprofileObject.valueChanges();
          
        } else {
          // The user isn't logged in
          this.firebaseUser = null;
          return of(null);
        }
      }),
      switchMap( (fbUserprofile) => {
        if (fbUserprofile) {
          // create the userprofile
          this.userprofile = this.currentUserProfile( fbUserprofile );
          return of( this.userprofile.getUid() );
          
        } else {
          return of(null);
        }
      } ),
      switchMap( (userID: string) => {
        if (userID) {
          let fbAssignedUserCredentials: AngularFireList<any> = this.getUserCredentialListById(userID);
          this.assignedUserCredentials$ = fbAssignedUserCredentials.snapshotChanges().pipe(
            map(changes => changes.map(c => ({ key: c.payload.key, ...c.payload.val() }) ))
          );

          this.credentialMap = this.currentAssignedUserCredentials(this.assignedUserCredentials$);
          
          return of(null);
        } else {
          // FV: Add a demo credential to the usercredentiallist
          //this.credentialMap.set('Demo', new Credential('Demo', 1, '', 0));
          return of(null);
        }
      })

    );

  }

  // #######################
  // ## GETTER AND SETTER ##
  // #######################
  get authenticated(): boolean {
    // Returns true if user is logged in
    return this.firebaseUser !== null;
  }

  get currentUserId(): string {
    // Returns current user UID or empty string
    return this.authenticated ? this.firebaseUser.uid : '';
  }

  get currentUserEmail(): string {
    // Returns current user email address or empty string
    return this.firebaseUser ? this.firebaseUser.email : '';
  }

  get currentUserEmailVerified(): boolean {
    // Retruns true if the email address is verfified or false
    return this.authenticated ? this.firebaseUser.emailVerified : false;
  }

  get currentUserAnonymous(): boolean {
    // Returns true if this user is an anonymous user
    return this.authenticated ? this.firebaseUser.isAnonymous : false;
  }

  get currentUserDisplayName(): string {
    // Returns current user display name or Guest
    if (!this.firebaseUser) { return 'Guest'; }
    if (this.currentUserAnonymous) {
      return 'Anonymous';
    } else {
      return this.firebaseUser['displayName'] || 'User without a Name';
    }
  }

  get FirebaseLoginMethod(): number {
    // Returns the Firebase login method as number
    let retrunValue: number = Constants.LOGIN_OPTION_NOT_LOGGED_IN;
    if (this.authenticated) {
      switch (this.firebaseUser.providerId) {
        case 'facebook.com': {
          // For linked facebook account
          retrunValue = Constants.LOGIN_OPTION_FACEBOOK;
          break;
        }
        case 'google.com': {
          // For linked Google account
          retrunValue = Constants.LOGIN_OPTION_GOOGLE;
          break;
        }
        case 'password': {
          // For Email/Password account
          retrunValue = Constants.LOGIN_OPTION_PASSWORD;
          break;
        }
        default: {
          retrunValue = Constants.LOGIN_OPTION_UNKNOWN;
        }
      }
    }
    return retrunValue;
  }

  // ####################
  // ## PUBLIC METHODS ##
  // ####################
  public getUserProfile(): Userprofile {
    console.log('getUserProfile - start');
    return this.currentUserProfile(null);
  }

  public getAssignedUserCredentials(): Map<string, Credential> {
    return this.currentAssignedUserCredentials(null);
  }

  public getUserCredential(): Credential {
    return this.usercredential;
  }

  public setUserCredential(newCredential: Credential): void {
    this.usercredential = newCredential;
  }

  public setUserProfile(newProfile: Userprofile): void {
    this.userprofile = newProfile;
  }

  public signOut() {
    this.afAuth.auth.signOut().then(() => {
      this.firebaseUser = null;
      this.authstate$ = null;
      this.userprofile = null;
      this.credentialno = 'Demo';
      this.usercredential = this.updateUserCredential(null);
      this.router.navigate(['home']);
    });
  }

  public updateFBUserProfile() {
    const fbUserprofileObject = this.getUserprofileObjectById(this.userprofile.getUid());
    return fbUserprofileObject.update({
      fullname: this.userprofile.getFullname() as String,
      email: this.userprofile.getEmail() as String,
      phone: this.userprofile.getPhone() as String,
      postaladdress: this.userprofile.getAddress() as String,
      serialnumber: this.usercredential.getSerialnumber() as String
    });
  }

  public updateFBUserCredential() {
    const fbUsercrednetialObject = this.getUserCredentialObjectById(this.usercredential.getSerialnumber());
    return fbUsercrednetialObject.update({
      accesslevel: this.usercredential.getAccesslevel() as Number,
      assigneduserprofile: this.usercredential.getAssignedUserprofile() as String,
      validuntil: this.usercredential.getValidUntil() as Number
    });
  }


  // ############################
  // ## PRIVATE HELPER METHODS ##
  // ############################
  private currentUserProfile(fbUserprofile: Observable<any>): Userprofile {
    console.log('currentUserProfile - start');
    let profile_new: Userprofile = null;
    let photourl = '';

    // if the userprofile is already build then return it
    if (this.userprofile) {
      console.log('9');
      return this.userprofile;
    }

    console.log('9.1');
    profile_new = new Userprofile('', '', false, '', '', '', '', 10);

    // if the user is authenticated then fill the new profile with that information
    if (this.authenticated) {
      profile_new.setUid(this.currentUserId);
      profile_new.setEmail(this.currentUserEmail);
      profile_new.setEmailVerified(this.currentUserEmailVerified);
      profile_new.setFullname(this.currentUserDisplayName);
      // photourl
      this.firebaseUser.providerData.forEach(profil => {
        photourl = profil.photoURL;
      });
      // photourl - the image url in firebase auth user must be corrected
      profile_new.setPhotoUrl(this.updatePhotoUrl(photourl));
      profile_new.setLoginMethod(this.FirebaseLoginMethod);
    }

    // if the fbUserprofile isn't null then get the data from there
    if (fbUserprofile) {
      // Fullname
      if (fbUserprofile.fullname.length > 0) { profile_new.setFullname(fbUserprofile.fullname); }
      // phone
      profile_new.setPhone(fbUserprofile.phone);
      // postal address
      profile_new.setAddress(fbUserprofile.postaladdress);
      // Get Credentials assigned to the user
      this.credentialno = fbUserprofile.serialnumber;
    }

    console.log('currentUserProfile - stop');
    // return the new profile
    return profile_new;
  }


  private updatePhotoUrl(photourl: string): string {
    let returnValue = photourl;
    // If the main profile Pic is an expiring facebook profile pic URL we'll update it automatically
    // to use the permanent graph API URL.
    if (returnValue && (returnValue.indexOf('lookaside.facebook.com') !== -1 || returnValue.indexOf('fbcdn.net') !== -1)) {
      // Fid the user's Facebook UID.
      const facebookUID = this.firebaseUser.providerData.find((providerData) => providerData.providerId === 'facebook.com').uid;
      returnValue = `https://graph.facebook.com/${facebookUID}/picture?type=small`;
      this.firebaseUser.updateProfile({displayName: this.firebaseUser.displayName, photoURL: returnValue}).then(() => {
        // console.log('User profile photourl updated.');
      });
    }
    return returnValue;
  }


  public updateUserCredential(fbCredential: any): Credential {
    let credential_new: Credential;

    if (fbCredential) {
      credential_new = new Credential(this.credentialno, fbCredential.accesslevel,
         fbCredential.assigneduserprofile, fbCredential.validuntil);
    } else {
      credential_new = new Credential('Demo', 1, '', 0);
    }
    return credential_new;
  }


  private getUserprofileObjectById(userID: string): AngularFireObject<any> {
    return this.afDatabase.object(`${this.PATH_USER_PROFILE}/${userID}`);
  }


  public getUserCredentialObjectById(credentialID: string): AngularFireObject<any> {
    return this.afDatabase.object(`${this.PATH_CREDENTIALS}/${credentialID}`);
  }


  public getUserCredentialListById(userID: string): AngularFireList<any> {
    return this.afDatabase.list<Credential>(`${this.PATH_USER_CREDENTIALS}/${userID}`);
  }


  private currentAssignedUserCredentials(assignedUserCredentials$: Observable<any | null>): Map<string, Credential> {
    let mocked_usercredentials: Map<string, Credential> = null;
    
    // if the assigned user credentials are already build then return it
    if (this.credentialMap) {
      return this.credentialMap;
    }

    mocked_usercredentials = new Map();

    if(assignedUserCredentials$) {

      assignedUserCredentials$.subscribe(credentials => {
        credentials.map(item => {
          mocked_usercredentials.set(item.key, new Credential(item.key, item.accesslevel, this.userprofile.getUid(), item.validuntil));
        });
        return mocked_usercredentials;
      });

    } else {
      return null;
    }

  }
}

感谢您的帮助! 问候弗兰克

0 个答案:

没有答案