Fixed type errors in nextJS apps, added Docker files

Co-authored-by: Nicolas <nocnico@users.noreply.github.com>
This commit is contained in:
PxlLoewe
2025-05-24 14:12:58 -07:00
parent 5187ed194c
commit 00e432814a
24 changed files with 334 additions and 258 deletions

View File

@@ -0,0 +1,6 @@
node_modules
Dockerfile
.dockerignore
nodemon.json
.env
.env.example

View File

@@ -0,0 +1,29 @@
FROM node:22-alpine
# Set the working directory
WORKDIR /usr/app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Change ownership to the non-root user
RUN chown -R node:node /usr/app
# Copy the rest of the application code
COPY . .
# Build the application
RUN npm run build
# Expose the application port
EXPOSE 3002
# Run container as non-root (unprivileged) user
# The "node" user is provided in the Node.js Alpine base image
USER node
# Command to run the application
CMD ["node", "index.js"]

View File

@@ -0,0 +1,7 @@
node_modules
Dockerfile
.dockerignore
.eslint.config.msj
.README.md
.env
.env.example

29
apps/dispatch/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM node:22-alpine
# Set the working directory
WORKDIR /usr/app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Change ownership to the non-root user
RUN chown -R node:node /usr/app
# Copy the rest of the application code
COPY . .
# Build the application
RUN npm run build
# Expose the application port
EXPOSE 3001
# Run container as non-root (unprivileged) user
# The "node" user is provided in the Node.js Alpine base image
USER node
# Command to run the application
CMD ["npm", "start"]

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { usePilotConnectionStore } from "../../../_store/pilot/connectionStore"; import { usePilotConnectionStore } from "_store/pilot/connectionStore";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { getStationsAPI } from "querys/stations"; import { getStationsAPI } from "querys/stations";

View File

@@ -0,0 +1,6 @@
node_modules
Dockerfile
.dockerignore
nodemon.json
.env
.env.example

View File

@@ -0,0 +1,31 @@
FROM node:22-alpine
ENV NODE_ENV=production
# Set the working directory
WORKDIR /usr/app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Change ownership to the non-root user
RUN chown -R node:node /usr/app
# Copy the rest of the application code
COPY . .
# Build the application
RUN npm run build
# Expose the application port
EXPOSE 3003
# Run container as non-root (unprivileged) user
# The "node" user is provided in the Node.js Alpine base image
USER node
# Command to run the application
CMD ["node", "index.js"]

View File

@@ -0,0 +1,8 @@
import { Event, Participant } from "@repo/db";
export const eventCompleted = (event: Event, participant?: Participant) => {
if (!participant) return false;
if (event.finisherMoodleCourseId && !participant.finisherMoodleCurseCompleted) return false;
if (event.hasPresenceEvents && !participant.attended) return false;
return true;
};

View File

