From 733054428e37c95c62566dc13b283e34865674dd Mon Sep 17 00:00:00 2001 From: Koper Date: Fri, 18 Aug 2023 19:29:02 +0700 Subject: [PATCH] Auth front-end --- www/app/{ => (auth)}/fiefWrapper.tsx | 0 www/app/(auth)/userInfo.tsx | 43 ++++++++++++++ www/app/api/.openapi-generator/FILES | 1 + www/app/api/apis/DefaultApi.ts | 45 ++++++++++++++ www/app/api/models/UserInfo.ts | 84 +++++++++++++++++++++++++++ www/app/api/models/index.ts | 1 + www/app/layout.tsx | 19 ++++-- www/app/lib/getApi.ts | 18 ++++++ www/app/lib/{random.tsx => random.ts} | 0 www/app/lib/{time.tsx => time.ts} | 0 www/app/lib/user.ts | 21 +++++++ www/app/transcripts/new/page.tsx | 9 +-- www/app/transcripts/useTranscript.tsx | 7 +-- www/app/transcripts/useWebRTC.tsx | 6 +- www/app/userInfo.tsx | 23 -------- 15 files changed, 234 insertions(+), 43 deletions(-) rename www/app/{ => (auth)}/fiefWrapper.tsx (100%) create mode 100644 www/app/(auth)/userInfo.tsx create mode 100644 www/app/api/models/UserInfo.ts create mode 100644 www/app/lib/getApi.ts rename www/app/lib/{random.tsx => random.ts} (100%) rename www/app/lib/{time.tsx => time.ts} (100%) create mode 100644 www/app/lib/user.ts delete mode 100644 www/app/userInfo.tsx diff --git a/www/app/fiefWrapper.tsx b/www/app/(auth)/fiefWrapper.tsx similarity index 100% rename from www/app/fiefWrapper.tsx rename to www/app/(auth)/fiefWrapper.tsx diff --git a/www/app/(auth)/userInfo.tsx b/www/app/(auth)/userInfo.tsx new file mode 100644 index 00000000..d0a8ad02 --- /dev/null +++ b/www/app/(auth)/userInfo.tsx @@ -0,0 +1,43 @@ +"use client"; +import { + useFiefIsAuthenticated, + useFiefUserinfo, +} from "@fief/fief/nextjs/react"; +import Link from "next/link"; +import Image from "next/image"; + +export default function UserInfo() { + const isAuthenticated = useFiefIsAuthenticated(); + const userinfo = useFiefUserinfo(); + + return ( +
+ {/* Logo on the left */} + + Reflector + + + {/* Text link on the right */} + {!isAuthenticated && ( + + Log in or create account + + )} + {isAuthenticated && ( + + {userinfo?.email} ( + + Log out + + ) + + )} +
+ ); +} diff --git a/www/app/api/.openapi-generator/FILES b/www/app/api/.openapi-generator/FILES index c6dc9bb8..91888ece 100644 --- a/www/app/api/.openapi-generator/FILES +++ b/www/app/api/.openapi-generator/FILES @@ -9,6 +9,7 @@ models/PageGetTranscript.ts models/RtcOffer.ts models/TranscriptTopic.ts models/UpdateTranscript.ts +models/UserInfo.ts models/ValidationError.ts models/index.ts runtime.ts diff --git a/www/app/api/apis/DefaultApi.ts b/www/app/api/apis/DefaultApi.ts index 752ef536..947c64ed 100644 --- a/www/app/api/apis/DefaultApi.ts +++ b/www/app/api/apis/DefaultApi.ts @@ -742,4 +742,49 @@ export class DefaultApi extends runtime.BaseAPI { ); return await response.value(); } + + /** + * User Me + */ + async v1UserMeRaw( + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise> { + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + if (this.configuration && this.configuration.accessToken) { + // oauth required + headerParameters["Authorization"] = await this.configuration.accessToken( + "OAuth2AuthorizationCodeBearer", + [], + ); + } + + const response = await this.request( + { + path: `/v1/me`, + method: "GET", + headers: headerParameters, + query: queryParameters, + }, + initOverrides, + ); + + if (this.isJsonMime(response.headers.get("content-type"))) { + return new runtime.JSONApiResponse(response); + } else { + return new runtime.TextApiResponse(response) as any; + } + } + + /** + * User Me + */ + async v1UserMe( + initOverrides?: RequestInit | runtime.InitOverrideFunction, + ): Promise { + const response = await this.v1UserMeRaw(initOverrides); + return await response.value(); + } } diff --git a/www/app/api/models/UserInfo.ts b/www/app/api/models/UserInfo.ts new file mode 100644 index 00000000..65d84951 --- /dev/null +++ b/www/app/api/models/UserInfo.ts @@ -0,0 +1,84 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * FastAPI + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * The version of the OpenAPI document: 0.1.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from "../runtime"; +/** + * + * @export + * @interface UserInfo + */ +export interface UserInfo { + /** + * + * @type {any} + * @memberof UserInfo + */ + sub: any | null; + /** + * + * @type {any} + * @memberof UserInfo + */ + email: any | null; + /** + * + * @type {any} + * @memberof UserInfo + */ + emailVerified: any | null; +} + +/** + * Check if a given object implements the UserInfo interface. + */ +export function instanceOfUserInfo(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "sub" in value; + isInstance = isInstance && "email" in value; + isInstance = isInstance && "emailVerified" in value; + + return isInstance; +} + +export function UserInfoFromJSON(json: any): UserInfo { + return UserInfoFromJSONTyped(json, false); +} + +export function UserInfoFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): UserInfo { + if (json === undefined || json === null) { + return json; + } + return { + sub: json["sub"], + email: json["email"], + emailVerified: json["email_verified"], + }; +} + +export function UserInfoToJSON(value?: UserInfo | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + sub: value.sub, + email: value.email, + email_verified: value.emailVerified, + }; +} diff --git a/www/app/api/models/index.ts b/www/app/api/models/index.ts index 7de1ce39..d872c782 100644 --- a/www/app/api/models/index.ts +++ b/www/app/api/models/index.ts @@ -8,4 +8,5 @@ export * from "./PageGetTranscript"; export * from "./RtcOffer"; export * from "./TranscriptTopic"; export * from "./UpdateTranscript"; +export * from "./UserInfo"; export * from "./ValidationError"; diff --git a/www/app/layout.tsx b/www/app/layout.tsx index 85a8f17b..fc7913f5 100644 --- a/www/app/layout.tsx +++ b/www/app/layout.tsx @@ -1,8 +1,8 @@ import "./styles/globals.scss"; import { Roboto } from "next/font/google"; import { Metadata } from "next"; -import FiefWrapper from "./fiefWrapper"; -import UserInfo from "./userInfo"; +import FiefWrapper from "./(auth)/fiefWrapper"; +import UserInfo from "./(auth)/userInfo"; const roboto = Roboto({ subsets: ["latin"], weight: "400" }); @@ -55,8 +55,19 @@ export default function RootLayout({ children }) { - - {children} +
+
+ + +
+

Reflector

+

+ Capture The Signal, Not The Noise +

+
+ {children} +
+
diff --git a/www/app/lib/getApi.ts b/www/app/lib/getApi.ts new file mode 100644 index 00000000..198bfd59 --- /dev/null +++ b/www/app/lib/getApi.ts @@ -0,0 +1,18 @@ +import { Configuration } from "../api/runtime"; +import { DefaultApi } from "../api/apis/DefaultApi"; + +import { useFiefAccessTokenInfo } from "@fief/fief/nextjs/react"; + +export default function getApi(): DefaultApi { + const accessTokenInfo = useFiefAccessTokenInfo(); + + const apiConfiguration = new Configuration({ + basePath: process.env.NEXT_PUBLIC_API_URL, + accessToken: accessTokenInfo + ? "Bearer " + accessTokenInfo.access_token + : undefined, + }); + const api = new DefaultApi(apiConfiguration); + + return api; +} diff --git a/www/app/lib/random.tsx b/www/app/lib/random.ts similarity index 100% rename from www/app/lib/random.tsx rename to www/app/lib/random.ts diff --git a/www/app/lib/time.tsx b/www/app/lib/time.ts similarity index 100% rename from www/app/lib/time.tsx rename to www/app/lib/time.ts diff --git a/www/app/lib/user.ts b/www/app/lib/user.ts new file mode 100644 index 00000000..26740e47 --- /dev/null +++ b/www/app/lib/user.ts @@ -0,0 +1,21 @@ +export async function getCurrentUser(): Promise { + try { + const response = await fetch("/api/current-user"); + + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + + const data = await response.json(); + + // Ensure the data structure is as expected + if (data.userinfo && data.access_token_info) { + return data; + } else { + throw new Error("Unexpected data structure"); + } + } catch (error) { + console.error("Error fetching the user data:", error); + throw error; // or you can return an appropriate fallback or error indicator + } +} diff --git a/www/app/transcripts/new/page.tsx b/www/app/transcripts/new/page.tsx index 80bbe9fe..949b477f 100644 --- a/www/app/transcripts/new/page.tsx +++ b/www/app/transcripts/new/page.tsx @@ -26,12 +26,7 @@ const App = () => { const webSockets = useWebSockets(transcript.response?.id); return ( -
-
-

Reflector

-

Capture The Signal, Not The Noise

-
- + <> { @@ -48,7 +43,7 @@ const App = () => { topics={webSockets.topics} disconnected={disconnected} /> -
+ ); }; diff --git a/www/app/transcripts/useTranscript.tsx b/www/app/transcripts/useTranscript.tsx index 26e0d440..040004ac 100644 --- a/www/app/transcripts/useTranscript.tsx +++ b/www/app/transcripts/useTranscript.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { DefaultApi, V1TranscriptsCreateRequest } from "../api/apis/DefaultApi"; import { Configuration } from "../api/runtime"; import { GetTranscript } from "../api"; +import getApi from "../lib/getApi"; type UseTranscript = { response: GetTranscript | null; @@ -15,11 +16,7 @@ const useTranscript = (): UseTranscript => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const apiConfiguration = new Configuration({ - basePath: process.env.NEXT_PUBLIC_API_URL, - // accessToken: - }); - const api = new DefaultApi(apiConfiguration); + const api = getApi(); const createTranscript = () => { setLoading(true); diff --git a/www/app/transcripts/useWebRTC.tsx b/www/app/transcripts/useWebRTC.tsx index ea622bb2..2f9f3c25 100644 --- a/www/app/transcripts/useWebRTC.tsx +++ b/www/app/transcripts/useWebRTC.tsx @@ -5,6 +5,7 @@ import { V1TranscriptRecordWebrtcRequest, } from "../api/apis/DefaultApi"; import { Configuration } from "../api/runtime"; +import getApi from "../lib/getApi"; const useWebRTC = ( stream: MediaStream | null, @@ -17,10 +18,7 @@ const useWebRTC = ( return; } - const apiConfiguration = new Configuration({ - basePath: process.env.NEXT_PUBLIC_API_URL, - }); - const api = new DefaultApi(apiConfiguration); + const api = getApi(); let p: Peer = new Peer({ initiator: true, stream: stream }); diff --git a/www/app/userInfo.tsx b/www/app/userInfo.tsx deleted file mode 100644 index bf8d19c5..00000000 --- a/www/app/userInfo.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; -import { useFiefUserinfo } from "@fief/fief/nextjs/react"; - -export default function UserInfo() { - const userinfo = useFiefUserinfo(); - - return ( - <> - {userinfo && ( - <> -

Logged In

-

{userinfo.email}

- - )} - - {!userinfo && ( - <> -

Not Logged In

- - )} - - ); -}