fixed moodle logic
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
HUB_SERVER_PORT=3003
|
HUB_SERVER_PORT=3003
|
||||||
MOODLE_TOKEN=ac346f0324647b68488d13fd52a9bbe8
|
MOODLE_API_TOKEN=ac346f0324647b68488d13fd52a9bbe8
|
||||||
NEXT_PUBLIC_HUB_URL=http://localhost:3000
|
NEXT_PUBLIC_HUB_URL=http://localhost:3000
|
||||||
MOODLE_URL=http://localhost:8081
|
MOODLE_URL=http://localhost:8081
|
||||||
|
NEXT_PUBLIC_MOODLE_URL=
|
||||||
MAIL_SERVER="asmtp.mail.hostpoint.ch"
|
MAIL_SERVER="asmtp.mail.hostpoint.ch"
|
||||||
MAIL_USER="noreply@virtualairrescue.com"
|
MAIL_USER="noreply@virtualairrescue.com"
|
||||||
MAIL_PASSWORD="b7316PB8aDPCC%-&"
|
MAIL_PASSWORD="b7316PB8aDPCC%-&"
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ export const getMoodleUserById = async (id: string) => {
|
|||||||
const { data: user } = await axios.get(
|
const { data: user } = await axios.get(
|
||||||
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
||||||
{
|
{
|
||||||
|
auth: {
|
||||||
|
username: "moodleuser",
|
||||||
|
password: "Xo1SXaLYBa7Yb6WW",
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
wstoken: process.env.MOODLE_TOKEN,
|
wstoken: process.env.MOODLE_API_TOKEN,
|
||||||
wsfunction: "core_user_get_users_by_field",
|
wsfunction: "core_user_get_users_by_field",
|
||||||
moodlewsrestformat: "json",
|
moodlewsrestformat: "json",
|
||||||
field: "idnumber",
|
field: "idnumber",
|
||||||
@@ -33,8 +37,12 @@ export const getMoodleQuizResult = async (userId: string, quizId: string) => {
|
|||||||
const { data: quizzes } = await axios.get(
|
const { data: quizzes } = await axios.get(
|
||||||
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
||||||
{
|
{
|
||||||
|
auth: {
|
||||||
|
username: "moodleuser",
|
||||||
|
password: "Xo1SXaLYBa7Yb6WW",
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
wstoken: process.env.MOODLE_TOKEN,
|
wstoken: process.env.MOODLE_API_TOKEN,
|
||||||
wsfunction: "mod_quiz_get_user_attempts",
|
wsfunction: "mod_quiz_get_user_attempts",
|
||||||
moodlewsrestformat: "json",
|
moodlewsrestformat: "json",
|
||||||
quizid: quizId,
|
quizid: quizId,
|
||||||
@@ -49,8 +57,12 @@ export const getMoodleCourseCompletionStatus = async (userId: string, courseId:
|
|||||||
const { data: completionStatus } = await axios.get(
|
const { data: completionStatus } = await axios.get(
|
||||||
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
||||||
{
|
{
|
||||||
|
auth: {
|
||||||
|
username: "moodleuser",
|
||||||
|
password: "Xo1SXaLYBa7Yb6WW",
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
wstoken: process.env.MOODLE_TOKEN,
|
wstoken: process.env.MOODLE_API_TOKEN,
|
||||||
wsfunction: "core_completion_get_course_completion_status",
|
wsfunction: "core_completion_get_course_completion_status",
|
||||||
moodlewsrestformat: "json",
|
moodlewsrestformat: "json",
|
||||||
userid: userId,
|
userid: userId,
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ router.post("/handle-participant-finished", async (req, res) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log("Handeling Participant-completed", participant?.User.publicId);
|
|
||||||
if (!participant) {
|
if (!participant) {
|
||||||
res.status(404).json({ error: "Participant not found" });
|
res.status(404).json({ error: "Participant not found" });
|
||||||
return;
|
return;
|
||||||
@@ -62,11 +61,16 @@ router.post("/check-moodle-results", async (req, res) => {
|
|||||||
res.status(400).json({ error: "Teilnehmer hat keine Moodle-ID" });
|
res.status(400).json({ error: "Teilnehmer hat keine Moodle-ID" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const quizzResult = await getMoodleCourseCompletionStatus(
|
const courseStatus = await getMoodleCourseCompletionStatus(
|
||||||
participant.User.moodleId.toString(),
|
participant.User.moodleId.toString(),
|
||||||
participant.Event.finisherMoodleCourseId!,
|
participant.Event.finisherMoodleCourseId!,
|
||||||
);
|
);
|
||||||
if (quizzResult?.completionstatus?.completed === true) {
|
|
||||||
|
if (courseStatus?.completionstatus?.completed === true) {
|
||||||
|
prisma.participant.update({
|
||||||
|
where: { id: participant.id },
|
||||||
|
data: { finisherMoodleCurseCompleted: true },
|
||||||
|
});
|
||||||
await handleParticipantFinished(participant.Event, participant, participant.User);
|
await handleParticipantFinished(participant.Event, participant, participant.User);
|
||||||
res
|
res
|
||||||
.status(200)
|
.status(200)
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ DISCORD_BOT_TOKEN=
|
|||||||
NEXT_PUBLIC_DISCORD_URL=
|
NEXT_PUBLIC_DISCORD_URL=
|
||||||
DISCORD_REDIRECT=
|
DISCORD_REDIRECT=
|
||||||
MOODLE_PW=var-api-user-P1
|
MOODLE_PW=var-api-user-P1
|
||||||
MOODLE_TOKEN=ac346f0324647b68488d13fd52a9bbe8
|
MOODLE_API_TOKEN=ac346f0324647b68488d13fd52a9bbe8
|
||||||
NEXT_PUBLIC_MOODLE_URL=http://localhost:8081
|
NEXT_PUBLIC_MOODLE_URL=http://localhost:8081
|
||||||
NEXT_PUBLIC_DISPATCH_URL=http://localhost:3001
|
NEXT_PUBLIC_DISPATCH_URL=http://localhost:3001
|
||||||
@@ -62,15 +62,6 @@ export const AppointmentModal = ({
|
|||||||
timeCaption="Uhrzeit"
|
timeCaption="Uhrzeit"
|
||||||
showTimeCaption
|
showTimeCaption
|
||||||
/>
|
/>
|
||||||
{/* <Input
|
|
||||||
form={appointmentForm}
|
|
||||||
type="datetime-local"
|
|
||||||
label="Datum"
|
|
||||||
name="appointmentDate"
|
|
||||||
formOptions={{
|
|
||||||
valueAsDate: true,
|
|
||||||
}}
|
|
||||||
/> */}
|
|
||||||
<div>
|
<div>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
hide={appointmentForm.watch("id") === undefined}
|
hide={appointmentForm.watch("id") === undefined}
|
||||||
|
|||||||
@@ -55,23 +55,28 @@ export const ParticipantModal = ({ participantForm, ref }: ParticipantModalProps
|
|||||||
<Button
|
<Button
|
||||||
className="btn-sm"
|
className="btn-sm"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
try {
|
||||||
if (!participantForm.watch("id")) return;
|
if (!participantForm.watch("id")) return;
|
||||||
|
|
||||||
const participant = participantForm.getValues();
|
const participant = participantForm.getValues();
|
||||||
await handleParticipantFinished(participant.id.toString()).catch((e) => {
|
await handleParticipantFinished(participant.id.toString()).catch((e) => {
|
||||||
const error = e as AxiosError;
|
const error = e as AxiosError;
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.success("Workflow erfolgreich ausgeführt");
|
||||||
|
router.refresh();
|
||||||
|
} catch (error) {
|
||||||
|
const e = error as AxiosError;
|
||||||
if (
|
if (
|
||||||
error.response?.data &&
|
e.response?.data &&
|
||||||
typeof error.response.data === "object" &&
|
typeof e.response.data === "object" &&
|
||||||
"error" in error.response.data
|
"error" in e.response.data
|
||||||
) {
|
) {
|
||||||
toast.error(`Fehler: ${error.response.data.error}`);
|
toast.error(`Fehler: ${e.response.data.error}`);
|
||||||
} else {
|
} else {
|
||||||
toast.error("Unbekannter Fehler beim ausführen des Workflows");
|
toast.error("Unbekannter Fehler beim ausführen des Workflows");
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
toast.success("Workflow erfolgreich ausgeführt");
|
|
||||||
router.refresh();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Event-abgeschlossen Workflow ausführen
|
Event-abgeschlossen Workflow ausführen
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ export const ProfileForm: React.FC<ProfileFormProps> = ({ user }: ProfileFormPro
|
|||||||
form={form}
|
form={form}
|
||||||
name="permissions"
|
name="permissions"
|
||||||
label="Permissions"
|
label="Permissions"
|
||||||
isDisabled={user.permissions.length > (session.data?.user?.permissions?.length ?? 0)}
|
isDisabled={!session.data?.user.permissions.includes("ADMIN_USER_ADVANCED")}
|
||||||
options={Object.entries(PERMISSION).map(([key, value]) => ({
|
options={Object.entries(PERMISSION).map(([key, value]) => ({
|
||||||
label: value,
|
label: value,
|
||||||
value: key,
|
value: key,
|
||||||
@@ -325,6 +325,7 @@ export const ConnectionHistory: React.FC<{ user: User }> = ({ user }: { user: Us
|
|||||||
export const UserPenalties = ({ user }: { user: User }) => {
|
export const UserPenalties = ({ user }: { user: User }) => {
|
||||||
const createdUser = useSession().data?.user;
|
const createdUser = useSession().data?.user;
|
||||||
const penaltyTable = useRef<PaginatedTableRef>(null);
|
const penaltyTable = useRef<PaginatedTableRef>(null);
|
||||||
|
const session = useSession();
|
||||||
return (
|
return (
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title flex justify-between">
|
<h2 className="card-title flex justify-between">
|
||||||
@@ -353,6 +354,7 @@ export const UserPenalties = ({ user }: { user: User }) => {
|
|||||||
btnTip="Timeban hinzufügen"
|
btnTip="Timeban hinzufügen"
|
||||||
showDatePicker={true}
|
showDatePicker={true}
|
||||||
/>
|
/>
|
||||||
|
{session.data?.user.permissions.includes("ADMIN_USER_ADVANCED") && (
|
||||||
<PenaltyDropdown
|
<PenaltyDropdown
|
||||||
Icon={<LockKeyhole size={15} />}
|
Icon={<LockKeyhole size={15} />}
|
||||||
onClick={async ({ reason }) => {
|
onClick={async ({ reason }) => {
|
||||||
@@ -370,8 +372,9 @@ export const UserPenalties = ({ user }: { user: User }) => {
|
|||||||
toast.success("Ban wurde hinzugefügt!");
|
toast.success("Ban wurde hinzugefügt!");
|
||||||
}}
|
}}
|
||||||
btnClassName="btn btn-outline btn-error tooltip-error"
|
btnClassName="btn btn-outline btn-error tooltip-error"
|
||||||
btnTip="Rechte-entzug hinzufügen"
|
btnTip="Nutzerkonto sperren"
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
@@ -484,7 +487,7 @@ export const AdminForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{user.isBanned && (
|
{user.isBanned && session?.user.permissions.includes("ADMIN_USER_ADVANCED") && (
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await editUser(user.id, { isBanned: false });
|
await editUser(user.id, { isBanned: false });
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useEffect } from "react";
|
import { use, useEffect } from "react";
|
||||||
import { CheckCircledIcon, CalendarIcon, EnterIcon } from "@radix-ui/react-icons";
|
import { CheckCircledIcon, CalendarIcon, EnterIcon } from "@radix-ui/react-icons";
|
||||||
import { Event, EventAppointment, Participant, User } from "@repo/db";
|
import { Event, EventAppointment, Participant, User } from "@repo/db";
|
||||||
import { cn } from "../../../../helper/cn";
|
import { cn } from "../../../../helper/cn";
|
||||||
@@ -87,6 +87,10 @@ const ModalBtn = ({
|
|||||||
? (selectedDate as any)?.Participants?.length + 1
|
? (selectedDate as any)?.Participants?.length + 1
|
||||||
: ownIndexInParticipantList + 1;
|
: ownIndexInParticipantList + 1;
|
||||||
|
|
||||||
|
const missingRequirements =
|
||||||
|
event.requiredBadges?.length > 0 &&
|
||||||
|
!event.requiredBadges.some((badge) => user.badges.includes(badge));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
@@ -96,14 +100,20 @@ const ModalBtn = ({
|
|||||||
eventCompleted(event, participant) && "btn-success",
|
eventCompleted(event, participant) && "btn-success",
|
||||||
)}
|
)}
|
||||||
onClick={openModal}
|
onClick={openModal}
|
||||||
disabled={eventCompleted(event, participant)}
|
disabled={eventCompleted(event, participant) || missingRequirements}
|
||||||
>
|
>
|
||||||
{participant && !eventCompleted(event, participant) && (
|
{missingRequirements && (
|
||||||
|
<>
|
||||||
|
<TriangleAlert className="h-6 w-6 shrink-0 stroke-current" fill="none" />
|
||||||
|
fehlende Anforderungen
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{participant && !eventCompleted(event, participant) && !missingRequirements && (
|
||||||
<>
|
<>
|
||||||
<EyeIcon /> Anzeigen
|
<EyeIcon /> Anzeigen
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!participant && (
|
{!participant && !missingRequirements && (
|
||||||
<>
|
<>
|
||||||
<EnterIcon /> Anmelden
|
<EnterIcon /> Anmelden
|
||||||
</>
|
</>
|
||||||
@@ -287,6 +297,7 @@ const MoodleCourseIndicator = ({
|
|||||||
<button
|
<button
|
||||||
className="btn btn-xs btn-info ml-2"
|
className="btn btn-xs btn-info ml-2"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
try {
|
||||||
await upsertParticipant({
|
await upsertParticipant({
|
||||||
eventId: event.id,
|
eventId: event.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
@@ -297,6 +308,9 @@ const MoodleCourseIndicator = ({
|
|||||||
await inscribeToMoodleCourse(moodleCourseId, user.moodleId);
|
await inscribeToMoodleCourse(moodleCourseId, user.moodleId);
|
||||||
}
|
}
|
||||||
window.open(courseUrl, "_blank");
|
window.open(courseUrl, "_blank");
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Fehler beim öffnen des Moodle-Kurses", error);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Zum Moodle Kurs
|
Zum Moodle Kurs
|
||||||
|
|||||||
@@ -11,21 +11,12 @@ export default async function Page() {
|
|||||||
const user = await prisma.user.findFirst({
|
const user = await prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: session.user.id,
|
id: session.user.id,
|
||||||
Penaltys: {
|
|
||||||
some: {
|
|
||||||
until: {
|
|
||||||
gte: new Date(),
|
|
||||||
},
|
|
||||||
suspended: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
discordAccounts: true,
|
discordAccounts: true,
|
||||||
Penaltys: true,
|
Penaltys: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log("User", session, user);
|
|
||||||
const userPenaltys = await prisma.penalty.findMany({
|
const userPenaltys = await prisma.penalty.findMany({
|
||||||
where: {
|
where: {
|
||||||
userId: session.user.id,
|
userId: session.user.id,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export const VerticalNav = async () => {
|
|||||||
<li>
|
<li>
|
||||||
<Link href="/logbook">
|
<Link href="/logbook">
|
||||||
<ReaderIcon />
|
<ReaderIcon />
|
||||||
Logbook
|
Logbuch
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { DiscordAccount, prisma, User } from "@repo/db";
|
|||||||
import bcrypt from "bcryptjs";
|
import bcrypt from "bcryptjs";
|
||||||
import oldUser from "./var.User.json";
|
import oldUser from "./var.User.json";
|
||||||
import { OldUser } from "../../../../types/oldUser";
|
import { OldUser } from "../../../../types/oldUser";
|
||||||
|
import { sendVerificationLink } from "(app)/admin/user/action";
|
||||||
|
|
||||||
export const options: AuthOptions = {
|
export const options: AuthOptions = {
|
||||||
providers: [
|
providers: [
|
||||||
@@ -69,6 +70,7 @@ export const options: AuthOptions = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
await sendVerificationLink(newUser.id);
|
||||||
return newUser;
|
return newUser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const GET = async (req: NextRequest) => {
|
|||||||
if (!user) return NextResponse.json({ error: "User not found" }, { status: 404 });
|
if (!user) return NextResponse.json({ error: "User not found" }, { status: 404 });
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const moodleUser = await getMoodleUserById(user.id);
|
const moodleUser = await getMoodleUserById(user.id);
|
||||||
|
|
||||||
await prisma.user.update({
|
await prisma.user.update({
|
||||||
where: {
|
where: {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
|||||||
@@ -1,37 +1,44 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export const enrollUserInCourse = async (
|
export const enrollUserInCourse = async (courseid: number | string, userid: number | string) => {
|
||||||
courseid: number | string,
|
try {
|
||||||
userid: number | string,
|
|
||||||
) => {
|
|
||||||
const { data: enrollmentResponse } = await axios.get(
|
const { data: enrollmentResponse } = await axios.get(
|
||||||
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
||||||
{
|
{
|
||||||
|
auth: {
|
||||||
|
username: "moodleuser",
|
||||||
|
password: "Xo1SXaLYBa7Yb6WW",
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
wstoken: process.env.MOODLE_TOKEN,
|
wstoken: process.env.MOODLE_API_TOKEN,
|
||||||
wsfunction: "enrol_manual_enrol_users",
|
wsfunction: "enrol_manual_enrol_users",
|
||||||
moodlewsrestformat: "json",
|
moodlewsrestformat: "json",
|
||||||
enrolments: [
|
enrolments: [
|
||||||
{
|
{
|
||||||
roleid: 5,
|
roleid: 5,
|
||||||
userid: typeof userid === "string" ? parseInt(userid) : userid,
|
userid: typeof userid === "string" ? parseInt(userid) : userid,
|
||||||
courseid:
|
courseid: typeof courseid === "string" ? parseInt(courseid) : courseid,
|
||||||
typeof courseid === "string" ? parseInt(courseid) : courseid,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (enrollmentResponse !== null) console.error(enrollmentResponse);
|
|
||||||
return enrollmentResponse;
|
return enrollmentResponse;
|
||||||
|
} catch (error) {
|
||||||
|
return new Error("Failed to enroll user in course");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getMoodleUserById = async (id: string) => {
|
export const getMoodleUserById = async (id: string) => {
|
||||||
const { data: user } = await axios.get(
|
const { data: user } = await axios.get(
|
||||||
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
`${process.env.NEXT_PUBLIC_MOODLE_URL}/webservice/rest/server.php`,
|
||||||
{
|
{
|
||||||
|
auth: {
|
||||||
|
username: "moodleuser",
|
||||||
|
password: "Xo1SXaLYBa7Yb6WW",
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
wstoken: process.env.MOODLE_TOKEN,
|
wstoken: process.env.MOODLE_API_TOKEN,
|
||||||
wsfunction: "core_user_get_users_by_field",
|
wsfunction: "core_user_get_users_by_field",
|
||||||
moodlewsrestformat: "json",
|
moodlewsrestformat: "json",
|
||||||
field: "idnumber",
|
field: "idnumber",
|
||||||
@@ -42,6 +49,7 @@ export const getMoodleUserById = async (id: string) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
console.log("Moodle User", user);
|
||||||
const u = user[0];
|
const u = user[0];
|
||||||
return (
|
return (
|
||||||
(u as {
|
(u as {
|
||||||
|
|||||||
Reference in New Issue
Block a user