Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/(safespace)/achievements/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import AchievementCard from "@/components/Achievements/achievement-card";
import AchievementCard from "@/components/achievements/achievement-card";
import { useEffect, useState } from "react";
import { ProgressBar } from "@/components/progress-bar";
import { Achievement, AchievementData } from "@/util/achievement-data";
Expand Down
6 changes: 3 additions & 3 deletions src/app/(safespace)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import { DesktopNav } from "@/components/NavBar/DesktopNavigation/desktop-nav";
import { MobileNav } from "@/components/NavBar/MobileNavigation/mobile-nav";
import { DesktopNav } from "@/components/nav-bar/desktop-navigation/desktop-nav";
import { MobileNav } from "@/components/nav-bar/mobile-navigation/mobile-nav";
import { usePathname, useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
import clsx from "clsx";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { AchievementId } from "@/util/achievement-data";
import { getUserService } from "@/services/user/UserService";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { useRouter } from "next/navigation";
import QuizList from "@/components/Quiz/quiz-list";
import { QuizParams } from "@/components/Quiz/quiz";
import QuizList from "@/components/quiz/quiz-list";
import { QuizParams } from "@/components/quiz/quiz";
import { PersistUserService } from "@/services/user/PersistUserService";
import { AchievementId } from "@/util/achievement-data";
import { getUserService } from "@/services/user/UserService";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from "@phosphor-icons/react";
import clsx from "clsx";
import Button from "@/components/button";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import Link from "next/link";
import TagList from "@/app/(safespace)/space/daten-verarbeitung/kapitel2/analyse/components/tag-list";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from "react";
import Task from "@/components/task";
import Button from "@/components/button";
import clsx from "clsx";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { useRouter } from "next/navigation";
import { AchievementId } from "@/util/achievement-data";
import { CheckCircle, Info } from "@phosphor-icons/react";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Robot from "@/components/robot/robot";
import clsx from "clsx";
import { HintCard } from "@/components/hint-card";
import { distance } from "fastest-levenshtein";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import Link from "next/link";

type ProfileAnalysisProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import clsx from "clsx";
import AnimatedText from "@/components/animated/animated-text";
import { useRouter } from "next/navigation";
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { getUserService } from "@/services/user/UserService";

export type State = {
Expand Down
4 changes: 2 additions & 2 deletions src/app/(safespace)/space/masterquiz/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { useRouter } from "next/navigation";
import { QuizParams } from "@/components/Quiz/quiz";
import QuizList from "@/components/Quiz/quiz-list";
import { QuizParams } from "@/components/quiz/quiz";
import QuizList from "@/components/quiz/quiz-list";
import { AchievementId } from "@/util/achievement-data";

const quizzes: QuizParams[] = [
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/passwort/builder/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ActionCard } from "@/components/action-card";
import { HintCard } from "@/components/hint-card";
import Button from "@/components/button";
import { InputValidation } from "@/components/input-validation";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { useEffect, useState } from "react";
import { calculateBruteForceTime } from "@/util/passwort/passwort-validation";
import { AchievementId } from "@/util/achievement-data";
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/passwort/quiz/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
replaceCharacter,
topTenPasswords,
} from "@/util/passwort/password-quiz-data";
import QuizList from "@/components/Quiz/quiz-list";
import QuizList from "@/components/quiz/quiz-list";
import { AchievementId } from "@/util/achievement-data";

const hintCards = [
Expand Down
4 changes: 2 additions & 2 deletions src/app/(safespace)/space/passwort/strength/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import Button from "@/components/button";
import Image from "next/image";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import clsx from "clsx";
import {
passwordData,
Expand Down Expand Up @@ -41,7 +41,7 @@ export default function PasswordStrength() {
const context = getUserService();
const fetchHighScore = async () => {
const loadedHighScore = await context.getHighScore("PASSWORD_STRENGTH");
setHighscore(loadedHighScore);
setHighscore(typeof loadedHighScore === "number" ? loadedHighScore : 0);
};

const setAchievement = async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/phishing/assign/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import clsx from "clsx";
import Robot from "@/components/robot/robot";
import Task from "@/components/task";
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { getUserService } from "@/services/user/UserService";

type Profile = {
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/phishing/profiling/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import clsx from "clsx";
import { HintCard } from "@/components/hint-card";
import Robot from "@/components/robot/robot";
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import Task from "@/components/task";
import { getUserService } from "@/services/user/UserService";

Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/privatsphaere/perso/perso.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Button from "@/components/button";
import Checkbox from "@/components/checkbox";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { SetStateAction, useState } from "react";
Expand Down
4 changes: 2 additions & 2 deletions src/app/(safespace)/space/privatsphaere/quiz/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { HintCard } from "@/components/hint-card";
import { useRouter } from "next/navigation";
import { useState } from "react";
import QuizList from "@/components/Quiz/quiz-list";
import { QuizParams } from "@/components/Quiz/quiz";
import QuizList from "@/components/quiz/quiz-list";
import { QuizParams } from "@/components/quiz/quiz";
import { AchievementId } from "@/util/achievement-data";

export default function StartGame() {
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/rechte/dsgvo/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import clsx from "clsx";
import { HintCard } from "@/components/hint-card";
import Robot from "@/components/robot/robot";
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { Question } from "@phosphor-icons/react";
import Task from "@/components/task";
import { getUserService } from "@/services/user/UserService";
Expand Down
13 changes: 8 additions & 5 deletions src/app/(safespace)/space/rechte/input/action.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { getUserService } from "@/services/user/UserService";
import { ApiEndpoints } from "@/lib/constants/endpoints";

export default async function getFeedback(
export const getFeedback = async (
situation: string,
userInput: string,
solution: string,
): Promise<string> {
const response = await fetch("/api/get-answer", {
): Promise<string> => {
const response = await fetch(ApiEndpoints.ANSWERS, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand All @@ -18,7 +19,9 @@ export default async function getFeedback(
throw new Error("Failed to fetch answer");
}
return await response.json();
}
};

export default getFeedback;

export function extractScoreAndReason(str: string) {
const trimmedStr = str.slice(1, -1);
Expand Down
2 changes: 1 addition & 1 deletion src/app/(safespace)/space/rechte/input/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import getFeedback, {
} from "@/app/(safespace)/space/rechte/input/action";
import { questions } from "@/util/rights/rights-data";
import { Score } from "@/app/(safespace)/space/rechte/input/score";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { useRouter } from "next/navigation";

export default function RightsInputValidation() {
Expand Down
6 changes: 3 additions & 3 deletions src/app/(safespace)/space/rechte/quiz/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import QuizList from "@/components/Quiz/quiz-list";
import { QuizParams } from "@/components/Quiz/quiz";
import QuizList from "@/components/quiz/quiz-list";
import { QuizParams } from "@/components/quiz/quiz";
import { useRouter } from "next/navigation";
import { useState } from "react";
import Robot from "@/components/robot/robot";
import Button from "@/components/button";
import { AchievementId } from "@/util/achievement-data";
import { useMessages } from "@/services/notfication/message-provider";
import { useMessages } from "@/services/notification/message-provider";
import { PersistUserService } from "@/services/user/PersistUserService";
import { getUserService } from "@/services/user/UserService";

Expand Down
112 changes: 112 additions & 0 deletions src/app/api/achievements/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { NextRequest } from "next/server";
import * as z from "zod";
import { achievements, users } from "@/server/database/schema";
import { and, eq } from "drizzle-orm";
import { db } from "@/server/database/connection";
import {
createSuccessResponse,
createCreatedResponse,
} from "@/lib/api/response";
import { handleApiError, createErrorResponse } from "@/lib/api/error-handler";
import { HttpStatus } from "@/lib/constants/http";

const getAchievementSchema = z.object({
userId: z.coerce.number(),
});

const setAchievementSchema = z.object({
userId: z.coerce.number(),
achievementEnum: z.string(),
unlocked: z.boolean(),
});

type GetAchievementRequest = z.infer<typeof getAchievementSchema>;
type SetAchievementRequest = z.infer<typeof setAchievementSchema>;

type AchievementResponse = {
achievementEnum: string;
isAchieved: boolean;
userId: number;
};

export const GET = async (req: NextRequest) => {
try {
const searchParams = req.nextUrl.searchParams;
const userId = searchParams.get("userId");

if (!userId) {
return createErrorResponse("userId is required", HttpStatus.BAD_REQUEST);
}

const { userId: validatedUserId } = getAchievementSchema.parse({
userId,
}) as GetAchievementRequest;

const userAchievements = await db
.select({
achievementEnum: achievements.achievementEnum,
isAchieved: achievements.isAchieved,
userId: achievements.userId,
})
.from(achievements)
.where(eq(achievements.userId, validatedUserId));

return createSuccessResponse<AchievementResponse[]>(userAchievements);
} catch (error: unknown) {
if (error instanceof z.ZodError) {
return createErrorResponse(
"Invalid request data",
HttpStatus.BAD_REQUEST,
);
}
return handleApiError(error, "Failed to get achievements");
}
};

export const POST = async (req: NextRequest) => {
try {
const requestData: unknown = await req.json();
const { userId, achievementEnum, unlocked } = setAchievementSchema.parse(
requestData,
) as SetAchievementRequest;

const userData = await db.select().from(users).where(eq(users.id, userId));

if (userData.length === 0) {
return createErrorResponse("User not found", HttpStatus.NOT_FOUND);
}

const foundAchievement = await db
.select()
.from(achievements)
.where(
and(
eq(achievements.userId, userId),
eq(achievements.achievementEnum, achievementEnum),
),
);

if (foundAchievement.length > 0) {
return createErrorResponse(
"Achievement already set",
HttpStatus.BAD_REQUEST,
);
}

await db.insert(achievements).values({
userId: userId,
isAchieved: unlocked,
achievementEnum: achievementEnum,
});

return createCreatedResponse({ message: "Achievement set" });
} catch (error: unknown) {
if (error instanceof z.ZodError) {
return createErrorResponse(
"Invalid request data",
HttpStatus.BAD_REQUEST,
);
}
return handleApiError(error, "Failed to set achievement");
}
};
Loading
Loading