This commit is contained in:
nocnico
2025-07-24 21:56:16 +02:00
10 changed files with 72 additions and 29 deletions

View File

@@ -92,6 +92,11 @@ export default function AdminPanel() {
const modalRef = useRef<HTMLDialogElement>(null); const modalRef = useRef<HTMLDialogElement>(null);
console.debug("piloten von API", {
anzahl: pilots?.length,
pilots,
});
return ( return (
<div> <div>
<button <button
@@ -108,11 +113,11 @@ export default function AdminPanel() {
<form method="dialog"> <form method="dialog">
<button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button> <button className="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form> </form>
<h3 className="font-bold text-lg flex items-center gap-2"> <h3 className="flex items-center gap-2 text-lg font-bold">
<Shield size={22} /> Admin Panel <Shield size={22} /> Admin Panel
</h3> </h3>
<div className="flex gap-2 mt-4 w-full"> <div className="mt-4 flex w-full gap-2">
<div className="card bg-base-300 shadow-md w-full h-96 overflow-y-auto"> <div className="card bg-base-300 h-96 w-full overflow-y-auto shadow-md">
<div className="card-body"> <div className="card-body">
<div className="card-title flex items-center gap-2"> <div className="card-title flex items-center gap-2">
<UserCheck size={20} /> Verbundene Clients <UserCheck size={20} /> Verbundene Clients

View File

@@ -73,7 +73,10 @@ export const ProfileForm: React.FC<ProfileFormProps> = ({ user }: ProfileFormPro
className="card-body" className="card-body"
onSubmit={form.handleSubmit(async (values) => { onSubmit={form.handleSubmit(async (values) => {
if (!values.id) return; if (!values.id) return;
await editUser(values.id, values); await editUser(values.id, {
...values,
email: values.email.toLowerCase(),
});
form.reset(values); form.reset(values);
toast.success("Deine Änderungen wurden gespeichert!", { toast.success("Deine Änderungen wurden gespeichert!", {
style: { style: {

View File

@@ -91,7 +91,10 @@ export const ProfileForm = ({
className="card-body" className="card-body"
onSubmit={form.handleSubmit(async (values) => { onSubmit={form.handleSubmit(async (values) => {
setIsLoading(true); setIsLoading(true);
await updateUser(values); await updateUser({
...values,
email: values.email.toLowerCase(),
});
if (discordAccount) { if (discordAccount) {
await setStandardName({ await setStandardName({
memberId: discordAccount.discordId, memberId: discordAccount.discordId,

View File

@@ -33,7 +33,7 @@ export const Login = () => {
try { try {
const data = await signIn("credentials", { const data = await signIn("credentials", {
redirect: false, redirect: false,
email: form.getValues("email"), email: form.getValues("email").toLowerCase(),
password: form.getValues("password"), password: form.getValues("password"),
}); });
setIsLoading(false); setIsLoading(false);
@@ -62,12 +62,12 @@ export const Login = () => {
Registrierung Registrierung
</Link> </Link>
</span> </span>
<div className="alert alert-info alert-outline text-sm font-semibold text-center justify-center"> <div className="alert alert-info alert-outline justify-center text-center text-sm font-semibold">
Du warst bereits Nutzer der V1? <br /> Du warst bereits Nutzer der V1? <br />
Melde dich mit deinen alten Zugangsdaten an. Melde dich mit deinen alten Zugangsdaten an.
</div> </div>
<div className="mt-5 mb-2"> <div className="mb-2 mt-5">
<label className="input input-bordered flex items-center gap-2 w-full"> <label className="input input-bordered flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -84,7 +84,7 @@ export const Login = () => {
? form.formState.errors.email.message ? form.formState.errors.email.message
: ""} : ""}
</p> </p>
<label className="input input-bordered flex items-center gap-2 mt-2 w-full"> <label className="input input-bordered mt-2 flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -105,8 +105,8 @@ export const Login = () => {
className="grow" className="grow"
/> />
</label> </label>
<span className="text-sm font-medium flex justify-end"> <span className="flex justify-end text-sm font-medium">
<Link href="/passwort-reset" className="link link-accent link-hover "> <Link href="/passwort-reset" className="link link-accent link-hover">
Passwort vergessen? Passwort vergessen?
</Link> </Link>
</span> </span>

View File

@@ -29,7 +29,7 @@ export const PasswortReset = () => {
onSubmit={form.handleSubmit(async () => { onSubmit={form.handleSubmit(async () => {
try { try {
setIsLoading(true); setIsLoading(true);
const { error } = await resetPassword(form.getValues().email); const { error } = await resetPassword(form.getValues().email.toLowerCase());
setIsLoading(false); setIsLoading(false);
if (error) { if (error) {
@@ -56,7 +56,7 @@ export const PasswortReset = () => {
<Toaster position="top-center" reverseOrder={false} /> <Toaster position="top-center" reverseOrder={false} />
</div> </div>
<h1 className="text-3xl font-bold">Passwort zurücksetzen</h1> <h1 className="text-3xl font-bold">Passwort zurücksetzen</h1>
<label className="input input-bordered flex items-center gap-2 w-full"> <label className="input input-bordered flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -73,8 +73,8 @@ export const PasswortReset = () => {
? form.formState.errors.email.message ? form.formState.errors.email.message
: ""} : ""}
</p> </p>
<span className="text-sm font-medium flex justify-end"> <span className="flex justify-end text-sm font-medium">
<Link href="/login" className="link link-accent link-hover "> <Link href="/login" className="link link-accent link-hover">
zum Login zum Login
</Link> </Link>
</span> </span>

View File

@@ -13,7 +13,7 @@ export const resetPassword = async (email: string) => {
email, email,
}, },
}); });
const oldUser = (OLD_USER as OldUser[]).find((u) => u.email.toLowerCase() === email.toLowerCase()); const oldUser = (OLD_USER as OldUser[]).find((u) => u.email.toLowerCase() === email);
if (!user) { if (!user) {
if (oldUser) { if (oldUser) {
user = await createNewUserFromOld(oldUser); user = await createNewUserFromOld(oldUser);

View File

@@ -83,7 +83,7 @@ export const Register = () => {
setIsLoading(true); setIsLoading(true);
const values = form.getValues(); const values = form.getValues();
const user = await register({ const user = await register({
email: form.getValues("email"), email: form.getValues("email").toLowerCase(),
password: form.getValues("password"), password: form.getValues("password"),
firstname: form.getValues("firstname"), firstname: form.getValues("firstname"),
lastname: form.getValues("lastname"), lastname: form.getValues("lastname"),
@@ -116,13 +116,13 @@ export const Register = () => {
Login Login
</Link> </Link>
</span> </span>
<div className="alert alert-info alert-outline text-sm font-semibold text-center justify-center"> <div className="alert alert-info alert-outline justify-center text-center text-sm font-semibold">
Du warst bereits Nutzer der V1? <br /> Du warst bereits Nutzer der V1? <br />
Du musst keinen neuen Account erstellen, sondern kannst dich mit deinen alten Zugangsdaten Du musst keinen neuen Account erstellen, sondern kannst dich mit deinen alten Zugangsdaten
anmelden. anmelden.
</div> </div>
<div className="mt-5 mb-2"> <div className="mb-2 mt-5">
<label className="input input-bordered flex items-center gap-2 mt-2 w-full"> <label className="input input-bordered mt-2 flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -143,7 +143,7 @@ export const Register = () => {
? form.formState.errors.firstname.message ? form.formState.errors.firstname.message
: ""} : ""}
</p> </p>
<label className="input input-bordered flex items-center gap-2 mt-2 w-full"> <label className="input input-bordered mt-2 flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -165,7 +165,7 @@ export const Register = () => {
: ""} : ""}
</p> </p>
<div className="divider">Account</div> <div className="divider">Account</div>
<label className="input input-bordered flex items-center gap-2 w-full"> <label className="input input-bordered flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -183,7 +183,7 @@ export const Register = () => {
? form.formState.errors.email.message ? form.formState.errors.email.message
: ""} : ""}
</p> </p>
<label className="input input-bordered flex items-center gap-2 mt-2 w-full"> <label className="input input-bordered mt-2 flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@@ -209,7 +209,7 @@ export const Register = () => {
? form.formState.errors.password.message ? form.formState.errors.password.message
: ""} : ""}
</p> </p>
<label className="input input-bordered flex items-center gap-2 mt-2 w-full"> <label className="input input-bordered mt-2 flex w-full items-center gap-2">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"

View File

@@ -29,7 +29,9 @@ export const register = async ({ password, ...user }: Omit<Prisma.UserCreateInpu
}, },
}); });
const existingOldUser = (OLD_USER as OldUser[]).find((u) => u.email.toLocaleLowerCase() === user.email.toLocaleLowerCase()); const existingOldUser = (OLD_USER as OldUser[]).find(
(u) => u.email.toLocaleLowerCase() === user.email,
);
if (existingUser) { if (existingUser) {
return { return {

View File

@@ -18,9 +18,16 @@ export const options: AuthOptions = {
try { try {
if (!credentials) throw new Error("No credentials provided"); if (!credentials) throw new Error("No credentials provided");
const user = await prisma.user.findFirst({ const user = await prisma.user.findFirst({
where: { email: credentials.email }, where: {
email: {
contains: credentials.email,
mode: "insensitive",
},
},
}); });
const v1User = (oldUser as OldUser[]).find((u) => u.email.toLowerCase() === credentials.email.toLowerCase()); const v1User = (oldUser as OldUser[]).find(
(u) => u.email.toLowerCase() === credentials.email,
);
if (!user && v1User) { if (!user && v1User) {
if (bcrypt.compareSync(credentials.password, v1User.password)) { if (bcrypt.compareSync(credentials.password, v1User.password)) {
const newUser = await createNewUserFromOld(v1User); const newUser = await createNewUserFromOld(v1User);

View File

@@ -31,6 +31,29 @@ export interface OldUser {
} }
export const createNewUserFromOld = async (oldUser: OldUser) => { export const createNewUserFromOld = async (oldUser: OldUser) => {
const existingPublicId = await prisma.user.findFirst({
where: {
publicId: oldUser.publicId,
},
});
let varPublicId = oldUser.publicId;
if (existingPublicId) {
const lastUserPublicId = await prisma.user.findFirst({
select: {
publicId: true,
},
orderBy: {
publicId: "desc",
},
});
if (lastUserPublicId) {
const lastUserInt = parseInt(lastUserPublicId.publicId.replace("VAR", ""));
varPublicId = `VAR${(lastUserInt + 1).toString().padStart(4, "0")}`;
}
}
const newUser = await prisma.user.create({ const newUser = await prisma.user.create({
data: { data: {
email: oldUser.email, email: oldUser.email,
@@ -38,7 +61,7 @@ export const createNewUserFromOld = async (oldUser: OldUser) => {
migratedFromV1: true, migratedFromV1: true,
firstname: oldUser.firstname, firstname: oldUser.firstname,
lastname: oldUser.lastname, lastname: oldUser.lastname,
publicId: oldUser.publicId, publicId: varPublicId,
badges: [ badges: [
...oldUser.badges ...oldUser.badges
.map((badge) => { .map((badge) => {