Skip to content

Commit

Permalink
Firestore working and syncing.
Browse files Browse the repository at this point in the history
  • Loading branch information
weishuhn committed Feb 2, 2022
1 parent f6f0dda commit 42d1805
Show file tree
Hide file tree
Showing 22 changed files with 1,641 additions and 62 deletions.
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VUE_APP_CLIENT_API_URL=http://127.0.0.1:8080
VUE_APP_SHOW_LOGIN=true
5 changes: 5 additions & 0 deletions .firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "inciteful-xyz"
}
}
23 changes: 23 additions & 0 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Inciteful-Web-CI

on:
push:
branches: [master]

env:
CARGO_TERM_COLOR: always

jobs:
firebase_deploy:
name: Building...
runs-on: ubuntu-18.04
steps:
- name: Checkout Repo
uses: actions/checkout@v2
- name: Deploy to Firebase
uses: w9jds/firebase-action@master
with:
args: deploy --only hosting
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?

# firebase
firestore-*.log
ui-*.log
/firebase-backup
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ npm-watch:
npm-build-release:
npm install
npm run build-prod

firebase-start:
firebase emulators:start --export-on-exit=./firebase-backup --import=./firebase-backup
1,404 changes: 1,404 additions & 0 deletions firebase-debug.log

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"firestore": {
"port": 8079
},
"ui": {
"enabled": true
},
"auth": {
"port": 9099
}
}
}
4 changes: 4 additions & 0 deletions firestore.indexes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"indexes": [],
"fieldOverrides": []
}
14 changes: 14 additions & 0 deletions firestore.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
match /paperCollections/{collectionId} {
allow read: if request.auth.uid == resource.data.ownerId || resource.data.visibility == "PUBLIC";
allow update, delete: if request.auth != null && request.auth.uid == resource.data.ownerId;
allow create: if request.auth != null;
}
}
}
2 changes: 1 addition & 1 deletion src/components/layout/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
</button>
<router-link
v-if="user.isSignedIn && user.enabled"
to="/dashboard"
to="/user"
class="ml-4 inline-flex items-center px-1 pt-1"
>
<span
Expand Down
4 changes: 3 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Vue3TouchEvents from 'vue3-touch-events'

import './assets/tailwind.css'
import { useUserStore } from './stores/user'
import { useDBStore } from './stores/db'
require('v3-tour/dist/vue-tour.css')