@@ -1,9 +1,9 @@
import { getMoodleCourseCompletionStatus, getMoodleUserById } from "./moodle"; import { getMoodleCourseCompletionStatus, getMoodleUserById } from "./moodle";
import { CronJob } from "cron"; import { CronJob } from "cron";
import { prisma } from "@repo/db"; import { prisma } from "@repo/db";
import { eventCompleted } from "@repo/ui/helper";
import { sendCourseCompletedEmail } from "modules/mail"; import { sendCourseCompletedEmail } from "modules/mail";
import { handleParticipantFinished } from "modules/event"; import { handleParticipantFinished } from "modules/event";
import { eventCompleted } from "helper/events";
const syncMoodleIds = async () => { const syncMoodleIds = async () => {
try { try {

8
apps/hub/.dockerignore Normal file
View File

@@ -0,0 +1,8 @@
node_modules
Dockerfile
.dockerignore
.gitignore
.eslint.config.msj
.README.md
.env
.env.example

29
apps/hub/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM node:22-alpine
# Set the working directory
WORKDIR /usr/app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install dependencies
RUN npm install
# Change ownership to the non-root user
RUN chown -R node:node /usr/app
# Copy the rest of the application code
COPY . .
# Build the application
RUN npm run build
# Expose the application port
EXPOSE 3000
# Run container as non-root (unprivileged) user
# The "node" user is provided in the Node.js Alpine base image
USER node
# Command to run the application
CMD ["npm", "start"]

View File

@@ -1,7 +1,7 @@
import { prisma } from "@repo/db"; import { prisma } from "@repo/db";
import { Form } from "../_components/Form"; import { Form } from "../_components/Form";
export default async ({ params }: { params: Promise<{ id: string }> }) => { export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params; const { id } = await params;
const event = await prisma.event.findUnique({ const event = await prisma.event.findUnique({
where: { where: {
@@ -10,4 +10,4 @@ export default async ({ params }: { params: Promise<{ id: string }> }) => {
}); });
if (!event) return <div>Event not found</div>; if (!event) return <div>Event not found</div>;
return <Form event={event} />; return <Form event={event} />;
}; }

View File

@@ -1,34 +1,21 @@
import { DateInput } from "../../../../_components/ui/DateInput"; import { Event, Participant } from "@repo/db";
import { zodResolver } from "@hookform/resolvers/zod"; import { EventAppointmentOptionalDefaults } from "@repo/db/zod";
import { Event, Participant, Prisma } from "@repo/db";
import {
EventAppointmentOptionalDefaults,
EventAppointmentOptionalDefaultsSchema,
ParticipantOptionalDefaultsSchema,
} from "@repo/db/zod";
import { useSession } from "next-auth/react";
import { Controller, useForm, UseFormReturn } from "react-hook-form";
import { deleteAppoinement, upsertAppointment } from "../action";
import { Button } from "../../../../_components/ui/Button";
import {
PaginatedTable,
PaginatedTableRef,
} from "../../../../_components/PaginatedTable";
import { Ref, RefObject, useRef } from "react";
import { CellContext } from "@tanstack/react-table"; import { CellContext } from "@tanstack/react-table";
import { useSession } from "next-auth/react";
import { RefObject, useRef } from "react";
import { UseFormReturn } from "react-hook-form";
import { PaginatedTable, PaginatedTableRef } from "../../../../_components/PaginatedTable";
import { Button } from "../../../../_components/ui/Button";
import { DateInput } from "../../../../_components/ui/DateInput";
import { upsertParticipant } from "../../../events/actions"; import { upsertParticipant } from "../../../events/actions";
import { Switch } from "../../../../_components/ui/Switch"; import { deleteAppoinement, upsertAppointment } from "../action";
interface AppointmentModalProps { interface AppointmentModalProps {
event?: Event; event?: Event;
ref: RefObject<HTMLDialogElement | null>; ref: RefObject<HTMLDialogElement | null>;
participantModal: RefObject<HTMLDialogElement | null>; participantModal: RefObject<HTMLDialogElement | null>;
appointmentsTableRef: React.RefObject<PaginatedTableRef>; appointmentsTableRef: React.RefObject<PaginatedTableRef | null>;
appointmentForm: UseFormReturn< appointmentForm: UseFormReturn<EventAppointmentOptionalDefaults, any, undefined>;
EventAppointmentOptionalDefaults,
any,
undefined
>;
participantForm: UseFormReturn<Participant, any, undefined>; participantForm: UseFormReturn<Participant, any, undefined>;
} }
@@ -56,9 +43,7 @@ export const AppointmentModal = ({
</button> </button>
</form> </form>
<h3 className="font-bold text-lg"> <h3 className="font-bold text-lg">Termin {appointmentForm.watch("id")}</h3>
Termin {appointmentForm.watch("id")}
</h3>
<form <form
onSubmit={appointmentForm.handleSubmit(async (values) => { onSubmit={appointmentForm.handleSubmit(async (values) => {
if (!event) return; if (!event) return;
@@ -101,13 +86,7 @@ export const AppointmentModal = ({
accessorKey: "enscriptionDate", accessorKey: "enscriptionDate",
header: "Einschreibedatum", header: "Einschreibedatum",
cell: ({ row }: CellContext<Participant, any>) => { cell: ({ row }: CellContext<Participant, any>) => {
return ( return <span>{new Date(row.original.enscriptionDate).toLocaleString()}</span>;
<span>
{new Date(
row.original.enscriptionDate,
).toLocaleString()}
</span>
);
}, },
}, },
{ {
@@ -116,11 +95,7 @@ export const AppointmentModal = ({
if (row.original.attended) { if (row.original.attended) {
return <span className="text-green-500">Ja</span>; return <span className="text-green-500">Ja</span>;
} else if (row.original.appointmentCancelled) { } else if (row.original.appointmentCancelled) {
return ( return <span className="text-red-500">Nein (Termin abgesagt)</span>;
<span className="text-red-500">
Nein (Termin abgesagt)
</span>
);
} else { } else {
return <span>?</span>; return <span>?</span>;
} }
@@ -159,33 +134,32 @@ export const AppointmentModal = ({
Anwesend Anwesend
</button> </button>
)} )}
{!row.original.appointmentCancelled && {!row.original.appointmentCancelled && event?.hasPresenceEvents && (
event?.hasPresenceEvents && ( <button
<button type="button"
type="button" onSubmit={() => {}}
onSubmit={() => {}} onClick={async () => {
onClick={async () => { await upsertParticipant({
await upsertParticipant({ eventId: event!.id,
eventId: event!.id, userId: row.original.userId,
userId: row.original.userId, attended: false,
attended: false, appointmentCancelled: true,
appointmentCancelled: true, statusLog: [
statusLog: [ ...(row.original.statusLog as any),
...(row.original.statusLog as any), {
{ event: "Gefehlt an Event",
event: "Gefehlt an Event", timestamp: new Date().toISOString(),
timestamp: new Date().toISOString(), user: `${session?.user?.firstname} ${session?.user?.lastname} - ${session?.user?.publicId}`,
user: `${session?.user?.firstname} ${session?.user?.lastname} - ${session?.user?.publicId}`, },
}, ],
], });
}); participantTableRef.current?.refresh();
participantTableRef.current?.refresh(); }}
}} className="btn btn-outline btn-error btn-sm"
className="btn btn-outline btn-error btn-sm" >
> abwesend
abwesend </button>
</button> )}
)}
</div> </div>
); );
}, },

View File

@@ -1,51 +1,42 @@
"use client"; "use client";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { BADGES, Event, EVENT_TYPE, Participant, PERMISSION, User } from "@repo/db";
import { import {
EventAppointmentOptionalDefaults, EventAppointmentOptionalDefaults,
EventAppointmentOptionalDefaultsSchema, EventAppointmentOptionalDefaultsSchema,
EventOptionalDefaults, EventOptionalDefaults,
EventOptionalDefaultsSchema, EventOptionalDefaultsSchema,
ParticipantOptionalDefaultsSchema, ParticipantSchema,
} from "@repo/db/zod"; } from "@repo/db/zod";
import { Controller, set, useForm } from "react-hook-form"; import { Bot, Calendar, FileText, UserIcon } from "lucide-react";
import {
BADGES,
Event,
EVENT_TYPE,
Participant,
PERMISSION,
prisma,
Prisma,
} from "@repo/db";
import { Bot, Calendar, FileText, User, UserIcon } from "lucide-react";
import { Input } from "../../../../_components/ui/Input";
import { useRef, useState } from "react";
import {
deleteAppoinement,
deleteEvent,
upsertAppointment,
upsertEvent,
} from "../action";
import { Button } from "../../../../_components/ui/Button";
import { redirect, useRouter } from "next/navigation";
import { Switch } from "../../../../_components/ui/Switch";
import DatePicker, { registerLocale } from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import {
PaginatedTable,
PaginatedTableRef,
} from "../../../../_components/PaginatedTable";
import { Select } from "../../../../_components/ui/Select";
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { redirect } from "next/navigation";
import { useRef, useState } from "react";
import "react-datepicker/dist/react-datepicker.css";
import { useForm } from "react-hook-form";
import { PaginatedTable, PaginatedTableRef } from "../../../../_components/PaginatedTable";
import { Button } from "../../../../_components/ui/Button";
import { Input } from "../../../../_components/ui/Input";
import { MarkdownEditor } from "../../../../_components/ui/MDEditor"; import { MarkdownEditor } from "../../../../_components/ui/MDEditor";
import { Select } from "../../../../_components/ui/Select";
import { Switch } from "../../../../_components/ui/Switch";
import { deleteEvent, upsertEvent } from "../action";
import { AppointmentModal } from "./AppointmentModal"; import { AppointmentModal } from "./AppointmentModal";
import { ParticipantModal } from "./ParticipantModal"; import { ParticipantModal } from "./ParticipantModal";
import { ColumnDef } from "@tanstack/react-table";
export const Form = ({ event }: { event?: Event }) => { export const Form = ({ event }: { event?: Event }) => {
const { data: session } = useSession(); const { data: session } = useSession();
const form = useForm({ const form = useForm<EventOptionalDefaults>({
resolver: zodResolver(EventOptionalDefaultsSchema), resolver: zodResolver(EventOptionalDefaultsSchema),
defaultValues: event, defaultValues: event
? {
...event,
discordRoleId: event.discordRoleId ?? undefined,
maxParticipants: event.maxParticipants ?? undefined,
finisherMoodleCourseId: event.finisherMoodleCourseId ?? undefined,
}
: undefined,
}); });
const appointmentForm = useForm<EventAppointmentOptionalDefaults>({ const appointmentForm = useForm<EventAppointmentOptionalDefaults>({
resolver: zodResolver(EventAppointmentOptionalDefaultsSchema), resolver: zodResolver(EventAppointmentOptionalDefaultsSchema),
@@ -55,7 +46,7 @@ export const Form = ({ event }: { event?: Event }) => {
}, },
}); });
const participantForm = useForm<Participant>({ const participantForm = useForm<Participant>({
resolver: zodResolver(ParticipantOptionalDefaultsSchema), resolver: zodResolver(ParticipantSchema),
}); });
const appointmentsTableRef = useRef<PaginatedTableRef>(null); const appointmentsTableRef = useRef<PaginatedTableRef>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -73,10 +64,7 @@ export const Form = ({ event }: { event?: Event }) => {
appointmentsTableRef={appointmentsTableRef} appointmentsTableRef={appointmentsTableRef}
event={event} event={event}
/> />
<ParticipantModal <ParticipantModal participantForm={participantForm} ref={participantModal} />
participantForm={participantForm}
ref={participantModal}
/>
<form <form
onSubmit={form.handleSubmit(async (values) => { onSubmit={form.handleSubmit(async (values) => {
setLoading(true); setLoading(true);
@@ -155,11 +143,7 @@ export const Form = ({ event }: { event?: Event }) => {
value: key, value: key,
}))} }))}
/> />
<Switch <Switch form={form} name="hasPresenceEvents" label="Hat Live Event" />
form={form}
name="hasPresenceEvents"
label="Hat Live Event"
/>
</div> </div>
</div> </div>
{form.watch("hasPresenceEvents") ? ( {form.watch("hasPresenceEvents") ? (
@@ -196,58 +180,61 @@ export const Form = ({ event }: { event?: Event }) => {
Presenter: true, Presenter: true,
Participants: true, Participants: true,
}} }}
columns={[ columns={
{ [
header: "Datum", {
accessorKey: "appointmentDate", header: "Datum",
accessorFn: (date) => accessorKey: "appointmentDate",
new Date(date.appointmentDate).toLocaleString(), accessorFn: (date) => new Date(date.appointmentDate).toLocaleString(),
},
{
header: "Presenter",
accessorKey: "presenter",
cell: ({ row }) => (
<div className="flex items-center">
<span className="ml-2">
{(row.original as any).Presenter.firstname}{" "}
{(row.original as any).Presenter.lastname}
</span>
</div>
),
},
{
header: "Teilnehmer",
accessorKey: "Participants",
cell: ({ row }) => (
<div className="flex items-center">
<UserIcon className="w-5 h-5" />
<span className="ml-2">
{row.original.Participants.length}
</span>
</div>
),
},
{
header: "Aktionen",
cell: ({ row }) => {
return (
<div className="flex gap-2">
<button
onSubmit={() => false}
type="button"
onClick={() => {
appointmentForm.reset(row.original);
appointmentModal.current?.showModal();
}}
className="btn btn-sm btn-outline"
>
Bearbeiten
</button>
</div>
);
}, },
}, {
]} header: "Presenter",
accessorKey: "presenter",
cell: ({ row }) => (
<div className="flex items-center">
<span className="ml-2">
{row.original.Presenter.firstname} {row.original.Presenter.lastname}
</span>
</div>
),
},
{
header: "Teilnehmer",
accessorKey: "Participants",
cell: ({ row }) => (
<div className="flex items-center">
<UserIcon className="w-5 h-5" />
<span className="ml-2">{row.original.Participants.length}</span>
</div>
),
},
{
header: "Aktionen",
cell: ({ row }) => {
return (
<div className="flex gap-2">
<button
onSubmit={() => false}
type="button"
onClick={() => {
appointmentForm.reset(row.original);
appointmentModal.current?.showModal();
}}
className="btn btn-sm btn-outline"
>
Bearbeiten
</button>
</div>
);
},
},
] as ColumnDef<
EventAppointmentOptionalDefaults & {
Presenter: User;
Participants: Participant[];
}
>[]
}
/> />
</div> </div>
</div> </div>
@@ -311,11 +298,7 @@ export const Form = ({ event }: { event?: Event }) => {
<div className="card bg-base-200 shadow-xl col-span-6"> <div className="card bg-base-200 shadow-xl col-span-6">
<div className="card-body "> <div className="card-body ">
<div className="flex w-full gap-4"> <div className="flex w-full gap-4">
<Button <Button isLoading={loading} type="submit" className="btn btn-primary flex-1">
isLoading={loading}
type="submit"
className="btn btn-primary flex-1"
>
Speichern Speichern
</Button> </Button>
{event && ( {event && (

View File

@@ -1,7 +1,7 @@
import { prisma } from "@repo/db"; import { prisma } from "@repo/db";
import { KeywordForm } from "../_components/Form"; import { KeywordForm } from "../_components/Form";
export default async ({ params }: { params: Promise<{ id: string }> }) => { export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params; const { id } = await params;
const keyword = await prisma.keyword.findUnique({ const keyword = await prisma.keyword.findUnique({
where: { where: {
@@ -10,4 +10,4 @@ export default async ({ params }: { params: Promise<{ id: string }> }) => {
}); });
if (!keyword) return <div>Station not found</div>; if (!keyword) return <div>Station not found</div>;
return <KeywordForm keyword={keyword} />; return <KeywordForm keyword={keyword} />;
}; }

View File

@@ -1,16 +1,9 @@
import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; import { ExclamationTriangleIcon } from "@radix-ui/react-icons";
import { prisma } from "@repo/db"; import { prisma } from "@repo/db";
import { Error } from "_components/Error"; import { Error } from "_components/Error";
import { import { ReportAdmin, ReportSenderInfo } from "(app)/admin/report/_components/form";
ReportAdmin,
ReportSenderInfo,
} from "(app)/admin/report/_components/form";
export default async function ReportDetailsPage({ export default async function Page({ params }: { params: Promise<{ id: string }> }) {
params,
}: {
params: { id: string };
}) {
const { id } = await params; const { id } = await params;
const report = await prisma.report.findUnique({ const report = await prisma.report.findUnique({

View File

@@ -1,13 +1,13 @@
import { prisma } from '@repo/db'; import { prisma } from "@repo/db";
import { StationForm } from '../_components/Form'; import { StationForm } from "../_components/Form";
export default async ({ params }: { params: Promise<{ id: string }> }) => { export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params; const { id } = await params;
const station = await prisma.station.findUnique({ const station = await prisma.station.findUnique({
where: { where: {
id: parseInt(id), id: parseInt(id),
}, },
}); });
if (!station) return <div>Station not found</div>; if (!station) return <div>Station not found</div>;
return <StationForm station={station} />; return <StationForm station={station} />;
}; }

View File

@@ -1,14 +1,9 @@
import { PersonIcon } from "@radix-ui/react-icons"; import { PersonIcon } from "@radix-ui/react-icons";
import { prisma, User } from "@repo/db"; import { prisma, User } from "@repo/db";
import { import { AdminForm, ConnectionHistory, ProfileForm, UserReports } from "./_components/forms";
AdminForm,
ConnectionHistory,
ProfileForm,
UserReports,
} from "./_components/forms";
import { Error } from "../../../../_components/Error"; import { Error } from "../../../../_components/Error";
const Page = async ({ params }: { params: { id: string } }) => { export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params; const { id } = await params;
const user: User | null = await prisma.user.findUnique({ const user: User | null = await prisma.user.findUnique({
@@ -107,12 +102,7 @@ const Page = async ({ params }: { params: { id: string } }) => {
<ProfileForm user={user} /> <ProfileForm user={user} />
</div> </div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3"> <div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
<AdminForm <AdminForm user={user} dispoTime={dispoTime} pilotTime={pilotTime} reports={reports} />
user={user}
dispoTime={dispoTime}
pilotTime={pilotTime}
reports={reports}
/>
</div> </div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6"> <div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-6">
<UserReports user={user} /> <UserReports user={user} />
@@ -122,6 +112,4 @@ const Page = async ({ params }: { params: { id: string } }) => {
</div> </div>
</div> </div>
); );
}; }
export default Page;

View File

@@ -18,7 +18,7 @@ Aktive Events / Mandatory Events
export default async function Home({ export default async function Home({
searchParams, searchParams,
}: { }: {
searchParams: { stats?: "pilot" | "dispo" }; searchParams: Promise<{ stats?: "pilot" | "dispo" }>;
}) { }) {
const { stats } = await searchParams; const { stats } = await searchParams;
const view = stats || "pilot"; const view = stats || "pilot";
@@ -33,10 +33,7 @@ export default async function Home({
<span className="card-title"> <span className="card-title">
<NotebookText className="w-4 h-4" /> Logbook <NotebookText className="w-4 h-4" /> Logbook
</span> </span>
<Link <Link className="badge badge-sm badge-info badge-outline" href="/logbook">
className="badge badge-sm badge-info badge-outline"
href="/logbook"
>
Zum vollständigen Logbook <ArrowRight className="w-4 h-4" /> Zum vollständigen Logbook <ArrowRight className="w-4 h-4" />
</Link> </Link>
</h2> </h2>

View File

@@ -3,7 +3,7 @@ import { getServerSession } from "../../api/auth/[...nextauth]/auth";
import { ProfileForm, SocialForm, PasswordForm, PilotForm } from "./_components/forms"; import { ProfileForm, SocialForm, PasswordForm, PilotForm } from "./_components/forms";
import { GearIcon } from "@radix-ui/react-icons"; import { GearIcon } from "@radix-ui/react-icons";
export const page = async () => { export default async function Page() {
const session = await getServerSession(); const session = await getServerSession();
if (!session) return null; if (!session) return null;
const user = await prisma.user.findFirst({ const user = await prisma.user.findFirst({
@@ -37,6 +37,4 @@ export const page = async () => {
</div> </div>
</div> </div>
); );
}; }
export default page;

View File

@@ -1,48 +1,20 @@
import { services } from "../../../helper/authServices";
import { Authorize } from "./_components/Authorize"; import { Authorize } from "./_components/Authorize";
export const services = [
{
id: "1",
service: "dispatch",
name: "Leitstellendisposition",
approvedUrls: ["http://localhost:3001"],
},
{
id: "2",
secret: "jp2k430fnv",
service: "desktop",
name: "Desktop client",
approvedUrls: ["var://oAuth"],
},
{
id: "3",
secret: "d0f3e4e4",
service: "moodle",
name: "Moodle",
approvedUrls: [
"http://localhost:8081",
"https://moodle.virtualairrescue.com",
],
},
];
export type Service = (typeof services)[number]; export type Service = (typeof services)[number];
const Page = async ({ export default async function Page({
searchParams, searchParams,
}: { }: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>; searchParams: Promise<{ client_id: string; service: string }>;
}) => { }) {
const { service: serviceId, client_id: clientId } = await searchParams; const { service: serviceId, client_id: clientId } = await searchParams;
const service = services.find( const service = services.find((service) => service.id === serviceId || service.id === clientId);
(service) => service.id === serviceId || service.id === clientId,
);
if (!service) { if (!service) {
return <div>Service not found</div>; return <div>Service not found</div>;
} }
return <Authorize service={service} />; return <Authorize service={service} />;
}; }
export default Page;

View File

@@ -1,15 +1,11 @@
import { NextRequest } from "next/server"; import { NextRequest } from "next/server";
import { sign } from "jsonwebtoken"; import { sign } from "jsonwebtoken";
import { services } from "(auth)/oauth/page";
import { prisma } from "@repo/db"; import { prisma } from "@repo/db";
import { services } from "../../../../helper/authServices";
export const POST = async (req: NextRequest) => { export const POST = async (req: NextRequest) => {
try { try {
if ( if (!req.headers.get("content-type")?.includes("application/x-www-form-urlencoded")) {
!req.headers
.get("content-type")
?.includes("application/x-www-form-urlencoded")
) {
return new Response("Unsupported Content-Type", { status: 415 }); return new Response("Unsupported Content-Type", { status: 415 });
} }

View File

@@ -0,0 +1,22 @@
export const services = [
{
id: "1",
service: "dispatch",
name: "Leitstellendisposition",
approvedUrls: ["http://localhost:3001"],
},
{
id: "2",
secret: "jp2k430fnv",
service: "desktop",
name: "Desktop client",
approvedUrls: ["var://oAuth"],
},
{
id: "3",
secret: "d0f3e4e4",
service: "moodle",
name: "Moodle",
approvedUrls: ["http://localhost:8081", "https://moodle.virtualairrescue.com"],
},
];

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://turbo.build/schema.json", "$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"], "globalDependencies": ["**/.env.*local"],
"globalEnv": ["EMAIL_SERVER", "EMAIL_FROM", "SECRET"], "globalEnv": ["EMAIL_SERVER", "EMAIL_FROM", "SECRET", "DATABASE_URL", "NEXTAUTH_SECRET"],
"ui": "tui", "ui": "tui",
"tasks": { "tasks": {
"generate": { "generate": {
@@ -15,7 +15,7 @@
"build": { "build": {
"dependsOn": ["^build", "generate", "migrate"], "dependsOn": ["^build", "generate", "migrate"],
"inputs": ["$TURBO_DEFAULT$", ".env*"], "inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"] "outputs": [".next/**", "!.next/cache/**", "dist/**"]
}, },
"lint": { "lint": {
"dependsOn": ["^lint"] "dependsOn": ["^lint"]