34b050503d
- Rechtsseiten: Impressum-Platzhalter + echte Nutzungsbedingungen/AGB, Datenschutz (DSGVO) und Richtlinien; LegalController/ImpressumController, Footer app-weit verlinkt, Seiten als permitAll freigegeben. - FinalFlux: 28 Themen / ~742 Fragen überarbeitet (plausible Distraktoren statt Dummy-Antworten, echte Erklärungen) + echte Lehrtexte je Seite; Netzwerktopologien mit Inline-SVG-Diagrammen (Stern/Bus/Ring/Mesh/Baum). - Login/Registrierung als kombiniertes Dual-Panel (Slide-Overlay + Neon-Hover- Button), ausgelagert nach auth.css; Register-Duplikat -> /?registerError. - Konto löschen repariert: @Transactional + Löschen von Spielständen, Achievements und Profilbild-Datei (DSGVO Art. 17). Impressum-Zurück-Link login-abhängig. - App-weiter Farb-Relaunch auf "Back to the Future"-Palette: Feuer-Amber primär + Flux-Blau sekundär, warmer Glow; Dark/Light bleiben. Spiele-Feedback ohne Grün: richtig = Blau + Haken, falsch = Rot + Kreuz (neue Tokens --success/--danger/--secondary). Legacy-Cyan in style.css auf Variablen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
210 lines
9.0 KiB
Java
210 lines
9.0 KiB
Java
package com.example.mindflux.controller;
|
|
|
|
import com.example.mindflux.model.User;
|
|
import com.example.mindflux.service.UserService;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.security.core.Authentication;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
|
import org.springframework.stereotype.Controller;
|
|
import org.springframework.ui.Model;
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import java.awt.Color;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.RenderingHints;
|
|
import java.awt.image.BufferedImage;
|
|
import javax.imageio.ImageIO;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.security.Principal;
|
|
import java.util.UUID;
|
|
|
|
@Controller
|
|
public class ProfileController {
|
|
|
|
@Autowired
|
|
private UserService userService;
|
|
|
|
@Autowired
|
|
private BCryptPasswordEncoder passwordEncoder;
|
|
|
|
private static final String UPLOAD_DIR = System.getProperty("user.dir") + "/uploads/profiles/";
|
|
|
|
@GetMapping("/profile")
|
|
public String profile(Model model, Principal principal, @RequestParam(value = "success", required = false) Boolean success) {
|
|
String username = principal.getName();
|
|
User user = userService.findByUsername(username);
|
|
|
|
model.addAttribute("user", user);
|
|
|
|
if (Boolean.TRUE.equals(success)) {
|
|
model.addAttribute("message", "Profil erfolgreich aktualisiert!");
|
|
}
|
|
|
|
return "profile";
|
|
}
|
|
|
|
@PostMapping("/profile/delete-picture")
|
|
public String deleteProfilePicture(Principal principal) {
|
|
String username = principal.getName();
|
|
User existingUser = userService.findByUsername(username);
|
|
|
|
if (existingUser != null) {
|
|
String profilePicture = existingUser.getProfilePicture();
|
|
if (profilePicture != null && !profilePicture.trim().isEmpty()) {
|
|
try {
|
|
Path picturePath = Paths.get(System.getProperty("user.dir"), "uploads", "profiles", profilePicture);
|
|
System.out.println("Versuche zu löschen: " + picturePath.toAbsolutePath());
|
|
|
|
if (Files.exists(picturePath)) {
|
|
Files.delete(picturePath);
|
|
System.out.println("Datei erfolgreich gelöscht: " + picturePath.getFileName());
|
|
} else {
|
|
System.out.println("Datei existiert nicht: " + picturePath.toAbsolutePath());
|
|
}
|
|
} catch (IOException e) {
|
|
System.err.println("Fehler beim Löschen der Datei: " + e.getMessage());
|
|
}
|
|
} else {
|
|
System.out.println("Kein Profilbild gesetzt, nichts zu löschen.");
|
|
}
|
|
|
|
existingUser.setProfilePicture(null); // Wichtig: auch wenn Datei nicht existiert
|
|
userService.save(existingUser);
|
|
}
|
|
|
|
return "redirect:/profile?success=true";
|
|
}
|
|
|
|
@GetMapping("/profile/knowledge")
|
|
public String knowledgeCenter(Model model, Principal principal) {
|
|
String username = principal.getName();
|
|
User user = userService.findByUsername(username);
|
|
|
|
model.addAttribute("user", user);
|
|
return "knowledge";
|
|
}
|
|
|
|
@PostMapping("/profile/update")
|
|
public String updateProfile(@RequestParam("email") String email,
|
|
@RequestParam(value = "profilePicture", required = false) MultipartFile file,
|
|
Principal principal) {
|
|
String username = principal.getName();
|
|
User existingUser = userService.findByUsername(username);
|
|
|
|
if (existingUser != null) {
|
|
existingUser.setEmail(email); // Email aktualisieren
|
|
|
|
if (file != null && !file.isEmpty()) {
|
|
try {
|
|
BufferedImage original = ImageIO.read(file.getInputStream());
|
|
if (original == null) {
|
|
// Keine lesbare Bilddatei -> Upload ignorieren, restliches Profil trotzdem speichern.
|
|
System.out.println("Profilbild-Upload ignoriert: keine lesbare Bilddatei.");
|
|
} else {
|
|
// Auf max. Kantenlänge herunterskalieren (kein Hochskalieren).
|
|
final int MAX_DIM = 400;
|
|
int w = original.getWidth();
|
|
int h = original.getHeight();
|
|
double scale = Math.min(1.0, (double) MAX_DIM / Math.max(w, h));
|
|
int nw = Math.max(1, (int) Math.round(w * scale));
|
|
int nh = Math.max(1, (int) Math.round(h * scale));
|
|
|
|
BufferedImage scaled = new BufferedImage(nw, nh, BufferedImage.TYPE_INT_RGB);
|
|
Graphics2D g = scaled.createGraphics();
|
|
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
|
g.setColor(Color.WHITE); // JPEG kennt kein Alpha -> Transparenz auf weißem Grund
|
|
g.fillRect(0, 0, nw, nh);
|
|
g.drawImage(original, 0, 0, nw, nh, null);
|
|
g.dispose();
|
|
|
|
// Altes Profilbild löschen (falls vorhanden)
|
|
if (existingUser.getProfilePicture() != null && !existingUser.getProfilePicture().isEmpty()) {
|
|
Path oldFilePath = Paths.get(System.getProperty("user.dir"), "uploads", "profiles", existingUser.getProfilePicture());
|
|
Files.deleteIfExists(oldFilePath);
|
|
}
|
|
|
|
// Normalisiert als JPEG speichern
|
|
String fileName = UUID.randomUUID() + ".jpg";
|
|
Path uploadPath = Paths.get(UPLOAD_DIR);
|
|
Files.createDirectories(uploadPath);
|
|
ImageIO.write(scaled, "jpg", uploadPath.resolve(fileName).toFile());
|
|
|
|
existingUser.setProfilePicture(fileName);
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
userService.save(existingUser);
|
|
}
|
|
|
|
return "redirect:/profile?success=true";
|
|
}
|
|
|
|
@PostMapping("/profile/change-password")
|
|
public String changePassword(@RequestParam("oldPassword") String oldPassword,
|
|
@RequestParam("newPassword") String newPassword,
|
|
Principal principal,
|
|
RedirectAttributes redirectAttributes) {
|
|
String username = principal.getName();
|
|
User user = userService.findByUsername(username);
|
|
|
|
if (user == null) {
|
|
redirectAttributes.addFlashAttribute("error", "Benutzer nicht gefunden.");
|
|
return "redirect:/profile/settings";
|
|
}
|
|
|
|
if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
|
|
redirectAttributes.addFlashAttribute("error", "Das aktuelle Passwort ist falsch.");
|
|
return "redirect:/profile/settings";
|
|
}
|
|
|
|
user.setPassword(passwordEncoder.encode(newPassword));
|
|
userService.save(user);
|
|
|
|
redirectAttributes.addFlashAttribute("message", "Passwort erfolgreich geändert.");
|
|
return "redirect:/profile/settings";
|
|
}
|
|
|
|
@PostMapping("/profile/delete")
|
|
public String deleteProfile(Principal principal, Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
|
|
String username = principal.getName();
|
|
|
|
// Profilbild-Datei von der Platte entfernen (DB-Daten löscht der Service in einer Transaktion).
|
|
User user = userService.findByUsername(username);
|
|
if (user != null) {
|
|
String profilePicture = user.getProfilePicture();
|
|
if (profilePicture != null && !profilePicture.trim().isEmpty()) {
|
|
try {
|
|
Path picturePath = Paths.get(System.getProperty("user.dir"), "uploads", "profiles", profilePicture);
|
|
Files.deleteIfExists(picturePath);
|
|
} catch (IOException e) {
|
|
System.err.println("Fehler beim Löschen des Profilbilds: " + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
userService.deleteByUsername(username);
|
|
new SecurityContextLogoutHandler().logout(request, response, authentication);
|
|
return "redirect:/?logout";
|
|
}
|
|
|
|
// Hilfsmethode: Dateiendung extrahieren
|
|
private String getFileExtension(String filename) {
|
|
if (filename == null || filename.lastIndexOf(".") == -1) {
|
|
return "";
|
|
}
|
|
return filename.substring(filename.lastIndexOf("."));
|
|
}
|
|
}
|