Skip to content

Commit

Permalink
Merge pull request #80 from brown-ccv/feat-google-group
Browse files Browse the repository at this point in the history
Feat: restrict google group to ccv
  • Loading branch information
eldu authored Apr 26, 2024
2 parents 8c420a0 + 67d3c4b commit 206167e
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 18 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion src/components/ContentPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function ContentPage() {

return (
<div className="main-content d-flex flex-column align-items-center">
{user ? (
{user?.ccv ? (
<div className="align-self-end">
<AddPublicationModal />
</div>
Expand Down
87 changes: 70 additions & 17 deletions src/utils/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { initializeApp } from 'firebase/app';
import {
getFirestore,
doc,
getDoc,
setDoc,
collection,
onSnapshot,
Expand All @@ -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',
Expand All @@ -35,15 +37,50 @@ 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',
});
const collectionName = 'publications';
const publicationsCollection = 'publications';
const usersCollection = 'users';
const ccvStaffGoogleGroupId = '0184mhaj2thv9r6';

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 { 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/${ccvStaffGoogleGroupId}/memberships`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

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());
}

const userDoc = await getUser(email);
if (!userDoc || userDoc.ccv !== ccv || userDoc.displayName !== displayName) {
await updateUser({
displayName,
email,
ccv,
});
}
} catch (error) {
console.log(error);
}
Expand All @@ -64,24 +101,22 @@ export const useAuthStateChanged = () => {
const dispatch = useDispatch();

useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
const unsubscribeAuth = onAuthStateChanged(auth, async (user) => {
if (user) {
const { displayName, email, uid } = user;

dispatch(
setUser({
displayName,
email,
uid,
})
);
const { email } = user;
const unsubscribeUser = onSnapshot(doc(db, usersCollection, email), (doc) => {
if (doc.exists) {
dispatch(setUserState(doc.data()));
}
});
return () => unsubscribeUser();
} else {
dispatch(setUser(null));
dispatch(setUserState(null));
}
});

return () => {
unsubscribe();
unsubscribeAuth();
};
}, [dispatch]);
};
Expand All @@ -95,7 +130,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?
),
Expand All @@ -116,10 +151,28 @@ 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,
updatedAt: Date.now(),
});
};

const updateUser = async ({ displayName, email, ccv }) => {
const docRef = doc(db, usersCollection, email);

await setDoc(docRef, {
displayName,
email,
ccv,
updatedAt: Date.now(),
});
};

const getUser = async (email): Promise<User> => {
const docRef = doc(db, usersCollection, email);
const docSnap = await getDoc(docRef);

return docSnap.data() as User;
};
7 changes: 7 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@ export interface Publication {
year: number;
abstract: string;
}

export interface User {
displayName: string;
email: string;
ccv: boolean;
updatedAt: number;
}

0 comments on commit 206167e

Please sign in to comment.