Web: Add Login Button or Avatar + API_HOST Env Var #137
@@ -26,10 +26,11 @@ Prerequisite: golang installed
|
||||
|
||||
Prerequisite: bun installed
|
||||
|
||||
The environment variable `API_HOST` will need to be set for the middleware.
|
||||
The environment variables `API_HOST` and `AUTH_HOST` will need to be set for the middleware.
|
||||
Example `.env` in web's root:
|
||||
```
|
||||
API_HOST="http://localhost:8082/v1/"
|
||||
AUTH_HOST="http://localhost:8083/"
|
||||
```
|
||||
|
||||
1. `cd web`
|
||||
|
||||
@@ -50,6 +50,7 @@ services:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- API_HOST=http://submissions:8082/v1
|
||||
- AUTH_HOST=http://localhost:8080/
|
||||
|
||||
validation:
|
||||
image:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import Image from "next/image";
|
||||
|
||||
import "./styles/header.scss"
|
||||
import { UserInfo } from "@/app/ts/User";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface HeaderButton {
|
||||
name: string,
|
||||
@@ -15,6 +20,25 @@ function HeaderButton(header: HeaderButton) {
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
const handleLoginClick = () => {
|
||||
window.location.href = "/auth/oauth2/login?redirect=" + window.location.href;
|
||||
};
|
||||
|
||||
const [valid, setValid] = useState<boolean>(false)
|
||||
const [user, setUser] = useState<UserInfo | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function getLoginInfo() {
|
||||
const [validateData, userData] = await Promise.all([
|
||||
fetch("/api/session/validate").then(validateResponse => validateResponse.json()),
|
||||
fetch("/api/session/user").then(userResponse => userResponse.json())
|
||||
]);
|
||||
setValid(validateData)
|
||||
setUser(userData)
|
||||
}
|
||||
getLoginInfo()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<header className="header-bar">
|
||||
<nav className="left">
|
||||
@@ -24,6 +48,16 @@ export default function Header() {
|
||||
</nav>
|
||||
<nav className="right">
|
||||
<HeaderButton name="Submit" href="/submit"/>
|
||||
{valid && user ? (
|
||||
<div className="author">
|
||||
<Link href="/auth">
|
||||
<Image className="avatar" width={28} height={28} priority={true} src={user.AvatarURL} alt={user.Username}/>
|
||||
<button>{user.Username}</button>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<button onClick={handleLoginClick}>Login</button>
|
||||
)}
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import Header from "./header";
|
||||
|
||||
async function login_check() {
|
||||
const response = await fetch("/api/session/validate")
|
||||
if (response.ok) {
|
||||
const logged_in = await response.json()
|
||||
if (!logged_in) {
|
||||
redirect("https://auth.staging.strafes.net/oauth2/login?redirect=" + window.location.href)
|
||||
}
|
||||
} else {
|
||||
console.error("No response from /api/session/validate")
|
||||
}
|
||||
}
|
||||
|
||||
export default function Webpage({children}: Readonly<{children?: React.ReactNode}>) {
|
||||
useEffect(() => { login_check() }, [])
|
||||
|
||||
return <>
|
||||
<Header/>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { MapfixList } from "../ts/Mapfix";
|
||||
import { MapfixCard } from "../_components/mapCard";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { SubmissionList } from "../ts/Submission";
|
||||
import { SubmissionCard } from "../_components/mapCard";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
|
||||
5
web/src/app/ts/User.ts
Normal file
5
web/src/app/ts/User.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface UserInfo {
|
||||
readonly UserID: number,
|
||||
readonly Username: string,
|
||||
readonly AvatarURL: string,
|
||||
}
|
||||
@@ -1,13 +1,29 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
|
||||
export const config = {
|
||||
matcher: ["/api/:path*"],
|
||||
matcher: ["/api/:path*", "/auth/:path*"],
|
||||
}
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
if (!process.env.API_HOST) {
|
||||
throw new Error("env variable \"API_HOST\" is not set")
|
||||
}
|
||||
const url = new URL(process.env.API_HOST + request.nextUrl.pathname.replace(/^\/api/, '') + request.nextUrl.search)
|
||||
return NextResponse.rewrite(url, { request })
|
||||
const { pathname, search } = request.nextUrl
|
||||
|
||||
if (pathname.startsWith("/api")) {
|
||||
if (!process.env.API_HOST) {
|
||||
throw new Error('env variable "API_HOST" is not set')
|
||||
}
|
||||
const apiUrl = new URL(process.env.API_HOST + pathname.replace(/^\/api/, '') + search)
|
||||
return NextResponse.rewrite(apiUrl, { request })
|
||||
} else if (pathname.startsWith("/auth")) {
|
||||
if (!process.env.AUTH_HOST) {
|
||||
throw new Error('env variable "AUTH_HOST" is not set')
|
||||
}
|
||||
|
||||
const authHost = process.env.AUTH_HOST.replace(/\/$/, "")
|
||||
const path = pathname.replace(/^\/auth/, "")
|
||||
const redirectUrl = new URL(authHost + path + search)
|
||||
|
||||
return NextResponse.redirect(redirectUrl, 302)
|
||||
}
|
||||
|
||||
return NextResponse.next()
|
||||
}
|
||||
Reference in New Issue
Block a user