Commiting to switch to a different orm
This commit is contained in:
@@ -1,23 +1,24 @@
|
||||
import { signIn } from "@/lib/auth"
|
||||
import { signIn } from "@/lib/auth";
|
||||
import type React from "react";
|
||||
|
||||
export default function Auth(props: {
|
||||
searchParams: { callbackUrl: string | undefined }
|
||||
}) {
|
||||
searchParams: Promise<{ callbackUrl: string | undefined }>
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<form
|
||||
className="w-40 mx-auto"
|
||||
action={async () => {
|
||||
"use server"
|
||||
"use server";
|
||||
await signIn("authelia", {
|
||||
redirectTo: props.searchParams?.callbackUrl ?? "",
|
||||
})
|
||||
redirectTo: (await props.searchParams)?.callbackUrl ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
>
|
||||
<button type="submit"
|
||||
className={`rounded-lg dark:bg-dracula-bg-light transition-colors duration-100 dark:text-white px-2 py-2 font-normal border-transparent`}
|
||||
>
|
||||
<span>Sign in with Authelia</span>
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
import NavBar from '@/components/navbar';
|
||||
import Footer from '@/components/footer';
|
||||
import LogIn from "@/components/auth/login";
|
||||
|
||||
import "../globals.css";
|
||||
|
||||
|
||||
@@ -11,21 +11,23 @@ export default async function Photos(): Promise<React.JSX.Element> {
|
||||
const {data: imageData} = await getImageData();
|
||||
|
||||
return (
|
||||
<Lightbox imageData={imageData.images}>
|
||||
{imageData.images.map((image) => (
|
||||
<Image
|
||||
key={image.src}
|
||||
alt={image.src}
|
||||
src={image.src}
|
||||
className="object-contain h-60 w-80"
|
||||
sizes="100vw"
|
||||
loading="lazy"
|
||||
width={image.width}
|
||||
height={image.height}
|
||||
blurDataURL={image.blur}
|
||||
placeholder="blur"
|
||||
/>
|
||||
))}
|
||||
</Lightbox>
|
||||
<div className="mx-auto">
|
||||
<Lightbox imageData={imageData.images}>
|
||||
{imageData.images.map((image) => (
|
||||
<Image
|
||||
key={image.src}
|
||||
alt={image.src}
|
||||
src={image.src}
|
||||
className="object-contain h-60 w-80"
|
||||
sizes="100vw"
|
||||
loading="lazy"
|
||||
width={image.width}
|
||||
height={image.height}
|
||||
blurDataURL={image.blur}
|
||||
placeholder="blur"
|
||||
/>
|
||||
))}
|
||||
</Lightbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,12 @@ export async function generateStaticParams(): Promise<{slug: string[]}[]> {
|
||||
return slugs;
|
||||
}
|
||||
|
||||
export default async function Post({params}: {params: { slug: string[] }}): Promise<React.JSX.Element> {
|
||||
const mdxFile = await import(`../../../../markdown/posts/[...slug]/${params.slug.join('/')}.mdx`)
|
||||
const Post = dynamic(async () => mdxFile);
|
||||
export default async function Post({params}: {params: Promise<{ slug: string[] }>}): Promise<React.JSX.Element> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const mdxFile = await import(`../../../../markdown/posts/[...slug]/${(await params).slug.join('/')}.mdx`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return
|
||||
const Post = dynamic(() => mdxFile);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return (
|
||||
<Post/>
|
||||
);
|
||||
|
||||
@@ -21,12 +21,15 @@ async function loadPostDetails(): Promise<postDetails[]> {
|
||||
});
|
||||
|
||||
const loadPostData = posts.map(async (post) => {
|
||||
const slug = [post.split('/').at(-1)!.slice(0, -4)]
|
||||
const mdxFile = await import(`../../../../src/markdown/posts/[...slug]/${slug.join('/')}.mdx`)
|
||||
const slug = [post.split('/').at(-1)!.slice(0, -4)];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const mdxFile = await import(`../../../../src/markdown/posts/[...slug]/${slug.join('/')}.mdx`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
return {
|
||||
link: getCurrentUrl() + '/posts/' + slug.join('/'),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
|
||||
metadata: mdxFile.metadata,
|
||||
link: getCurrentUrl() + '/posts/' + slug.join('/')
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const postData = await Promise.all(loadPostData);
|
||||
@@ -39,7 +42,7 @@ const getPosts = unstable_cache(
|
||||
{
|
||||
revalidate: false
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export default async function Posts(): Promise<React.JSX.Element> {
|
||||
const postDetails = await getPosts();
|
||||
@@ -58,7 +61,7 @@ export default async function Posts(): Promise<React.JSX.Element> {
|
||||
<div key={`${post.link}_${tag}`}>
|
||||
<span className="select-none text-sm me-2 px-2.5 py-1 rounded border border-dracula-pink dark:bg-dracula-bg-darker dark:text-dracula-pink">{tag}</span>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<p>
|
||||
@@ -66,7 +69,7 @@ export default async function Posts(): Promise<React.JSX.Element> {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,21 +2,21 @@ import { NextRequest } from "next/server";
|
||||
import { handlers } from "@/lib/auth";
|
||||
|
||||
const reqWithTrustedOrigin = (req: NextRequest): NextRequest => {
|
||||
const proto = req.headers.get('x-forwarded-proto')
|
||||
const host = req.headers.get('x-forwarded-host')
|
||||
const proto = req.headers.get('x-forwarded-proto');
|
||||
const host = req.headers.get('x-forwarded-host');
|
||||
if (!proto || !host) {
|
||||
console.warn("Missing x-forwarded-proto or x-forwarded-host headers.")
|
||||
return req
|
||||
console.warn("Missing x-forwarded-proto or x-forwarded-host headers.");
|
||||
return req;
|
||||
}
|
||||
const envOrigin = `${proto}://${host}`
|
||||
const { href, origin } = req.nextUrl
|
||||
return new NextRequest(href.replace(origin, envOrigin), req)
|
||||
}
|
||||
const envOrigin = `${proto}://${host}`;
|
||||
const { href, origin } = req.nextUrl;
|
||||
return new NextRequest(href.replace(origin, envOrigin), req);
|
||||
};
|
||||
|
||||
export const GET = (req: NextRequest) => {
|
||||
return handlers.GET(reqWithTrustedOrigin(req))
|
||||
}
|
||||
export const GET = (req: NextRequest): Promise<Response> => {
|
||||
return handlers.GET(reqWithTrustedOrigin(req));
|
||||
};
|
||||
|
||||
export const POST = (req: NextRequest) => {
|
||||
return handlers.POST(reqWithTrustedOrigin(req))
|
||||
}
|
||||
export const POST = (req: NextRequest): Promise<Response> => {
|
||||
return handlers.POST(reqWithTrustedOrigin(req));
|
||||
};
|
||||
@@ -49,8 +49,8 @@ export async function GET(): Promise<Response> {
|
||||
}),
|
||||
title: photo.title ?? undefined,
|
||||
description: photo.description ?? undefined
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json<GetPhotos>({ status: 200, data: { images } });
|
||||
}
|
||||
@@ -15,7 +15,7 @@ export type GetPhotosUpdate = {
|
||||
|
||||
export const GET = auth(async function GET(req): Promise<Response> {
|
||||
if (!req.auth) {
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 });
|
||||
}
|
||||
|
||||
const dataSource = await PhotoDataSource.dataSource;
|
||||
@@ -35,7 +35,7 @@ export const GET = auth(async function GET(req): Promise<Response> {
|
||||
const s3Res = await s3Client.send(listObjCmd);
|
||||
|
||||
if (!s3Res.Contents) {
|
||||
return NextResponse.json({ status: 500 })
|
||||
return NextResponse.json({ status: 500 });
|
||||
}
|
||||
const s3Photos = sift(s3Res.Contents.map((obj) => {
|
||||
if (!obj.Key?.endsWith('/')) {
|
||||
@@ -51,7 +51,7 @@ export const GET = auth(async function GET(req): Promise<Response> {
|
||||
const getImageCmd = new GetObjectCommand({
|
||||
Bucket: "joemonk-photos",
|
||||
Key: fileName.replace("https://fly.storage.tigris.dev/joemonk-photos/", "")
|
||||
})
|
||||
});
|
||||
const imgRes = await s3Client.send(getImageCmd);
|
||||
const image = await imgRes.Body?.transformToByteArray();
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ export default async function LogIn(): Promise<React.JSX.Element | undefined> {
|
||||
return (
|
||||
<form
|
||||
action={async () => {
|
||||
"use server"
|
||||
"use server";
|
||||
if (session?.user) {
|
||||
await signOut({
|
||||
redirectTo: `${getCurrentUrl()}/`
|
||||
})
|
||||
});
|
||||
} else {
|
||||
await signIn("authelia")
|
||||
await signIn("authelia");
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -63,21 +63,23 @@ function NextJsImage({ slide, offset, rect, unoptimized = false }: {slide: Image
|
||||
);
|
||||
}
|
||||
|
||||
export default function MyLightbox({imageData, children}: {imageData: ImageData[], children: React.JSX.Element[]}): React.JSX.Element {
|
||||
export function MyLightbox({imageData, children}: {imageData: ImageData[], children: React.JSX.Element[]}): React.JSX.Element {
|
||||
const [active, setActive] = useState<number | null>(null);
|
||||
|
||||
return (
|
||||
<div className="mx-auto">
|
||||
<div className="flex flex-row flex-wrap justify-center">
|
||||
{children.map((image, index) => (
|
||||
<button key={`lightbox_img_${index}`} onClick={(() => {
|
||||
setActive(index);
|
||||
})}>
|
||||
<div className="relative">
|
||||
{image}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
{children.map((image, index) => {
|
||||
return (
|
||||
<button key={`lightbox_img_${index}`} onClick={(() => {
|
||||
setActive(index);
|
||||
})}>
|
||||
<div className="relative">
|
||||
{image}
|
||||
</div>
|
||||
</button>
|
||||
); }
|
||||
)}
|
||||
</div>
|
||||
<YARL
|
||||
open={typeof active === 'number'}
|
||||
@@ -90,4 +92,41 @@ export default function MyLightbox({imageData, children}: {imageData: ImageData[
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
interface FormElements extends HTMLFormControlsCollection {
|
||||
src: HTMLInputElement
|
||||
}
|
||||
interface UsernameFormElement extends HTMLFormElement {
|
||||
readonly elements: FormElements
|
||||
}
|
||||
|
||||
export default function Test(props: {imageData: ImageData[], children: React.JSX.Element[]}): React.JSX.Element {
|
||||
const [imageData, setImageData] = useState(props.imageData);
|
||||
|
||||
function handleSubmit(event: React.FormEvent<UsernameFormElement>): void {
|
||||
event.preventDefault();
|
||||
const imageData = props.imageData;
|
||||
setImageData(imageData.filter((data) => data.src === event.currentTarget.elements.src.value));
|
||||
}
|
||||
|
||||
const children = imageData.map((data) => props.children.find((child) => {
|
||||
return data.src === child.key ? child : null;
|
||||
})).filter(((data) => !!data));
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="src">Src:</label>
|
||||
<input id="src" type="text" />
|
||||
</div>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<MyLightbox imageData={imageData}>
|
||||
{...children}
|
||||
</MyLightbox>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export default function NavBarClient({LogIn, navigation}: NavBarClientProps): Re
|
||||
current.current = true;
|
||||
}
|
||||
return nav;
|
||||
}, [pathname]);
|
||||
}, [pathname, navigation]);
|
||||
|
||||
return (
|
||||
<nav className="dark:bg-dracula-bg-darker border-b-2 dark:border-dracula-purple">
|
||||
|
||||
@@ -12,7 +12,7 @@ const defaultNavigation = [
|
||||
|
||||
const authedNavigation = [
|
||||
{ name: 'Manage', href: '/manage', current: false },
|
||||
]
|
||||
];
|
||||
|
||||
export default async function NavBar(): Promise<React.JSX.Element> {
|
||||
const session = await auth();
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function PostHeader({metadata}: PostHeaderProps): React.JSX.Eleme
|
||||
<>
|
||||
<span className="select-none text-sm me-2 px-2.5 py-1 rounded border border-dracula-pink dark:bg-dracula-bg-darker dark:text-dracula-pink">{tag}</span>
|
||||
</>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Photo } from "./entity/photo";
|
||||
|
||||
const dataSource = new DataSource({
|
||||
type: "better-sqlite3",
|
||||
database: "db.sql",
|
||||
database: `${process.cwd()}/db.sql`,
|
||||
entities: [Photo],
|
||||
migrations: ["./migrations"],
|
||||
})
|
||||
});
|
||||
|
||||
export default class PhotoDataSource {
|
||||
private static _dataSource: DataSource | null = null;
|
||||
@@ -22,11 +22,11 @@ export default class PhotoDataSource {
|
||||
static async initDataSource(): Promise<DataSource> {
|
||||
if (!PhotoDataSource._dataSource || !PhotoDataSource._dataSource.isInitialized) {
|
||||
const ds = await dataSource.initialize();
|
||||
console.log('Photo data source initialized')
|
||||
console.log('Photo data source initialized');
|
||||
PhotoDataSource._dataSource = ds;
|
||||
}
|
||||
return PhotoDataSource._dataSource;
|
||||
}
|
||||
}
|
||||
|
||||
PhotoDataSource.initDataSource();
|
||||
await PhotoDataSource.initDataSource();
|
||||
@@ -1,48 +1,48 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
|
||||
@Entity()
|
||||
export class Photo {
|
||||
@PrimaryGeneratedColumn()
|
||||
id!: number
|
||||
id!: number;
|
||||
|
||||
@Column("text", { unique: true })
|
||||
src!: string;
|
||||
src!: string;
|
||||
|
||||
@Column()
|
||||
width!: number
|
||||
width!: number;
|
||||
|
||||
@Column()
|
||||
height!: number
|
||||
height!: number;
|
||||
|
||||
@Column("blob")
|
||||
blur!: string
|
||||
blur!: string;
|
||||
|
||||
@Column("text", { nullable: true })
|
||||
camera: string | null = null;
|
||||
camera: string | null = null;
|
||||
|
||||
// Manually input data
|
||||
@Column("text", { nullable: true })
|
||||
title: string | null = null;
|
||||
title: string | null = null;
|
||||
|
||||
@Column("text", { nullable: true })
|
||||
description: string | null = null;
|
||||
description: string | null = null;
|
||||
|
||||
// Exif data
|
||||
@Column("int", { nullable: true })
|
||||
exposureBiasValue: number | null = null
|
||||
exposureBiasValue: number | null = null;
|
||||
|
||||
@Column("float", { nullable: true })
|
||||
fNumber: number | null = null
|
||||
fNumber: number | null = null;
|
||||
|
||||
@Column("int", { nullable: true })
|
||||
isoSpeedRatings: number | null = null
|
||||
isoSpeedRatings: number | null = null;
|
||||
|
||||
@Column("int", { nullable: true })
|
||||
focalLength: number | null = null
|
||||
focalLength: number | null = null;
|
||||
|
||||
@Column("date", { nullable: true })
|
||||
dateTimeOriginal: Date | null = null
|
||||
dateTimeOriginal: Date | null = null;
|
||||
|
||||
@Column("text", { nullable: true })
|
||||
lensModel: string | null = null
|
||||
lensModel: string | null = null;
|
||||
}
|
||||
@@ -13,4 +13,4 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
}],
|
||||
trustHost: true,
|
||||
redirectProxyUrl: `${getCurrentUrl()}/api/auth`,
|
||||
})
|
||||
});
|
||||
Reference in New Issue
Block a user