Implement Auth.

This commit is contained in:
Gabriel Brown 2024-07-19 12:08:09 -05:00
parent 3c9a23481e
commit 6414307462
9 changed files with 105 additions and 98 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

View File

@ -1,19 +1,20 @@
import "~/styles/globals.css"; import "~/styles/globals.css";
import { Inter as FontSans } from "next/font/google"; import { Inter as FontSans } from "next/font/google";
import { cn } from "~/lib/utils"; import { cn } from "~/lib/utils";
import { SessionProvider } from "next-auth/react";
import { type Metadata } from "next";
export const metadata: Metadata = {
title: "Tech Tracker",
description: "App used by COG IT employees to update their status throughout the day.",
icons: [{ rel: "icon", url: "/favicon.ico" }],
};
const fontSans = FontSans({ const fontSans = FontSans({
subsets: ["latin"], subsets: ["latin"],
variable: "--font-sans", variable: "--font-sans",
}); });
import { type Metadata } from "next";
export const metadata: Metadata = {
title: "Create T3 App",
description: "Generated by create-t3-app",
icons: [{ rel: "icon", url: "/favicon.ico" }],
};
export default function RootLayout({ export default function RootLayout({
children, children,
}: Readonly<{ children: React.ReactNode }>) { }: Readonly<{ children: React.ReactNode }>) {
@ -22,10 +23,11 @@ export default function RootLayout({
<body <body
className={cn( className={cn(
"min-h-screen bg-background font-sans antialiased", "min-h-screen bg-background font-sans antialiased",
fontSans.variable fontSans.variable)}
)}
> >
<SessionProvider>
{children} {children}
</SessionProvider>
</body> </body>
</html> </html>
); );

View File

@ -1,37 +1,21 @@
import Link from "next/link"; import { auth } from "~/auth";
import { db } from "~/server/db";
import No_Session from "~/components/auth/No_Session";
export default function HomePage() { export default async function HomePage() {
const user = await auth();
const employees = await db.query.users.findMany({
orderBy: (model, {desc}) => desc(model.id),
});
if (!user) {
return ( return (
<main className="flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c] text-white"> <No_Session />
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16"> );
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]"> } else {
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App return (
</h1> <main className="min-h-screen bg-gradient-to-b from-[#111111] to-[#111325] text-white">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8"> <h1 className="text-2xl font-semibold">Welcome!</h1>
<Link
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
href="https://create.t3.gg/en/usage/first-steps"
target="_blank"
>
<h3 className="text-2xl font-bold">First Steps </h3>
<div className="text-lg">
Just the basics - Everything you need to know to set up your
database and authentication.
</div>
</Link>
<Link
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
href="https://create.t3.gg/en/introduction"
target="_blank"
>
<h3 className="text-2xl font-bold">Documentation </h3>
<div className="text-lg">
Learn more about Create T3 App, the libraries it uses, and how to
deploy it.
</div>
</Link>
</div>
</div>
</main> </main>
); );
} }
}

View File

@ -0,0 +1,10 @@
import Sign_In from "./Sign_In";
export default function No_Session() {
return (
<div className="w-2/3 mx-auto text-center pt-10">
<h1 className="text-2xl font-semibold">Unauthorized. Please sign in first.</h1>
< Sign_In />
</div>
);
};

View File

@ -0,0 +1,13 @@
import { signIn } from "~/auth";
export default async function Sign_In() {
return (
<form className="w-full"
action={async () => {
"use server";
await signIn("microsoft-entra-id");
}}>
<button type="submit" className="w-full">Sign In</button>
</form>
);
}

View File

@ -16,9 +16,9 @@ export const env = createEnv({
process.env.NODE_ENV === "production" process.env.NODE_ENV === "production"
? z.string() ? z.string()
: z.string().optional(), : z.string().optional(),
AUTH_MICROSOFT_ENTRA_ID: z.string(), AUTH_MICROSOFT_ENTRA_ID_ID: z.string(),
AUTH_MICROSOFT_ENTRA_SECRET: z.string(), AUTH_MICROSOFT_ENTRA_ID_SECRET: z.string(),
AUTH_MICROSOFT_ENTRA_TENANT_ID: z.string(), AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: z.string(),
}, },
/** /**
@ -38,10 +38,10 @@ export const env = createEnv({
DATABASE_URL: process.env.DATABASE_URL, DATABASE_URL: process.env.DATABASE_URL,
NODE_ENV: process.env.NODE_ENV, NODE_ENV: process.env.NODE_ENV,
API_KEY: process.env.API_KEY, API_KEY: process.env.API_KEY,
AUTH_SECRET: process.env.AUTH_SECRET, AUTH_SECRET: process.env.NEXTAUTH_SECRET,
AUTH_MICROSOFT_ENTRA_ID: process.env.AUTH_MICROSOFT_ENTRA_ID, AUTH_MICROSOFT_ENTRA_ID_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_ID,
AUTH_MICROSOFT_ENTRA_SECRET: process.env.AUTH_MICROSOFT_ENTRA_SECRET, AUTH_MICROSOFT_ENTRA_ID_SECRET: process.env.AUTH_MICROSOFT_ENTRA_ID_SECRET,
AUTH_MICROSOFT_ENTRA_TENANT_ID: process.env.AUTH_MICROSOFT_ENTRA_TENANT_ID, AUTH_MICROSOFT_ENTRA_ID_TENANT_ID: process.env.AUTH_MICROSOFT_ENTRA_ID_TENANT_ID,
}, },
/** /**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially

View File

@ -1,34 +1,32 @@
// Example model schema from the Drizzle docs
// https://orm.drizzle.team/docs/sql-schema-declaration // https://orm.drizzle.team/docs/sql-schema-declaration
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { import {
bigint, bigint,
index,
mysqlTableCreator, mysqlTableCreator,
timestamp, timestamp,
varchar, varchar,
} from "drizzle-orm/mysql-core"; } from "drizzle-orm/mysql-core";
/** export const createTable = mysqlTableCreator((name) => `${name}`);
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
* database instance for multiple projects.
*
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema
*/
export const createTable = mysqlTableCreator((name) => `tech_tracker_web_${name}`);
export const posts = createTable( export const users = createTable(
"post", "users",
{ {
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(), id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
name: varchar("name", { length: 256 }), name: varchar("name", { length: 256 }),
createdAt: timestamp("created_at") status: varchar("status", { length: 256 }),
updatedAt: timestamp("updated_at")
.default(sql`CURRENT_TIMESTAMP`) .default(sql`CURRENT_TIMESTAMP`)
.notNull(), .notNull(),
updatedAt: timestamp("updated_at").onUpdateNow(),
}, },
(example) => ({ );
nameIndex: index("name_idx").on(example.name),
}) export const history = createTable(
"history",
{
id: bigint("id", {mode: "number"}).primaryKey().autoincrement(),
user_id: bigint("user_id", {mode: "number"}).references(() => users.id),
status: varchar("status", { length: 256 }),
updatedAt: timestamp("updated_at").notNull(),
},
); );

View File

@ -4,6 +4,33 @@
@layer base { @layer base {
:root { :root {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
.dark {
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%; --card: 0 0% 100%;
@ -30,33 +57,6 @@
--chart-4: 43 74% 66%; --chart-4: 43 74% 66%;
--chart-5: 27 87% 67%; --chart-5: 27 87% 67%;
} }
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
} }
@layer base { @layer base {