home index
This commit is contained in:
1 parent
a4d8608a3e
commit
b6c6e54ef8
8 files changed
+103
-179
No files matched your search
@@ -3,8 +3,9 @@ import { getCookies } from "$std/http/cookie.ts"
|
|||||||
import { CratesCtx } from 'api/mw.service.ts'
|
import { CratesCtx } from 'api/mw.service.ts'
|
||||||
|
|
||||||
const PROTECTED = [
|
const PROTECTED = [
|
||||||
"/api/auth",
|
"/",
|
||||||
"/home",
|
"/home",
|
||||||
|
"/api/auth",
|
||||||
]
|
]
|
||||||
|
|
||||||
// Open Deno KV database
|
// Open Deno KV database
|
||||||
|
|||||||
@@ -1,46 +1,10 @@
|
|||||||
import { h } from 'preact';
|
import { User } from 'prismaClient'
|
||||||
import { route } from 'preact-router';
|
|
||||||
import { useEffect } from 'preact/hooks';
|
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
import LogRocket from 'logrocket';
|
|
||||||
|
|
||||||
import http from './../http';
|
function showAdmin(user: User) {
|
||||||
import { State } from './../store';
|
|
||||||
|
|
||||||
import Swirl from './swirl';
|
|
||||||
|
|
||||||
function showAdmin(user) {
|
|
||||||
return user && user.email === 'ntr@mnml.gg';
|
return user && user.email === 'ntr@mnml.gg';
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_ROUTE = '/';
|
const Nav = ({ user }) => {
|
||||||
|
|
||||||
const Nav = () => {
|
|
||||||
const user = useSelector((state: State) => state.user);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!user) {
|
|
||||||
route('/login');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
route(DEFAULT_ROUTE)
|
|
||||||
|
|
||||||
if (window.location.host === 'crates.ntwl.xyz') {
|
|
||||||
LogRocket.identify(user.id, {
|
|
||||||
name: user.email,
|
|
||||||
email: user.email,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}, [user])
|
|
||||||
|
|
||||||
async function logoutClick(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
await http.postLogout();
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
const nav = () => (
|
const nav = () => (
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/">Offers</a>
|
<a href="/">Offers</a>
|
||||||
@@ -65,7 +29,7 @@ const Nav = () => {
|
|||||||
const userNav = () => (
|
const userNav = () => (
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/info">Info</a>
|
<a href="/info">Info</a>
|
||||||
<a href="/auth/logout" onClick={logoutClick}>Logout</a>
|
<a href="/api/auth/logout" >Logout</a>
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import * as $api_auth_status from './routes/api/auth/status.ts'
|
|||||||
import * as $api_offers from './routes/api/offers.ts'
|
import * as $api_offers from './routes/api/offers.ts'
|
||||||
import * as $api_wants from './routes/api/wants.ts'
|
import * as $api_wants from './routes/api/wants.ts'
|
||||||
import * as $home from './routes/home.tsx'
|
import * as $home from './routes/home.tsx'
|
||||||
|
import * as $index from './routes/index.tsx'
|
||||||
import * as $login from './routes/login.tsx'
|
import * as $login from './routes/login.tsx'
|
||||||
import * as $register from './routes/register.tsx'
|
import * as $register from './routes/register.tsx'
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ const manifest = {
|
|||||||
'./routes/api/offers.ts': $api_offers,
|
'./routes/api/offers.ts': $api_offers,
|
||||||
'./routes/api/wants.ts': $api_wants,
|
'./routes/api/wants.ts': $api_wants,
|
||||||
'./routes/home.tsx': $home,
|
'./routes/home.tsx': $home,
|
||||||
|
'./routes/index.tsx': $index,
|
||||||
'./routes/login.tsx': $login,
|
'./routes/login.tsx': $login,
|
||||||
'./routes/register.tsx': $register,
|
'./routes/register.tsx': $register,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { type PageProps } from "$fresh/server.ts";
|
import { type PageProps } from "$fresh/server.ts";
|
||||||
|
|
||||||
export default function App({ Component }: PageProps) {
|
export default function App({ Component }: PageProps) {
|
||||||
return (
|
return (
|
||||||
<html>
|
<html>
|
||||||
|
|||||||
@@ -6,12 +6,7 @@ import { z } from "npm:zod"
|
|||||||
import { zx } from "npm:zodix"
|
import { zx } from "npm:zodix"
|
||||||
|
|
||||||
import { createSession } from "api/mw.auth.ts"
|
import { createSession } from "api/mw.auth.ts"
|
||||||
import {
|
import { InvalidCredentialsError } from "api/errors.ts"
|
||||||
ValidationError,
|
|
||||||
InvalidCredentialsError,
|
|
||||||
NotLoggedInError,
|
|
||||||
ServerError
|
|
||||||
} from "api/errors.ts"
|
|
||||||
import { CratesState } from 'api/mw.service.ts'
|
import { CratesState } from 'api/mw.service.ts'
|
||||||
|
|
||||||
const LoginSchema = z.object({
|
const LoginSchema = z.object({
|
||||||
@@ -21,70 +16,37 @@ const LoginSchema = z.object({
|
|||||||
|
|
||||||
export const handler: Handlers<{email: string}, CratesState> = {
|
export const handler: Handlers<{email: string}, CratesState> = {
|
||||||
async POST(req, ctx) {
|
async POST(req, ctx) {
|
||||||
try {
|
const { email, password } = await zx.parseForm(req, LoginSchema)
|
||||||
const { email, password } = await zx.parseForm(req, LoginSchema)
|
|
||||||
|
|
||||||
// Create pg instance for database operations
|
// Create pg instance for database operations
|
||||||
const { pg } = ctx.state
|
const { pg } = ctx.state
|
||||||
|
|
||||||
// Find user by email
|
|
||||||
const user = await pg.userFindEmail(email)
|
|
||||||
if (!user) throw new InvalidCredentialsError()
|
|
||||||
|
|
||||||
// Verify password
|
|
||||||
const match = await bcrypt.compare(password, user.password)
|
|
||||||
if (!match) throw new InvalidCredentialsError()
|
|
||||||
|
|
||||||
// Create session using Deno KV
|
// Find user by email
|
||||||
const { sessionId, expiresAt } = await createSession(user.id, 24 * 7) // 7 days in hours
|
const user = await pg.userFindEmail(email)
|
||||||
|
if (!user) throw new InvalidCredentialsError()
|
||||||
// Set cookie
|
|
||||||
const headers = new Headers({ "Content-Type": "application/json" })
|
|
||||||
setCookie(headers, {
|
|
||||||
name: "session",
|
|
||||||
value: sessionId,
|
|
||||||
expires: expiresAt,
|
|
||||||
path: "/",
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
sameSite: "Lax"
|
|
||||||
})
|
|
||||||
|
|
||||||
// Return user data
|
|
||||||
return new Response(JSON.stringify({
|
|
||||||
email: user.email
|
|
||||||
}), {
|
|
||||||
status: 200,
|
|
||||||
headers
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
// Let the error middleware handle custom errors
|
|
||||||
if (error instanceof ValidationError ||
|
|
||||||
error instanceof InvalidCredentialsError) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error("Login error:", error)
|
// Verify password
|
||||||
throw new ServerError("An error occurred during login")
|
const match = await bcrypt.compare(password, user.password)
|
||||||
}
|
if (!match) throw new InvalidCredentialsError()
|
||||||
},
|
|
||||||
|
// Create session using Deno KV
|
||||||
// GET handler to check login status
|
const { sessionId, expiresAt } = await createSession(user.id, 24 * 7) // 7 days in hours
|
||||||
async GET(req, ctx) {
|
|
||||||
// This would be handled by the auth middleware
|
// Set cookie
|
||||||
// If the request reaches here, the user is authenticated
|
const headers = new Headers({ "Content-Type": "application/json" })
|
||||||
const user = ctx.state.user
|
setCookie(headers, {
|
||||||
|
name: "session",
|
||||||
if (!user) {
|
value: sessionId,
|
||||||
throw new NotLoggedInError()
|
expires: expiresAt,
|
||||||
}
|
path: "/",
|
||||||
|
httpOnly: true,
|
||||||
return new Response(JSON.stringify({
|
secure: true,
|
||||||
id: user.id,
|
sameSite: "Lax"
|
||||||
email: user.email
|
|
||||||
}), {
|
|
||||||
status: 200,
|
|
||||||
headers: { "Content-Type": "application/json" }
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: { Location: "/home" }
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Handlers } from "$fresh/server.ts"
|
import { Handlers } from "$fresh/server.ts"
|
||||||
import { setCookie } from "$std/http/cookie.ts"
|
import { setCookie } from "$std/http/cookie.ts"
|
||||||
import { z } from "https://deno.land/x/zod@v3.22.4/mod.ts"
|
|
||||||
|
import { z } from "npm:zod"
|
||||||
|
import { zx } from "npm:zodix"
|
||||||
|
|
||||||
import { createPg } from "api/pg.ts"
|
import { createPg } from "api/pg.ts"
|
||||||
import { createSession } from "api/mw.auth.ts"
|
import { createSession } from "api/mw.auth.ts"
|
||||||
import {
|
import { ResourceExistsError } from "api/errors.ts"
|
||||||
ValidationError,
|
import { CratesState } from 'api/mw.service.ts'
|
||||||
ResourceExistsError,
|
|
||||||
ServerError
|
|
||||||
} from "api/errors.ts"
|
|
||||||
|
|
||||||
// Define validation schema with Zod
|
// Define validation schema with Zod
|
||||||
const RegisterSchema = z.object({
|
const RegisterSchema = z.object({
|
||||||
@@ -16,67 +16,43 @@ const RegisterSchema = z.object({
|
|||||||
discogs: z.string().optional()
|
discogs: z.string().optional()
|
||||||
})
|
})
|
||||||
|
|
||||||
export const handler: Handlers = {
|
export const handler: Handlers<{email: string}, CratesState> = {
|
||||||
async POST(req, _ctx) {
|
async POST(req, _ctx) {
|
||||||
try {
|
const { discogs, email, password } = await zx.parseForm(req, RegisterSchema)
|
||||||
const data = await req.formData()
|
|
||||||
|
|
||||||
// Validate input data with Zod
|
|
||||||
const result = RegisterSchema.safeParse(data)
|
|
||||||
|
|
||||||
if (!result.success) {
|
// Create pg instance for database operations
|
||||||
// Throw validation error
|
const pg = createPg(console)
|
||||||
throw new ValidationError("Validation failed", result.error.format())
|
|
||||||
}
|
|
||||||
|
|
||||||
const { discogs, email, password } = result.data
|
|
||||||
|
|
||||||
// Create pg instance for database operations
|
// Check if user exists
|
||||||
const pg = createPg(console)
|
const existingUser = await pg.userFindEmail(email)
|
||||||
|
if (existingUser) throw new ResourceExistsError("User with this email")
|
||||||
// Check if user exists
|
|
||||||
const existingUser = await pg.userFindEmail(email)
|
|
||||||
|
|
||||||
if (existingUser) {
|
|
||||||
throw new ResourceExistsError("User with this email")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create user
|
|
||||||
const params = { discogs, email, password, data: {} }
|
|
||||||
const user = await pg.userCreate(params)
|
|
||||||
|
|
||||||
// Create session using Deno KV
|
|
||||||
const { sessionId, expiresAt } = await createSession(user.id, 24 * 7) // 7 days in hours
|
|
||||||
|
|
||||||
// Set cookie
|
|
||||||
const headers = new Headers({ "Content-Type": "application/json" })
|
|
||||||
setCookie(headers, {
|
|
||||||
name: "session",
|
|
||||||
value: sessionId,
|
|
||||||
expires: expiresAt,
|
|
||||||
path: "/",
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
sameSite: "Lax"
|
|
||||||
})
|
|
||||||
|
|
||||||
// Return user data
|
|
||||||
return new Response(JSON.stringify({
|
|
||||||
id: user.id,
|
|
||||||
email: user.email
|
|
||||||
}), {
|
|
||||||
status: 200,
|
|
||||||
headers
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
// Let the error middleware handle custom errors
|
|
||||||
if (error instanceof ValidationError ||
|
|
||||||
error instanceof ResourceExistsError) {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error("Registration error:", error)
|
// Create user
|
||||||
throw new ServerError("An error occurred during registration")
|
const params = { discogs, email, password, data: {} }
|
||||||
}
|
const user = await pg.userCreate(params)
|
||||||
|
|
||||||
|
// Create session using Deno KV
|
||||||
|
const { sessionId, expiresAt } = await createSession(user.id, 24 * 7) // 7 days in hours
|
||||||
|
|
||||||
|
// Set cookie
|
||||||
|
const headers = new Headers({ "Content-Type": "application/json" })
|
||||||
|
setCookie(headers, {
|
||||||
|
name: "session",
|
||||||
|
value: sessionId,
|
||||||
|
expires: expiresAt,
|
||||||
|
path: "/",
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "Lax"
|
||||||
|
})
|
||||||
|
|
||||||
|
// Return user data
|
||||||
|
return new Response(JSON.stringify({
|
||||||
|
id: user.id,
|
||||||
|
email: user.email
|
||||||
|
}), {
|
||||||
|
status: 200,
|
||||||
|
headers
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import Main from "../components/main.tsx";
|
|||||||
|
|
||||||
import { CratesState } from "api/mw.service.ts"
|
import { CratesState } from "api/mw.service.ts"
|
||||||
import { Offer, Want } from "prismaClient"
|
import { Offer, Want } from "prismaClient"
|
||||||
|
import Nav from '../components/nav.tsx'
|
||||||
|
|
||||||
interface HomeData {
|
interface HomeData {
|
||||||
wants: Want[],
|
wants: Want[],
|
||||||
@@ -13,21 +14,20 @@ export const handler: Handlers<HomeData, CratesState> = {
|
|||||||
async GET(_req, ctx) {
|
async GET(_req, ctx) {
|
||||||
const { pg, offers, user } = ctx.state
|
const { pg, offers, user } = ctx.state
|
||||||
|
|
||||||
console.log(user)
|
|
||||||
|
|
||||||
const wants = await pg.userWants(user);
|
const wants = await pg.userWants(user);
|
||||||
const uOffers = await offers.userOffers(user);
|
const uOffers = await offers.userOffers(user);
|
||||||
|
|
||||||
return await ctx.render({ wants, offers: uOffers });
|
return await ctx.render({ user, wants, offers: uOffers });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Home({ data }: PageProps) {
|
export default function Home({ data }: PageProps) {
|
||||||
const { wants, offers } = data || {};
|
const { user, wants, offers } = data
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="mcrates">
|
<>
|
||||||
|
<Nav user={user} />
|
||||||
<Main wants={wants} offers={offers} />
|
<Main wants={wants} offers={offers} />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import { Handlers } from "$fresh/server.ts"
|
||||||
|
import { CratesState } from 'api/mw.service.ts'
|
||||||
|
|
||||||
|
export const handler: Handlers<{email: string}, CratesState> = {
|
||||||
|
GET(_req, ctx) {
|
||||||
|
const { user } = ctx.state
|
||||||
|
|
||||||
|
if (user) return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: { Location: "/home" }
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(null, {
|
||||||
|
status: 302,
|
||||||
|
headers: { Location: "/login" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user