Skip to content

Commit

Permalink
feat: create private content route and data readers
Browse files Browse the repository at this point in the history
  • Loading branch information
vighnesh153 committed Dec 22, 2024
1 parent 1fa831a commit ffc1b61
Show file tree
Hide file tree
Showing 21 changed files with 357 additions and 22 deletions.
3 changes: 3 additions & 0 deletions tools-nodejs/vighnesh153-astro/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export const functionsRegion = "us-central1";

export const firebaseCollections = {
usersByUserId: "users_by_userId",
userIdByUsername: "userId_by_username",
privateContent: "private_content",
};
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"ekAHm4gvpTBjoSmvINUnt638btaM","createdAt":"1734187406426","lastLoginAt":"1734276869465","displayName":"Vighnesh Raut","photoUrl":"https://i.imgur.com/npqtdBu.png","providerUserInfo":[{"providerId":"google.com","rawId":"5762999240917570257694699278672391745578","federatedId":"5762999240917570257694699278672391745578","displayName":"Vighnesh Raut","photoUrl":"https://i.imgur.com/npqtdBu.png","email":"[email protected]","screenName":"vighnesh153"}],"validSince":"1734279393","email":"[email protected]","emailVerified":true,"disabled":false}]}
{"kind":"identitytoolkit#DownloadAccountResponse","users":[{"localId":"ekAHm4gvpTBjoSmvINUnt638btaM","createdAt":"1734187406426","lastLoginAt":"1734882450193","displayName":"Vighnesh Raut","photoUrl":"https://i.imgur.com/npqtdBu.png","providerUserInfo":[{"providerId":"google.com","rawId":"5762999240917570257694699278672391745578","federatedId":"5762999240917570257694699278672391745578","displayName":"Vighnesh Raut","photoUrl":"https://i.imgur.com/npqtdBu.png","email":"[email protected]","screenName":"vighnesh153"}],"validSince":"1734881873","email":"[email protected]","emailVerified":true,"disabled":false,"lastRefreshAt":"2024-12-22T17:33:39.253Z"},{"localId":"iWtBCmoWRTXg6UTQCV7ncLJPxcNO","displayName":"Pikachu","photoUrl":"https://i.imgur.com/npqtdBu.png","screenName":"Pikachu","email":"[email protected]","emailVerified":true,"createdAt":"1734882413806","lastLoginAt":"1734882416118","providerUserInfo":[{"providerId":"google.com","rawId":"7759237076568892792428913761032108656749","federatedId":"7759237076568892792428913761032108656749","displayName":"Pikachu","photoUrl":"https://i.imgur.com/npqtdBu.png","email":"[email protected]","screenName":"Pikachu"}],"lastRefreshAt":"2024-12-22T15:46:56.118Z"}]}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { firestore } from "firebase-admin";
import * as logger from "firebase-functions/logger";
import { HttpsError, onCall } from "firebase-functions/v2/https";

import { firebaseCollections } from "../../constants";
import { hasPermission } from "../../permissions/mod";

const db = firestore();

export const getPrivateContent = onCall(async (req) => {
const uid = req.auth?.uid;
if (!uid) {
logger.error("You are not logged in.");
throw new HttpsError("unauthenticated", "Not logged in.");
}

if (!hasPermission(uid, "getPrivateContent")) {
logger.error("You don't have permission to access this resource.");
throw new HttpsError(
"permission-denied",
"You don't have permission to get private content.",
);
}

try {
const snapshot = await db.collection(firebaseCollections.privateContent)
.get();
const docs = await snapshot.docs.map((doc) => doc.data());
return docs;
} catch (e) {
logger.error("Failed to fetch private content:", e);
throw new HttpsError(
"internal",
"Some internal error occurred file fetching private content.",
);
}
});
5 changes: 4 additions & 1 deletion tools-nodejs/vighnesh153-astro/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
import { setGlobalOptions } from "firebase-functions/v2";
import { initializeApp } from "firebase-admin/app";

setGlobalOptions({ maxInstances: 2 });
import { functionsRegion } from "../../constants";

setGlobalOptions({ maxInstances: 1, region: functionsRegion });
initializeApp();

export * from "./before_user_sign_up";
export * from "./before_user_sign_in";
export * from "./get_private_content";
68 changes: 68 additions & 0 deletions tools-nodejs/vighnesh153-astro/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion tools-nodejs/vighnesh153-astro/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
{
"scripts": {
"start": "npx firebase emulators:start --project demo-vighnesh153-app --import ./firebase-seed --export-on-exit ./firebase-seed",
"start:functions-watch": "npm run --prefix functions build:watch",
"start:emulators": "npx firebase emulators:start --project demo-vighnesh153-app --import ./firebase-seed --export-on-exit ./firebase-seed",
"start": "npx conc --kill-others \"npm run start:functions-watch\" \"npm run start:emulators\"",
"deploy": "npx firebase deploy --project vighnesh153-app",
"deploy:hosting": "npx firebase deploy --only hosting --project vighnesh153-app",
"deploy:functions": "npx firebase deploy --only functions --project vighnesh153-app"
},
"dependencies": {
"firebase-functions": "^6.1.1",
"firebase-tools": "^13.28.0"
},
"devDependencies": {
"concurrently": "^9.1.0"
}
}
17 changes: 17 additions & 0 deletions tools-nodejs/vighnesh153-astro/permissions/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { type Permissions } from "./permissions";
import { vighnesh153Permissions } from "./vighnesh153";

