I am using Angular with firebase. In my app users can create "projects" and invite another users to that "project" in other words one project can have multiple users. I have user
collection and project
collection in firestore.
User collection
users/userID/ -> { name: string }
in users
collection are documents which have id value and data (just name)
Project collection
project/projectID/ ->
{
projectName: String,
users: [
{
userID: (here id of user),
role: String
}
]
in project
collection are documents which have id value and data. Data are projectName and array of users. In this array of users i have ids of users that can access the project.
Scenario
User signIn to my app, now he is in simple intro page at route /hello
. Now user can see his projects, when he click at some project he will be routed to this path /project/:id
and here he can use other functions e.g. /project/:id/overview
. It's similar to firebase console https://console.firebase.google.com/u/0/project/myprojectid/authentication/users
:) I hope I just clarify what i am trying to achieve. If you are still confused let me know in comments.
What's the problem?
In my project this works good, but problem is when someone copy id of different project to url and hits enter. I want to prevent users to get to others users projects so if i enter this path /project/notMyProject/overview
in url, I should be redirected or something. Hmm thats easy, just create router guard I thought. So I started...
app-routing.module.ts
const routes: Routes = [
{ path: 'project/:pid', component: ProjectComponent,
children: [
{ path: '', component: OverviewComponent},
{ path: 'users', component: ProjectUsersComponent, },
],
canActivate: [ProjectGuard, AuthGuard]
},
{ path: '', component: PageComponent }
];
project.guard.ts
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../core/auth.service';
import { map } from 'rxjs/operators';
import {
AngularFirestore,
AngularFirestoreDocument
} from 'angularfire2/firestore';
@Injectable({
providedIn: 'root'
})
export class ProjectGuard implements CanActivate {
private itemDoc: AngularFirestoreDocument<any>;
item: Observable<any>;
constructor(
private auth: AuthService,
private afs: AngularFirestore,
) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | boolean {
this.itemDoc = this.afs.doc<any>.(`project/${next.paramMap.get('pid')}`);
this.item = this.itemDoc.valueChanges();
this.item.subscribe(response => {
console.log(response)
response.users.forEach( (element) => {
if(element.userID == this.auth.user.subscribe( data => { return data.uid })) {
return true;
}
})
})
}
}
and here I am. I quite new to rxjs and all that observable stuff. That code is asynchronous and I don't know how to make this work,I am getting error that I have to return Observable or boolean...
Question
Is my general approach to this specific problem correct? Is there some better options that I should consider? How other pages solve this problem e.g. firebase (try this Firebase). And if my solution is good can you help me with my project.guard?? Thank you very much
I tried to describe my problem as clear as possible. If you missing some informations, please let me know in comments and I will update my question. I searched many hours how to solve this but i could not find anything or I just use wrong search keywords. I hope this will help others too.