Expand All @@ -38,7 +39,8 @@ if (process.env.NODE_ENV === 'production') {
(async () => {
app.use(createPinia())
const { bindUser } = useUserStore();
await bindUser();
const { bind } = useDBStore()
await bindUser([bind]);

app.use(router)
.use(VueTour)
Expand Down
23 changes: 22 additions & 1 deletion src/plugins/firebase.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { initializeApp } from 'firebase/app'
import { getAuth, connectAuthEmulator } from "firebase/auth";
import { getFirestore, connectFirestoreEmulator, DocumentData, CollectionReference, collection } from 'firebase/firestore';
import { User, PaperCollection } from '../types/user';

// Firebase app config
const config = {
Expand All @@ -12,5 +15,23 @@ const config = {
}

// Init our firebase app
const app = initializeApp(config)
initializeApp(config)

const db = getFirestore();
const auth = getAuth();

// If on localhost, use all firebase services locally
if (process.env.NODE_ENV === 'development') {
connectFirestoreEmulator(db, 'localhost', 8079);
connectAuthEmulator(auth, "http://localhost:9099");
// add more services as described in the docs: https://firebase.google.com/docs/emulator-suite/connect_firestore
}

const createCollection = <T = DocumentData>(collectionName: string) => {
return collection(db, collectionName) as CollectionReference<T>
}
const usersCol = createCollection<User>('users')
const paperCollectionsCol = createCollection<PaperCollection>('paperCollections')

export { auth, db, paperCollectionsCol, usersCol }

17 changes: 16 additions & 1 deletion src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import qs from 'qs'
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import pagedata from '../utils/pagedata'
import { useUserStore } from '../stores/user';

const routes = [
{
Expand All @@ -13,7 +14,8 @@ const routes = [
description:
'Committed to open access, Inciteful uses the power of graph analysis to help you explore and find the most relevant academic literature.',
canonical: '/'
}
},
isSecureContext
},
{
path: '/login',
Expand Down Expand Up @@ -225,6 +227,19 @@ const router = createRouter({
return result || ''
}
})

router.beforeEach((to) => {
const userStore = useUserStore()

if (to.path.toLowerCase().startsWith("/user") && !userStore.isSignedIn) {
return '/login'
}

if ((to.path.toLowerCase().startsWith("/login") || to.path.toLowerCase().startsWith("/register")) && userStore.isSignedIn) {
return '/user'
}
})

router.afterEach(to => {
pagedata.setTitle(to.meta.title as string)
pagedata.setDescription(to.meta.description as string)
Expand Down
50 changes: 50 additions & 0 deletions src/stores/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

import { defineStore } from 'pinia'
import { collection, setDoc, addDoc, doc, query, where, onSnapshot } from 'firebase/firestore';
import { usersCol, paperCollectionsCol } from '@/plugins/firebase'
import { PaperCollection, User } from '../types/user';

export const useDBStore = defineStore({
id: 'firestoreDB',
state: () => {
return {
paperCollections: [] as PaperCollection[],
user: undefined as User | undefined,
db: {
users: usersCol,
paperCollections: paperCollectionsCol
}
}
},
actions: {
async savePaperCollection(paperCollection: PaperCollection) {
await addDoc(this.db.paperCollections, paperCollection)
},
async saveUser(user: User) {
await setDoc(doc(this.db.users, user.id), user)
},
async bind(userId: string | undefined) {
console.log("binding " + userId)
const q = query(paperCollectionsCol, where("ownerId", "==", userId));

onSnapshot(q, (querySnapshot) => {
this.paperCollections = []
querySnapshot.forEach((doc) => {
this.paperCollections.push(doc.data());
});

console.log("Current collections: ", JSON.stringify(this.paperCollections));

return this.paperCollections
});

onSnapshot(doc(usersCol, userId), (doc) => {
this.user = doc.data()
console.log("Current data: ", doc.data());
});
}
},
getters: {

},
})
31 changes: 0 additions & 31 deletions src/stores/firestore.ts

This file was deleted.

31 changes: 23 additions & 8 deletions src/stores/user.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@

import { getAuth, onAuthStateChanged, createUserWithEmailAndPassword, getIdTokenResult, IdTokenResult, AuthError, signInWithEmailAndPassword, sendPasswordResetEmail } from 'firebase/auth'
import { onAuthStateChanged, createUserWithEmailAndPassword, getIdTokenResult, IdTokenResult, AuthError, signInWithEmailAndPassword, sendPasswordResetEmail } from 'firebase/auth'
import { defineStore } from 'pinia'
import '@/plugins/firebase'
import { auth, usersCol } from '@/plugins/firebase'
import { User } from '../types/user';
import { doc, setDoc } from 'firebase/firestore';

const auth = getAuth()
// avoid null value before initialization from async onAuthStateChanged
const storageId = 'firebase:uid';
type OnChangeFn = (userId: string | undefined) => Promise<void>;

export const useUserStore = defineStore({
id: 'loggedInUser',
state: () => {
const auth = getAuth()

return {
user: auth.currentUser,
userData: undefined as undefined | User,
error: null as null | AuthError,
token: null as null | IdTokenResult,
enabled: process.env.VUE_APP_SHOW_LOGIN == "true"
}
},
actions: {
async saveUser(user: User) {
await setDoc(doc(usersCol, user.id), user)
},
async signUpWithEmailAndPassword(email: string, password: string) {
return createUserWithEmailAndPassword(auth, email, password)
.then(userCredential => {
Expand Down Expand Up @@ -45,18 +51,24 @@ export const useUserStore = defineStore({
})
},
signOut() {
getAuth().signOut()
auth.signOut()
},
async bindUser() {
async bindUser(executeOnChange: OnChangeFn[]) {
onAuthStateChanged(
auth,
async (user) => {
this.user = user;
if (user) {
localStorage.setItem(storageId, user.uid);
this.token = await getIdTokenResult(user);
this.user = user
this.error = null
} else {
localStorage.removeItem(storageId);
}

console.log("changed")
await Promise.all(executeOnChange.map(x => x(user?.uid)))
},
);
},
Expand All @@ -73,11 +85,14 @@ export const useUserStore = defineStore({
},
getters: {
isSignedIn(state): boolean {
return state.user !== null
return state.user !== null || localStorage[storageId]
},
userName(state): string | null {
return state.user ? state.user.email : null;
},
userId(state): string | null {
return state.user ? state.user.uid : null;
},
initial(): string | null {
return (this.userName && this.userName.length > 0 ? this.userName[0].toUpperCase() : null)
}
Expand Down
6 changes: 0 additions & 6 deletions src/types/inciteful.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@ import { LayoutOptions, Core } from 'cytoscape'

export type PaperID = string

export interface ZoteroToken {
oauthToken: string,
oauthTokenSecret: string,
username: string | undefined,
userId: string | undefined
}
export interface Paper {
id: PaperID;
doi: string;
Expand Down
33 changes: 33 additions & 0 deletions src/types/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { PaperID } from "./inciteful";

export interface User {
id: string,
zoteroToken: ZoteroToken | null,
}

enum ItemVisibility {
Hidden = "HIDDEN",
Public = "PUBLIC",
}

export interface ZoteroToken {
oauthToken: string,
oauthTokenSecret: string,
username: string | undefined,
userId: string | undefined
}

export interface PaperCollection {
id: string,
ownerId: string,
parentID: string | null,
visibility: ItemVisibility,
name: string,
papers: CollectionPaper[]
zoteroKey: string | null,
}

export interface CollectionPaper {
paperId: PaperID
zoteroKey: string | null
}
Loading

0 comments on commit 42d1805

Please sign in to comment.