export function hasPermission(
uid: string,
permission: keyof Permissions,
): boolean {
return uidToPermissions[uid]?.[permission] ?? false;
}

const uidToPermissions: Record<string, Permissions> = {
// prod
"pIX2CHynXKYyobveA1B3Ym7T99Z2": vighnesh153Permissions,

// local
"ekAHm4gvpTBjoSmvINUnt638btaM": vighnesh153Permissions,
};
4 changes: 4 additions & 0 deletions tools-nodejs/vighnesh153-astro/permissions/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Permissions {
// IYKYK
getPrivateContent?: boolean;
}
5 changes: 5 additions & 0 deletions tools-nodejs/vighnesh153-astro/permissions/vighnesh153.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { type Permissions } from "./permissions";

export const vighnesh153Permissions: Permissions = {
getPrivateContent: true,
};
4 changes: 2 additions & 2 deletions tools-nodejs/vighnesh153-astro/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"private": true,
"license": "MIT",
"scripts": {
"dev": "astro dev --host",
"build": "astro check && astro build",
"dev": "NODE_ENV=dev astro dev --host",
"build": "NODE_ENV=production astro check && astro build",
"lint": "astro check",
"prefmt": "cp deno-bk.json deno.json",
"fmt": "deno fmt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const { navItems = defaultNavItems, ...props } = Astro.props;
</nav>

<script>
import { AllNavigationItems, logAnalyticsEvent } from "@/utils/index.ts";
import { AllNavigationItems } from "@/utils/index.ts";
import { logAnalyticsEvent } from "@/utils/firebase_config.ts";

document
.getElementById(AllNavigationItems.resume.id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { createResource, For, type JSX, Show } from "solid-js";
import { useStore } from "@nanostores/solid";

import { classes } from "@/utils";
import { loggedInUserId } from "@/store/auth.ts";
import { getPrivateContent } from "@/store/private_content";

const fetchPrivateContent = (userId: string | null) =>
getPrivateContent(userId);

export function PrivateCardsCollection(): JSX.Element {
const $loggedInUserId = useStore(loggedInUserId);
const [privateContent] = createResource($loggedInUserId, fetchPrivateContent);

return (
<div>
<Show when={privateContent.loading}>
<p>Loading...</p>
</Show>
<Show when={privateContent.error || privateContent() === null}>
<p>Failed to fetch content.</p>
</Show>
<Show when={privateContent() !== null}>
<div
class={classes(`
grid gap-4
grid-cols-1 sm:grid-cols-2 lg:grid-cols-3
`)}
>
<For each={privateContent()?.data ?? []}>
{(card) => (
<div class="min-w-5 aspect-video bg-primary rounded-lg"></div>
)}
</For>
</div>
</Show>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { z } from "zod";

export const PrivateContent = z.object({
data: z.object({
id: z.string().min(1),
localPath: z.string().min(1),
imageUrl: z.string().min(1),
videoUrl: z.string().min(1),
}).array(),
});

export type PrivateContent = z.infer<typeof PrivateContent>;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
import { classes, projectNavItems } from "@/utils/index.ts";
import ContentLayout from "@/layouts/ContentLayout.astro";
import { GraphicsProjectsCollection } from "@/components/projects/graphics/GraphicsProjectsCollection.tsx";
import { PrivateCardsCollection } from "@/components/private/private_cards_collection.tsx";
const title = "Vighnesh Raut | Private content";
const description = `Graphics programming projects built with HTML Canvas API`;
Expand All @@ -15,6 +15,13 @@ const description = `Graphics programming projects built with HTML Canvas API`;
<div
class={classes(`mt-32 mb-12 max-w-xl mx-auto lg:max-w-[unset] scroll-mt-8`)}
>
<!-- <GraphicsProjectsCollection client:load /> -->
<PrivateCardsCollection client:load />
</div>
</ContentLayout>

<script>
// import { invokeFirebaseFunction } from "@/utils/firebase_config";

// const result = await invokeFirebaseFunction("getPrivateContent");
// console.log("Pikachu:", result);
</script>
6 changes: 5 additions & 1 deletion tools-nodejs/vighnesh153-astro/website/src/store/auth.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { onAuthStateChanged } from "firebase/auth";
import { atom, type ReadableAtom } from "nanostores";
import { atom, computed, type ReadableAtom } from "nanostores";

import { UserInfo } from "@/models/user_info.ts";
import { getAuth } from "@/utils/firebase_config.ts";
import { getUserById } from "./users.ts";

const mutableLoggedInUser = atom<UserInfo | null>(null);
export const loggedInUser: ReadableAtom<UserInfo | null> = mutableLoggedInUser;
export const loggedInUserId = computed(
loggedInUser,
(user) => user?.userId ?? null,
);

export async function initializeUserInStore() {
await onAuthStateChanged(await getAuth(), async (user) => {
Expand Down
Loading

0 comments on commit ffc1b61

Please sign in to comment.