From 79653ace20fc6e883a4924a73e231c33599d464f Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Wed, 10 Apr 2024 15:05:26 -0400 Subject: [PATCH 1/7] wip: test on preview --- src/utils/firebase.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index f510031..02f5646 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -35,6 +35,7 @@ const app = initializeApp(firebaseConfig); const db = getFirestore(app); const auth = getAuth(); const provider = new GoogleAuthProvider(); +provider.addScope('https://www.googleapis.com/auth/cloud-identity.groups.readonly'); provider.setCustomParameters({ hd: 'brown.edu', @@ -43,7 +44,26 @@ const collectionName = 'publications'; export const handleLogin = async () => { try { - await signInWithPopup(auth, provider); + const result = await signInWithPopup(auth, provider); + + const credential = GoogleAuthProvider.credentialFromResult(result); + const token = credential.accessToken; + const { email } = result.user; + + console.log(token); + console.log(email); + + // const response = await fetch(`https://cloudidentity.googleapis.com/v1/groups:lookup?groupKey.id=ccv-gsdc@brown.edu`, { + const response = await fetch( + `https://cloudidentity.googleapis.com/v1/groups/0184mhaj2thv9r6/memberships`, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + console.log(response); } catch (error) { console.log(error); } From b39d0047e95851f5aeb6981313dd87758d193021 Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Mon, 15 Apr 2024 18:45:44 -0400 Subject: [PATCH 2/7] wip: test on preview again --- src/utils/firebase.ts | 56 +++++++++++++++++++++++++++++-------------- types/index.d.ts | 7 ++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 02f5646..5b526d7 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -4,6 +4,7 @@ import { initializeApp } from 'firebase/app'; import { getFirestore, doc, + getDoc, setDoc, collection, onSnapshot, @@ -19,7 +20,8 @@ import { signOut, } from 'firebase/auth'; -import { setPublications, setUser } from '../store/slice/appState'; +import { setPublications, setUser as setUserState } from '../store/slice/appState'; +import { User } from '../../types'; const firebaseConfig = { apiKey: 'AIzaSyBlu1GzA5jvM6mh6taIcjtNgcSEVxlxa1Q', @@ -45,15 +47,10 @@ const collectionName = 'publications'; export const handleLogin = async () => { try { const result = await signInWithPopup(auth, provider); - const credential = GoogleAuthProvider.credentialFromResult(result); const token = credential.accessToken; const { email } = result.user; - console.log(token); - console.log(email); - - // const response = await fetch(`https://cloudidentity.googleapis.com/v1/groups:lookup?groupKey.id=ccv-gsdc@brown.edu`, { const response = await fetch( `https://cloudidentity.googleapis.com/v1/groups/0184mhaj2thv9r6/memberships`, { @@ -63,7 +60,17 @@ export const handleLogin = async () => { } ); - console.log(response); + let ccv = false; + if (response.ok) { + const { memberships } = (await response.json()) ?? []; + ccv = memberships.some((m) => m.preferredMemberKey.id.toLowerCase() === email.toLowerCase()); + } + + const userDoc = await getUser(email); + if (!userDoc || userDoc.ccv !== ccv) { + userDoc.ccv = ccv; + await updateUser(userDoc); + } } catch (error) { console.log(error); } @@ -84,19 +91,14 @@ export const useAuthStateChanged = () => { const dispatch = useDispatch(); useEffect(() => { - const unsubscribe = onAuthStateChanged(auth, (user) => { + const unsubscribe = onAuthStateChanged(auth, async (user) => { if (user) { - const { displayName, email, uid } = user; - - dispatch( - setUser({ - displayName, - email, - uid, - }) - ); + const { email } = user; + const userData = await getUser(email); + console.log(userData); + dispatch(setUserState(userData)); } else { - dispatch(setUser(null)); + dispatch(setUserState(null)); } }); @@ -143,3 +145,21 @@ export const addPublication = async (publication) => { updatedAt: Date.now(), }); }; + +const updateUser = async ({ displayName, email, ccv }: User) => { + const docRef = doc(db, 'users', email); + + await setDoc(docRef, { + displayName, + email, + ccv, + updatedAt: Date.now(), + }); +}; + +const getUser = async (email): Promise => { + const docRef = doc(db, 'users', email); + const docSnap = await getDoc(docRef); + + return docSnap.data() as User; +}; diff --git a/types/index.d.ts b/types/index.d.ts index b4f79f8..601c69d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -8,3 +8,10 @@ export interface Publication { year: number; abstract: string; } + +export interface User { + displayName: string; + email: string; + ccv: boolean; + updatedAt: number; +} \ No newline at end of file From c1260c7cc0bd81bde0e85174c0459da6f409c812 Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Mon, 15 Apr 2024 18:53:14 -0400 Subject: [PATCH 3/7] wip: test on preview again --- src/utils/firebase.ts | 6 ++++-- types/index.d.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 5b526d7..c81e47e 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -68,8 +68,10 @@ export const handleLogin = async () => { const userDoc = await getUser(email); if (!userDoc || userDoc.ccv !== ccv) { - userDoc.ccv = ccv; - await updateUser(userDoc); + await updateUser({ + ...userDoc, + ccv, + }); } } catch (error) { console.log(error); diff --git a/types/index.d.ts b/types/index.d.ts index 601c69d..15c8ef4 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -14,4 +14,4 @@ export interface User { email: string; ccv: boolean; updatedAt: number; -} \ No newline at end of file +} From e1ff051bf0a3021519cad742310452e1ea05d7e3 Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Tue, 16 Apr 2024 09:27:56 -0400 Subject: [PATCH 4/7] feat: update user on firebase --- package.json | 1 + src/utils/firebase.ts | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3ebd2e1..129a2db 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "homepage": ".", + "proxy": "https://ccv-pubs.web.app/", "scripts": { "start": "react-scripts start", "build": "react-scripts build", diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index c81e47e..4a9a8c4 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -49,7 +49,7 @@ export const handleLogin = async () => { const result = await signInWithPopup(auth, provider); const credential = GoogleAuthProvider.credentialFromResult(result); const token = credential.accessToken; - const { email } = result.user; + const { displayName, email } = result.user; const response = await fetch( `https://cloudidentity.googleapis.com/v1/groups/0184mhaj2thv9r6/memberships`, @@ -67,9 +67,10 @@ export const handleLogin = async () => { } const userDoc = await getUser(email); - if (!userDoc || userDoc.ccv !== ccv) { + if (!userDoc || userDoc.ccv !== ccv || userDoc.displayName !== displayName) { await updateUser({ - ...userDoc, + displayName, + email, ccv, }); } @@ -148,7 +149,7 @@ export const addPublication = async (publication) => { }); }; -const updateUser = async ({ displayName, email, ccv }: User) => { +const updateUser = async ({ displayName, email, ccv }) => { const docRef = doc(db, 'users', email); await setDoc(docRef, { From 6fcb4fc5ca4fe04cccce887dc952b130a6abeb14 Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Tue, 16 Apr 2024 10:38:47 -0400 Subject: [PATCH 5/7] refactor: subscribe to user --- src/utils/firebase.ts | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 4a9a8c4..834586b 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { useDispatch } from 'react-redux'; import { initializeApp } from 'firebase/app'; import { @@ -42,7 +42,9 @@ provider.addScope('https://www.googleapis.com/auth/cloud-identity.groups.readonl provider.setCustomParameters({ hd: 'brown.edu', }); -const collectionName = 'publications'; +const publicationsCollection = 'publications'; +const usersCollection = 'users'; +const ccvStaffGoogleGroupId = '0184mhaj2thv9r6'; export const handleLogin = async () => { try { @@ -51,8 +53,11 @@ export const handleLogin = async () => { const token = credential.accessToken; const { displayName, email } = result.user; + // Fetch members from the CCV group + // If the user is in the group, we'll get back members. Otherwise, we'll get a permission error + // The access token is in scope here and I didn't want to save it anywhere const response = await fetch( - `https://cloudidentity.googleapis.com/v1/groups/0184mhaj2thv9r6/memberships`, + `https://cloudidentity.googleapis.com/v1/groups/${ccvStaffGoogleGroupId}/memberships`, { headers: { Authorization: `Bearer ${token}`, @@ -63,6 +68,8 @@ export const handleLogin = async () => { let ccv = false; if (response.ok) { const { memberships } = (await response.json()) ?? []; + + // Double check that the user is a member in the ccv group ccv = memberships.some((m) => m.preferredMemberKey.id.toLowerCase() === email.toLowerCase()); } @@ -94,19 +101,23 @@ export const useAuthStateChanged = () => { const dispatch = useDispatch(); useEffect(() => { - const unsubscribe = onAuthStateChanged(auth, async (user) => { + const unsubscribeAuth = onAuthStateChanged(auth, async (user) => { if (user) { const { email } = user; - const userData = await getUser(email); - console.log(userData); - dispatch(setUserState(userData)); + const unsubscribeUser = onSnapshot(doc(db, usersCollection, email), (doc) => { + if (doc.exists) { + dispatch(setUserState(doc.data())); + return; + } + }); + unsubscribeUser(); } else { dispatch(setUserState(null)); } }); return () => { - unsubscribe(); + unsubscribeAuth(); }; }, [dispatch]); }; @@ -120,7 +131,7 @@ export const usePublicationsCollection = () => { useEffect(() => { const unsubscribe = onSnapshot( query( - collection(db, collectionName), + collection(db, publicationsCollection), orderBy('updatedAt', 'desc'), limit(100) // TODO: TEMPORARY. Limiting right now. Set up pagination? ), @@ -141,7 +152,7 @@ export const usePublicationsCollection = () => { export const addPublication = async (publication) => { const docId = publication.doi.toLowerCase().replace(/\//g, '_'); - const docRef = doc(db, collectionName, docId); + const docRef = doc(db, publicationsCollection, docId); await setDoc(docRef, { ...publication, @@ -150,7 +161,7 @@ export const addPublication = async (publication) => { }; const updateUser = async ({ displayName, email, ccv }) => { - const docRef = doc(db, 'users', email); + const docRef = doc(db, usersCollection, email); await setDoc(docRef, { displayName, @@ -161,7 +172,7 @@ const updateUser = async ({ displayName, email, ccv }) => { }; const getUser = async (email): Promise => { - const docRef = doc(db, 'users', email); + const docRef = doc(db, usersCollection, email); const docSnap = await getDoc(docRef); return docSnap.data() as User; From 2ed0d56558807b5af7d91dded77cb7930a574279 Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Tue, 16 Apr 2024 12:14:02 -0400 Subject: [PATCH 6/7] feat: show add pub if user is in ccv --- src/components/ContentPage.jsx | 2 +- src/utils/firebase.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ContentPage.jsx b/src/components/ContentPage.jsx index 2e1af69..02a1939 100755 --- a/src/components/ContentPage.jsx +++ b/src/components/ContentPage.jsx @@ -14,7 +14,7 @@ export function ContentPage() { return (
- {user ? ( + {user?.ccv ? (
diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 834586b..7ec2fd4 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { initializeApp } from 'firebase/app'; import { From 67d3c4b46e197d3e93e322803fe3400151cbd95a Mon Sep 17 00:00:00 2001 From: Ellen Duong Date: Tue, 16 Apr 2024 13:06:41 -0400 Subject: [PATCH 7/7] fix: unsubscribe user --- src/utils/firebase.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/firebase.ts b/src/utils/firebase.ts index 7ec2fd4..21274c5 100644 --- a/src/utils/firebase.ts +++ b/src/utils/firebase.ts @@ -107,10 +107,9 @@ export const useAuthStateChanged = () => { const unsubscribeUser = onSnapshot(doc(db, usersCollection, email), (doc) => { if (doc.exists) { dispatch(setUserState(doc.data())); - return; } }); - unsubscribeUser(); + return () => unsubscribeUser(); } else { dispatch(setUserState(null)); }