added google auth provider
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 0s
This commit is contained in:
parent
c6cfecdb0f
commit
b171956105
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "wiki-antifa",
|
||||
"name": "logipedia",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@ -46,6 +46,7 @@
|
||||
"@trpc/client": "^11.0.0-rc.446",
|
||||
"@trpc/react-query": "^11.0.0-rc.446",
|
||||
"@trpc/server": "^11.0.0-rc.446",
|
||||
"argon2": "^0.41.1",
|
||||
"cheerio": "^1.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
|
||||
31
pnpm-lock.yaml
generated
31
pnpm-lock.yaml
generated
@ -86,6 +86,9 @@ importers:
|
||||
'@trpc/server':
|
||||
specifier: ^11.0.0-rc.446
|
||||
version: 11.0.0-rc.824(typescript@5.8.2)
|
||||
argon2:
|
||||
specifier: ^0.41.1
|
||||
version: 0.41.1
|
||||
cheerio:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
@ -982,6 +985,10 @@ packages:
|
||||
'@paralleldrive/cuid2@2.2.2':
|
||||
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
|
||||
|
||||
'@phc/format@1.0.0':
|
||||
resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
@ -2051,6 +2058,10 @@ packages:
|
||||
arg@5.0.2:
|
||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||
|
||||
argon2@0.41.1:
|
||||
resolution: {integrity: sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
@ -3356,6 +3367,14 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
|
||||
node-addon-api@8.3.1:
|
||||
resolution: {integrity: sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==}
|
||||
engines: {node: ^18 || ^20 || >= 21}
|
||||
|
||||
node-gyp-build@4.8.4:
|
||||
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
|
||||
hasBin: true
|
||||
|
||||
normalize-path@3.0.0:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -4886,6 +4905,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@noble/hashes': 1.7.1
|
||||
|
||||
'@phc/format@1.0.0': {}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
@ -5963,6 +5984,12 @@ snapshots:
|
||||
|
||||
arg@5.0.2: {}
|
||||
|
||||
argon2@0.41.1:
|
||||
dependencies:
|
||||
'@phc/format': 1.0.0
|
||||
node-addon-api: 8.3.1
|
||||
node-gyp-build: 4.8.4
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
aria-hidden@1.2.4:
|
||||
@ -7598,6 +7625,10 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
node-addon-api@8.3.1: {}
|
||||
|
||||
node-gyp-build@4.8.4: {}
|
||||
|
||||
normalize-path@3.0.0: {}
|
||||
|
||||
novel@1.0.2(@tiptap/extension-code-block@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(highlight.js@11.11.1)(lowlight@3.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
|
||||
1
public/placeholder.svg
Normal file
1
public/placeholder.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@ -14,21 +14,21 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { z } from "zod";
|
||||
import { userProfileSchema } from "@/lib/validation/zod/user";
|
||||
import { userSchema } from "@/lib/validation/zod/user";
|
||||
import { User } from "next-auth";
|
||||
import { updateUserProfile } from "@/server/actions/user";
|
||||
import { toast } from "sonner";
|
||||
|
||||
function UserForm({ server_user, cb }: { server_user: User; cb?: () => void }) {
|
||||
const form = useForm<z.infer<typeof userProfileSchema>>({
|
||||
resolver: zodResolver(userProfileSchema),
|
||||
const form = useForm<z.infer<typeof userSchema>>({
|
||||
resolver: zodResolver(userSchema),
|
||||
defaultValues: {
|
||||
name: server_user?.name ?? "",
|
||||
},
|
||||
});
|
||||
|
||||
// 2. Define a submit handler.
|
||||
async function onSubmit(values: z.infer<typeof userProfileSchema>) {
|
||||
async function onSubmit(values: z.infer<typeof userSchema>) {
|
||||
// Do something with the form values.
|
||||
// ✅ This will be type-safe and validated.
|
||||
const { success } = await updateUserProfile(values);
|
||||
|
||||
@ -22,6 +22,7 @@ export type AppRoutes = {
|
||||
|
||||
// Auth routes
|
||||
signin: string;
|
||||
signup: string;
|
||||
signout: string;
|
||||
profile: string;
|
||||
};
|
||||
@ -43,6 +44,7 @@ export const appRoutes: AppRoutes = {
|
||||
|
||||
// auth
|
||||
signin: "/api/auth/signin",
|
||||
signup: "/api/auth/signin",
|
||||
signout: "/api/auth/signout",
|
||||
profile: "/me",
|
||||
};
|
||||
|
||||
@ -13,6 +13,8 @@ export const env = createEnv({
|
||||
: z.string().optional(),
|
||||
AUTH_DISCORD_ID: z.string(),
|
||||
AUTH_DISCORD_SECRET: z.string(),
|
||||
AUTH_GOOGLE_ID: z.string(),
|
||||
AUTH_GOOGLE_SECRET: z.string(),
|
||||
DATABASE_URL: z.string().url(),
|
||||
NODE_ENV: z
|
||||
.enum(["development", "test", "production"])
|
||||
@ -36,6 +38,8 @@ export const env = createEnv({
|
||||
AUTH_SECRET: process.env.AUTH_SECRET,
|
||||
AUTH_DISCORD_ID: process.env.AUTH_DISCORD_ID,
|
||||
AUTH_DISCORD_SECRET: process.env.AUTH_DISCORD_SECRET,
|
||||
AUTH_GOOGLE_ID: process.env.AUTH_GOOGLE_ID,
|
||||
AUTH_GOOGLE_SECRET: process.env.AUTH_GOOGLE_SECRET,
|
||||
DATABASE_URL: process.env.DATABASE_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
},
|
||||
|
||||
@ -1,7 +1,28 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const userProfileSchema = z.object({
|
||||
export const userSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
// image: z.string().optional(),
|
||||
// email: z.string().email(),
|
||||
email: z.string().email(),
|
||||
image: z.string().optional(),
|
||||
});
|
||||
|
||||
export const passwordSchema = z.string().min(8, {
|
||||
message: "Passwort muss mindestens 8 Zeichen lang sein",
|
||||
});
|
||||
|
||||
export const loginSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(1),
|
||||
});
|
||||
|
||||
export const registerSchema = z
|
||||
.object({
|
||||
name: z.string().min(1),
|
||||
email: z.string().email(),
|
||||
password: passwordSchema,
|
||||
confirmPassword: z.string(),
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword, {
|
||||
message: "Passwörter stimmen nicht überein",
|
||||
path: ["confirmPassword"],
|
||||
});
|
||||
|
||||
7
src/server/actions/auth.ts
Normal file
7
src/server/actions/auth.ts
Normal file
@ -0,0 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { signIn } from "@/server/auth";
|
||||
|
||||
export async function loginOAuth(provider: string) {
|
||||
return await signIn(provider);
|
||||
}
|
||||
@ -1,13 +1,11 @@
|
||||
"use server";
|
||||
|
||||
import { userProfileSchema } from "@/lib/validation/zod/user";
|
||||
import { userSchema } from "@/lib/validation/zod/user";
|
||||
import { api } from "@/trpc/server";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { z } from "zod";
|
||||
|
||||
export async function updateUserProfile(
|
||||
profile: z.infer<typeof userProfileSchema>,
|
||||
) {
|
||||
export async function updateUserProfile(profile: z.infer<typeof userSchema>) {
|
||||
const [result] = await api.users.updateProfile({ profile });
|
||||
if (!result?.id) return { success: false };
|
||||
revalidatePath("/me");
|
||||
|
||||
@ -4,6 +4,7 @@ import { createCallerFactory, createTRPCRouter } from "@/server/api/trpc";
|
||||
import { usersRouter } from "./routers/users";
|
||||
import { authorRouter } from "./routers/author";
|
||||
import { appRouter as globalRouter } from "./routers/app";
|
||||
import { authRouter } from "./routers/auth";
|
||||
/**
|
||||
* This is the primary router for your server.
|
||||
*
|
||||
@ -15,6 +16,7 @@ export const appRouter = createTRPCRouter({
|
||||
users: usersRouter,
|
||||
author: authorRouter,
|
||||
app: globalRouter,
|
||||
auth: authRouter,
|
||||
});
|
||||
|
||||
// export type definition of API
|
||||
|
||||
54
src/server/api/routers/auth.ts
Normal file
54
src/server/api/routers/auth.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { passwordSchema, userSchema } from "@/lib/validation/zod/user";
|
||||
import { createTRPCRouter, publicProcedure } from "../trpc";
|
||||
import { z } from "zod";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { users } from "@/server/db/schema";
|
||||
import argon from "argon2";
|
||||
|
||||
export const authRouter = createTRPCRouter({
|
||||
register: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
user: userSchema,
|
||||
password: passwordSchema,
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const {
|
||||
password,
|
||||
user: { email, name },
|
||||
} = input;
|
||||
// Check if user already exists
|
||||
try {
|
||||
const existingUser = await ctx.db.query.users.findFirst({
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return { success: false, message: "User already exists" };
|
||||
}
|
||||
|
||||
// Hash the password (12 is a good cost factor)
|
||||
const hashedPassword = await argon.hash(password);
|
||||
|
||||
// Create user in database
|
||||
const [user] = await ctx.db
|
||||
.insert(users)
|
||||
.values({
|
||||
name,
|
||||
email,
|
||||
password: hashedPassword,
|
||||
})
|
||||
.returning({ id: users.id });
|
||||
console.log(user);
|
||||
|
||||
if (user) {
|
||||
return { success: true, message: "User created successfully" };
|
||||
}
|
||||
return { success: false, message: "Error creating user" };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { success: false, message: "Error creating user" };
|
||||
}
|
||||
}),
|
||||
});
|
||||
@ -3,11 +3,11 @@ import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { z } from "zod";
|
||||
import { users } from "@/server/db/schema";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { userProfileSchema } from "@/lib/validation/zod/user";
|
||||
import { userSchema } from "@/lib/validation/zod/user";
|
||||
|
||||
export const usersRouter = createTRPCRouter({
|
||||
updateProfile: protectedProcedure
|
||||
.input(z.object({ profile: userProfileSchema }))
|
||||
.input(z.object({ profile: userSchema }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return await ctx.db
|
||||
.update(users)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { DrizzleAdapter } from "@auth/drizzle-adapter";
|
||||
import { type DefaultSession, type NextAuthConfig } from "next-auth";
|
||||
import DiscordProvider from "next-auth/providers/discord";
|
||||
import GoogleProvider from "next-auth/providers/google";
|
||||
|
||||
import { db } from "@/server/db";
|
||||
import {
|
||||
@ -37,9 +38,18 @@ declare module "next-auth" {
|
||||
*
|
||||
* @see https://next-auth.js.org/configuration/options
|
||||
*/
|
||||
|
||||
export const adapter = DrizzleAdapter(db, {
|
||||
usersTable: users,
|
||||
accountsTable: accounts,
|
||||
sessionsTable: sessions,
|
||||
verificationTokensTable: verificationTokens,
|
||||
}) as Adapter;
|
||||
|
||||
export const authConfig = {
|
||||
providers: [
|
||||
DiscordProvider,
|
||||
GoogleProvider,
|
||||
/**
|
||||
* ...add more providers here.
|
||||
*
|
||||
@ -50,19 +60,23 @@ export const authConfig = {
|
||||
* @see https://next-auth.js.org/providers/github
|
||||
*/
|
||||
],
|
||||
adapter: DrizzleAdapter(db, {
|
||||
usersTable: users,
|
||||
accountsTable: accounts,
|
||||
sessionsTable: sessions,
|
||||
verificationTokensTable: verificationTokens,
|
||||
}) as Adapter,
|
||||
// pages: {
|
||||
// signIn: appRoutes.signin, // Custom sign in page
|
||||
// },
|
||||
adapter,
|
||||
callbacks: {
|
||||
session: ({ session, user }) => ({
|
||||
session: ({ session, user }) => {
|
||||
return {
|
||||
...session,
|
||||
user: {
|
||||
...session.user,
|
||||
id: user.id,
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
},
|
||||
session: {
|
||||
strategy: "database",
|
||||
maxAge: 60 * 60 * 24 * 7, // 7 days,
|
||||
},
|
||||
} satisfies NextAuthConfig;
|
||||
|
||||
436
src/server/auth/credentials-provider.ts
Normal file
436
src/server/auth/credentials-provider.ts
Normal file
@ -0,0 +1,436 @@
|
||||
import { createId } from "@paralleldrive/cuid2";
|
||||
|
||||
export function generateSessionToken() {
|
||||
return createId();
|
||||
}
|
||||
export const fromDate = (time: number, date = Date.now()) => {
|
||||
return new Date(date + time * 1000);
|
||||
};
|
||||
|
||||
// CredentialsProvider({
|
||||
// name: "Credentials",
|
||||
// credentials: {
|
||||
// email: { label: "Email", type: "email" },
|
||||
// password: { label: "Password", type: "password" },
|
||||
// },
|
||||
// authorize: async (credentials) => {
|
||||
// let user: Session["user"] | null = null;
|
||||
|
||||
// if (!credentials?.email || !credentials?.password) return null;
|
||||
|
||||
// if (
|
||||
// typeof credentials.password !== "string" ||
|
||||
// typeof credentials.email !== "string"
|
||||
// ) {
|
||||
// console.log("WARN: Password or Email is not a string.");
|
||||
// return null;
|
||||
// }
|
||||
// try {
|
||||
// // Add your own database logic here
|
||||
// const response = await db.query.users.findFirst({
|
||||
// where: eq(users.email, String(credentials.email)),
|
||||
// });
|
||||
|
||||
// // No user found
|
||||
// if (!response || !response.password) {
|
||||
// if (!response?.password) return null;
|
||||
// }
|
||||
// user = response;
|
||||
// // Check password - using timing-safe comparison via bcrypt
|
||||
// const isValidPassword = await argon.verify(
|
||||
// String(response.password),
|
||||
// String(credentials?.password),
|
||||
// );
|
||||
// if (!isValidPassword) return null;
|
||||
// console.log("User authenticated successfully:", user.id);
|
||||
|
||||
// return {
|
||||
// name: user.name,
|
||||
// email: user.email,
|
||||
// image: user.image,
|
||||
// id: user.id,
|
||||
// role: user.role,
|
||||
// } as User;
|
||||
// } catch (e) {
|
||||
// console.log("WARN: Error while validating credentials.");
|
||||
// return null;
|
||||
// }
|
||||
// },
|
||||
// }),
|
||||
|
||||
// callback
|
||||
// async signIn({ user, account, profile, email, credentials }) {
|
||||
// console.log("👉 SignIn callback triggered", user?.id);
|
||||
// console.log("👉 SignIn callback credentials", credentials);
|
||||
// if (credentials && user.id) await createSession(user.id!);
|
||||
// // Return true to allow sign-in
|
||||
// return true;
|
||||
// },
|
||||
|
||||
// server action
|
||||
// export async function login(values: z.infer<typeof loginSchema>) {
|
||||
// return await signIn("credentials", values);
|
||||
// }
|
||||
// export async function register(values: z.infer<typeof registerSchema>) {
|
||||
// try {
|
||||
// const { success } = await api.auth.register({
|
||||
// user: {
|
||||
// email: values.email,
|
||||
// name: values.name,
|
||||
// },
|
||||
// password: values.password,
|
||||
// });
|
||||
// await signIn("credentials", {
|
||||
// email: values.email,
|
||||
// password: values.password,
|
||||
// });
|
||||
// return success;
|
||||
// } catch (e) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// export async function createSession(userId: string) {
|
||||
// if (!adapter.createSession) throw new Error("Adapter not initialized");
|
||||
// const sessionToken = generateSessionToken();
|
||||
// const sessionExpiry = fromDate(authConfig.session.maxAge);
|
||||
// console.log("👉 createSession", sessionToken);
|
||||
// const session = await adapter.createSession({
|
||||
// sessionToken: sessionToken,
|
||||
// userId: userId,
|
||||
// expires: sessionExpiry,
|
||||
// });
|
||||
// console.log("👉 createSession session", session);
|
||||
// const cookieStore = await cookies();
|
||||
// cookieStore.set("authjs.session-token", sessionToken, {
|
||||
// expires: sessionExpiry,
|
||||
// });
|
||||
// }
|
||||
|
||||
// register page
|
||||
// "use client";
|
||||
// import { cn } from "@/lib/utils";
|
||||
// import { Button } from "@/components/ui/button";
|
||||
// import { Card, CardContent } from "@/components/ui/card";
|
||||
// import { Input } from "@/components/ui/input";
|
||||
// import { zodResolver } from "@hookform/resolvers/zod";
|
||||
// import { useForm } from "react-hook-form";
|
||||
// import { z } from "zod";
|
||||
|
||||
// import {
|
||||
// Form,
|
||||
// FormControl,
|
||||
// FormField,
|
||||
// FormItem,
|
||||
// FormLabel,
|
||||
// FormMessage,
|
||||
// } from "@/components/ui/form";
|
||||
|
||||
// import { registerSchema } from "@/lib/validation/zod/user";
|
||||
// import { appConfig, appRoutes } from "@/config";
|
||||
// import Link from "next/link";
|
||||
// import { login, register } from "@/server/actions/auth";
|
||||
// import { toast } from "sonner";
|
||||
// import { AuthProviderList, LeagalFooter } from ".";
|
||||
|
||||
// export function RegisterForm({
|
||||
// className,
|
||||
// ...props
|
||||
// }: React.ComponentProps<"div">) {
|
||||
// const form = useForm<z.infer<typeof registerSchema>>({
|
||||
// resolver: zodResolver(registerSchema),
|
||||
// defaultValues: {
|
||||
// name: "",
|
||||
// email: "",
|
||||
// password: "",
|
||||
// confirmPassword: "",
|
||||
// },
|
||||
// });
|
||||
|
||||
// // 2. Define a submit handler.
|
||||
// async function onSubmit(values: z.infer<typeof registerSchema>) {
|
||||
// const success = await register(values);
|
||||
// if (!success) toast.error("Registrierung fehlgeschlagen");
|
||||
// form.reset();
|
||||
// }
|
||||
// return (
|
||||
// <div className={cn("flex flex-col gap-6", className)} {...props}>
|
||||
// <Card className="overflow-hidden">
|
||||
// <CardContent className="grid p-0 md:grid-cols-2">
|
||||
// <Form {...form}>
|
||||
// <form onSubmit={form.handleSubmit(onSubmit)} className="p-6 md:p-8">
|
||||
// <div className="flex flex-col gap-6">
|
||||
// <div className="flex flex-col items-center text-center">
|
||||
// <h1 className="text-2xl font-bold">Wilkommen</h1>
|
||||
// <p className="text-balance text-muted-foreground">
|
||||
// Erstelle dein {appConfig.name} Konto
|
||||
// </p>
|
||||
// </div>
|
||||
|
||||
// <AuthProviderList />
|
||||
|
||||
// <div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
||||
// <span className="relative z-10 bg-background px-2 text-muted-foreground">
|
||||
// Oder mit
|
||||
// </span>
|
||||
// </div>
|
||||
|
||||
// <div className="space-y-4">
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="name"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Name</FormLabel>
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// placeholder="Mustermax"
|
||||
// tabIndex={1}
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="email"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Email</FormLabel>
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// placeholder="email@beispiel.com"
|
||||
// tabIndex={2}
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="password"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Passwort</FormLabel>
|
||||
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// type="password"
|
||||
// tabIndex={3}
|
||||
// placeholder="******"
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="confirmPassword"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Passwort Wiederholen</FormLabel>
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// type="password"
|
||||
// tabIndex={4}
|
||||
// placeholder="******"
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// </div>
|
||||
|
||||
// <Button type="submit">Login</Button>
|
||||
|
||||
// <div className="text-center text-sm">
|
||||
// Du hast bereits ein Konto?{" "}
|
||||
// <Link
|
||||
// href={appRoutes.signin}
|
||||
// className="underline underline-offset-4"
|
||||
// >
|
||||
// Anmelden
|
||||
// </Link>
|
||||
// </div>
|
||||
// </div>
|
||||
// </form>
|
||||
// </Form>
|
||||
|
||||
// <div className="relative hidden bg-muted md:block">
|
||||
// <img
|
||||
// src="/placeholder.svg"
|
||||
// alt="Image"
|
||||
// className="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
|
||||
// />
|
||||
// </div>
|
||||
// </CardContent>
|
||||
// </Card>
|
||||
// <LeagalFooter />
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
// Login page
|
||||
|
||||
// export function LoginForm({
|
||||
// className,
|
||||
// ...props
|
||||
// }: React.ComponentProps<"div">) {
|
||||
// const form = useForm<z.infer<typeof loginSchema>>({
|
||||
// resolver: zodResolver(loginSchema),
|
||||
// defaultValues: {
|
||||
// email: "",
|
||||
// password: "",
|
||||
// },
|
||||
// });
|
||||
|
||||
// // 2. Define a submit handler.
|
||||
// async function onSubmit(values: z.infer<typeof loginSchema>) {
|
||||
// const success = await login(values);
|
||||
// // if (!success) toast.error("Login fehlgeschlagen");
|
||||
// // form.reset();
|
||||
// }
|
||||
// return (
|
||||
// <div className={cn("flex flex-col gap-6", className)} {...props}>
|
||||
// <Card className="overflow-hidden">
|
||||
// <CardContent className="grid p-0 md:grid-cols-2">
|
||||
// <Form {...form}>
|
||||
// <form onSubmit={form.handleSubmit(onSubmit)} className="p-6 md:p-8">
|
||||
// <div className="flex flex-col gap-6">
|
||||
// <div className="flex flex-col items-center text-center">
|
||||
// <h1 className="text-2xl font-bold">Wilkommen Zurück</h1>
|
||||
// <p className="text-balance text-muted-foreground">
|
||||
// Melde dich in deinem {appConfig.name} Konto an
|
||||
// </p>
|
||||
// </div>
|
||||
// <AuthProviderList />
|
||||
// <div className="relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t after:border-border">
|
||||
// <span className="relative z-10 bg-background px-2 text-muted-foreground">
|
||||
// Oder mit
|
||||
// </span>
|
||||
// </div>
|
||||
// <div className="space-y-4">
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="email"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <FormLabel>Email</FormLabel>
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// placeholder="email@beispiel.com"
|
||||
// tabIndex={1}
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// <FormField
|
||||
// control={form.control}
|
||||
// name="password"
|
||||
// render={({ field }) => (
|
||||
// <FormItem>
|
||||
// <div className="flex items-center">
|
||||
// <FormLabel>Passwort</FormLabel>
|
||||
|
||||
// <a
|
||||
// href="#"
|
||||
// className="ml-auto text-sm underline-offset-2 hover:underline"
|
||||
// >
|
||||
// passwort vergessen?
|
||||
// </a>
|
||||
// </div>
|
||||
// <FormControl>
|
||||
// <Input
|
||||
// type="password"
|
||||
// tabIndex={2}
|
||||
// placeholder="******"
|
||||
// {...field}
|
||||
// />
|
||||
// </FormControl>
|
||||
// <FormMessage />
|
||||
// </FormItem>
|
||||
// )}
|
||||
// />
|
||||
// </div>
|
||||
|
||||
// <Button type="submit">Login</Button>
|
||||
|
||||
// <div className="text-center text-sm">
|
||||
// Du hast noch kein Konto?{" "}
|
||||
// <Link
|
||||
// href={appRoutes.signup}
|
||||
// className="underline underline-offset-4"
|
||||
// >
|
||||
// Registrieren
|
||||
// </Link>
|
||||
// </div>
|
||||
// </div>
|
||||
// </form>
|
||||
// </Form>
|
||||
|
||||
// <div className="relative hidden bg-muted md:block">
|
||||
// <img
|
||||
// src="/placeholder.svg"
|
||||
// alt="Image"
|
||||
// className="absolute inset-0 h-full w-full object-cover dark:brightness-[0.2] dark:grayscale"
|
||||
// />
|
||||
// </div>
|
||||
// </CardContent>
|
||||
// </Card>
|
||||
// <LeagalFooter />
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
// export function AuthProviderList() {
|
||||
// return (
|
||||
// <div className="grid grid-cols-3 gap-4">
|
||||
// <Button
|
||||
// variant="outline"
|
||||
// className="w-full"
|
||||
// onClick={() => loginOAuth("discord")}
|
||||
// >
|
||||
// <Icons.discord />
|
||||
// <span className="sr-only">Login with Discord</span>
|
||||
// </Button>
|
||||
// <Button variant="outline" className="w-full">
|
||||
// <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
// <path
|
||||
// d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
|
||||
// fill="currentColor"
|
||||
// />
|
||||
// </svg>
|
||||
// <span className="sr-only">Login with Google</span>
|
||||
// </Button>
|
||||
// <Button variant="outline" className="w-full">
|
||||
// <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
// <path
|
||||
// d="M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z"
|
||||
// fill="currentColor"
|
||||
// />
|
||||
// </svg>
|
||||
// <span className="sr-only">Login with Meta</span>
|
||||
// </Button>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
// export function LeagalFooter() {
|
||||
// return (
|
||||
// <div className="text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary">
|
||||
// By clicking continue, you agree to our <a href="#">Terms of Service</a>{" "}
|
||||
// and <a href="#">Privacy Policy</a>.
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@ -15,7 +15,7 @@ import { User } from "next-auth";
|
||||
import { type AdapterAccount } from "next-auth/adapters";
|
||||
import { JSONContent } from "novel";
|
||||
|
||||
export const createTable = pgTableCreator((name) => `wiki-antifa_${name}`);
|
||||
export const createTable = pgTableCreator((name) => `logipedia_${name}`);
|
||||
|
||||
export const articles = createTable(
|
||||
"article",
|
||||
@ -104,6 +104,7 @@ export const users = createTable("user", {
|
||||
withTimezone: true,
|
||||
}).default(sql`CURRENT_TIMESTAMP`),
|
||||
image: varchar("image", { length: 255 }),
|
||||
password: varchar("password", { length: 255 }),
|
||||
});
|
||||
|
||||
export const usersRelations = relations(users, ({ many }) => ({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user