Files
xxx-sphere-web/src/main/java/de/oaa/xxx/user/UserController.java
Mario a13b8e894f
Some checks failed
Host-Based Deploy (Java 21 Fix) / build-and-run (push) Has been cancelled
Alles mögliche
2026-04-08 00:53:49 +02:00

538 lines
28 KiB
Java

package de.oaa.xxx.user;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.time.LocalDate;
import java.time.Period;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.oaa.xxx.config.CookieFactory;
import de.oaa.xxx.games.bdsm.entity.BdsmDefaultsEntity;
import de.oaa.xxx.games.bdsm.repository.BdsmDefaultsRepository;
import de.oaa.xxx.games.chastity.common.BaseLockRepository;
import de.oaa.xxx.games.chastity.common.BaseLockTemplateRepository;
import de.oaa.xxx.games.chastity.common.CodeCreator;
import de.oaa.xxx.games.chastity.ttlock.TTAuthService;
import de.oaa.xxx.games.chastity.ttlock.TTLockConfigRepository;
import de.oaa.xxx.games.chastity.ttlock.TTLockService;
import de.oaa.xxx.games.chastity.ttlock.TTLockUserConfigEntity;
import de.oaa.xxx.games.chastity.ttlock.TTLockUserConfigRepository;
import de.oaa.xxx.registration.Registration;
import de.oaa.xxx.registration.RegistrationRepository;
import de.oaa.xxx.social.entity.MessageCause;
import de.oaa.xxx.social.entity.NotificationPreferenceEntity;
import de.oaa.xxx.social.repository.NotificationPreferenceRepository;
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
private final UserRepository userRepository;
private final RegistrationRepository registrationRepository;
private final NotificationPreferenceRepository notificationPreferenceRepository;
private final BdsmDefaultsRepository bdsmDefaultsRepository;
private final UserService userService;
private final TTLockUserConfigRepository ttLockUserConfigRepository;
private final TTLockConfigRepository ttLockConfigRepository;
private final TTAuthService ttAuthService;
private final TTLockService ttLockService;
private final BaseLockRepository baseLockRepository;
private final BaseLockTemplateRepository baseLockTemplateRepository;
private final CookieFactory cookieFactory;
public UserController(UserRepository userRepository,
RegistrationRepository registrationRepository,
NotificationPreferenceRepository notificationPreferenceRepository,
BdsmDefaultsRepository bdsmDefaultsRepository,
UserService userService,
TTLockUserConfigRepository ttLockUserConfigRepository,
TTLockConfigRepository ttLockConfigRepository,
TTAuthService ttAuthService,
TTLockService ttLockService,
BaseLockRepository baseLockRepository,
BaseLockTemplateRepository baseLockTemplateRepository,
CookieFactory cookieFactory) {
this.userRepository = userRepository;
this.registrationRepository = registrationRepository;
this.notificationPreferenceRepository = notificationPreferenceRepository;
this.bdsmDefaultsRepository = bdsmDefaultsRepository;
this.userService = userService;
this.ttLockUserConfigRepository = ttLockUserConfigRepository;
this.ttLockConfigRepository = ttLockConfigRepository;
this.ttAuthService = ttAuthService;
this.ttLockService = ttLockService;
this.baseLockRepository = baseLockRepository;
this.baseLockTemplateRepository = baseLockTemplateRepository;
this.cookieFactory = cookieFactory;
}
record ProfilePictureRequest(String picture, String pictureHq) {}
record NameChangeRequest(String name) {}
record GeburtsdatumChangeRequest(LocalDate geburtsdatum) {}
record TtlockUserConfigDto(String username, boolean passwordSet, Integer lockId, boolean testSuccessful) {}
record TtlockUserConfigRequest(String username, String password, Integer lockId) {}
record ProfileRequest(Integer groesse, Integer gewicht,
Geschlecht geschlecht, Neigung neigung, Beziehungsstatus beziehungsstatus, String beschreibung) {}
record DatingRequest(boolean datingAktiv, String datingStadt, Double datingLat, Double datingLon,
List<String> datingGeschlechter,
Integer datingMaxDistanzKm, Integer datingMinAlter, Integer datingMaxAlter) {}
record DatingFilterRequest(List<String> datingGeschlechter,
Integer datingMaxDistanzKm, Integer datingMinAlter, Integer datingMaxAlter) {}
record PrivacyRequest(
Sichtbarkeit sichtbarkeitGrunddaten,
Sichtbarkeit sichtbarkeitGalerie,
Sichtbarkeit sichtbarkeitFreunde,
Sichtbarkeit sichtbarkeitFeed,
Sichtbarkeit sichtbarkeitPinnwand,
Sichtbarkeit sichtbarkeitXp,
Sichtbarkeit sichtbarkeitLockhistorie,
Sichtbarkeit sichtbarkeitVorlieben,
Boolean profilBeiVeroeffentlichungenSichtbar) {}
@PutMapping("/me/dating")
public ResponseEntity<Void> updateDating(@RequestBody DatingRequest request, Principal principal) {
if (request.datingAktiv() && (request.datingStadt() == null || request.datingStadt().isBlank())) {
return ResponseEntity.badRequest().build();
}
var user = userService.requireUser(principal);
user.setDatingAktiv(request.datingAktiv());
if (!request.datingAktiv()) {
// Alle Dating-Einstellungen zurücksetzen
user.setDatingStadt(null);
user.setDatingLat(null);
user.setDatingLon(null);
user.setDatingGeschlechter(null);
user.setDatingMaxDistanzKm(null);
user.setDatingMinAlter(null);
user.setDatingMaxAlter(null);
} else {
user.setDatingStadt(request.datingStadt().trim());
user.setDatingLat(request.datingLat());
user.setDatingLon(request.datingLon());
if (request.datingGeschlechter() != null && !request.datingGeschlechter().isEmpty()) {
String joined = request.datingGeschlechter().stream()
.filter(g -> { try { Geschlecht.valueOf(g); return true; } catch (IllegalArgumentException e) { return false; } })
.collect(Collectors.joining(","));
user.setDatingGeschlechter(joined.isBlank() ? null : joined);
} else {
user.setDatingGeschlechter(null);
}
if (request.datingMaxDistanzKm() != null) user.setDatingMaxDistanzKm(Math.max(1, Math.min(500, request.datingMaxDistanzKm())));
if (request.datingMinAlter() != null) user.setDatingMinAlter(Math.max(18, Math.min(99, request.datingMinAlter())));
if (request.datingMaxAlter() != null) user.setDatingMaxAlter(Math.max(18, Math.min(99, request.datingMaxAlter())));
}
userRepository.save(user);
LOGGER.info("User {} hat Dating-Einstellungen aktualisiert: aktiv={}", user.getUserId(), request.datingAktiv());
return ResponseEntity.ok().build();
}
@PutMapping("/me/dating-filter")
public ResponseEntity<Void> updateDatingFilter(@RequestBody DatingFilterRequest request, Principal principal) {
var user = userService.requireUser(principal);
if (!user.isDatingAktiv())
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
if (request.datingGeschlechter() != null) {
String joined = request.datingGeschlechter().stream()
.filter(g -> { try { Geschlecht.valueOf(g); return true; } catch (IllegalArgumentException e) { return false; } })
.collect(Collectors.joining(","));
user.setDatingGeschlechter(joined.isBlank() ? null : joined);
}
if (request.datingMaxDistanzKm() != null) user.setDatingMaxDistanzKm(Math.max(1, Math.min(500, request.datingMaxDistanzKm())));
if (request.datingMinAlter() != null) user.setDatingMinAlter(Math.max(18, Math.min(99, request.datingMinAlter())));
if (request.datingMaxAlter() != null) user.setDatingMaxAlter(Math.max(18, Math.min(99, request.datingMaxAlter())));
userRepository.save(user);
return ResponseEntity.ok().build();
}
@PutMapping("/me/picture")
public ResponseEntity<Void> updateProfilePicture(@RequestBody ProfilePictureRequest request, Principal principal) {
var user = userService.requireUser(principal);
user.setProfilePicture(request.picture());
user.setProfilePictureHq(request.pictureHq());
userRepository.save(user);
LOGGER.debug("User {} hat Profilbild aktualisiert", user.getUserId());
return ResponseEntity.ok().build();
}
@PutMapping("/me/profile")
public ResponseEntity<Void> updateProfile(@RequestBody ProfileRequest request, Principal principal) {
var user = userService.requireUser(principal);
if (request.beschreibung() != null && request.beschreibung().length() > 600) {
return ResponseEntity.badRequest().build();
}
user.setGroesse(request.groesse());
user.setGewicht(request.gewicht());
user.setGeschlecht(request.geschlecht());
user.setNeigung(request.neigung());
user.setBeziehungsstatus(request.beziehungsstatus());
user.setBeschreibung(request.beschreibung());
userRepository.save(user);
LOGGER.info("User {} hat Profil aktualisiert", user.getUserId());
return ResponseEntity.ok().build();
}
@PutMapping("/me/privacy")
public ResponseEntity<Void> updatePrivacy(@RequestBody PrivacyRequest request, Principal principal) {
var user = userService.requireUser(principal);
if (request.sichtbarkeitGrunddaten() != null) user.setSichtbarkeitGrunddaten(request.sichtbarkeitGrunddaten());
if (request.sichtbarkeitGalerie() != null) user.setSichtbarkeitGalerie(request.sichtbarkeitGalerie());
if (request.sichtbarkeitFreunde() != null) user.setSichtbarkeitFreunde(request.sichtbarkeitFreunde());
if (request.sichtbarkeitFeed() != null) user.setSichtbarkeitFeed(request.sichtbarkeitFeed());
if (request.sichtbarkeitPinnwand() != null) user.setSichtbarkeitPinnwand(request.sichtbarkeitPinnwand());
if (request.sichtbarkeitXp() != null) user.setSichtbarkeitXp(request.sichtbarkeitXp());
if (request.sichtbarkeitLockhistorie()!= null) user.setSichtbarkeitLockhistorie(request.sichtbarkeitLockhistorie());
if (request.sichtbarkeitVorlieben() != null) user.setSichtbarkeitVorlieben(request.sichtbarkeitVorlieben());
if (request.profilBeiVeroeffentlichungenSichtbar() != null) {
boolean showAuthor = request.profilBeiVeroeffentlichungenSichtbar();
user.setProfilBeiVeroeffentlichungenSichtbar(showAuthor);
// Alle veröffentlichten Templates synchronisieren
var templates = baseLockTemplateRepository.findByOwnerAndPublishedTrue(user.getUserId());
for (var t : templates) {
t.setShowAuthor(showAuthor);
}
baseLockTemplateRepository.saveAll(templates);
}
userRepository.save(user);
LOGGER.info("User {} hat Datenschutz-Einstellungen aktualisiert", user.getUserId());
return ResponseEntity.ok().build();
}
record NotificationPreferenceRequest(boolean inApp, boolean email) {}
@GetMapping("/me/notifications")
public ResponseEntity<Map<String, Object>> getNotifications(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
Map<String, NotificationPreferenceEntity> byKey = notificationPreferenceRepository.findByUserId(userId)
.stream().collect(Collectors.toMap(p -> p.getCause().name(), p -> p));
Map<String, Object> result = new LinkedHashMap<>();
for (MessageCause cause : MessageCause.values()) {
NotificationPreferenceEntity pref = byKey.getOrDefault(
cause.name(), NotificationPreferenceEntity.defaultFor(userId, cause));
Map<String, Object> entry = new LinkedHashMap<>();
entry.put("inApp", pref.isInApp());
entry.put("email", pref.isEmail());
result.put(cause.name(), entry);
}
return ResponseEntity.ok(result);
}
@PutMapping("/me/notifications")
public ResponseEntity<Void> updateNotifications(@RequestBody Map<String, NotificationPreferenceRequest> request, Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
for (var entry : request.entrySet()) {
MessageCause cause;
try {
cause = MessageCause.valueOf(entry.getKey());
} catch (IllegalArgumentException e) {
continue;
}
NotificationPreferenceEntity pref = notificationPreferenceRepository
.findByUserIdAndCause(userId, cause)
.orElseGet(() -> {
NotificationPreferenceEntity n = new NotificationPreferenceEntity();
n.setUserId(userId);
n.setCause(cause);
return n;
});
pref.setInApp(entry.getValue().inApp());
pref.setEmail(entry.getValue().email());
notificationPreferenceRepository.save(pref);
}
return ResponseEntity.ok().build();
}
record BdsmDefaultsRequest(List<String> spieltMit, List<String> rollen, List<String> werkzeuge) {}
@GetMapping("/me/bdsm-defaults")
public ResponseEntity<Map<String, Object>> getBdsmDefaults(Principal principal) {
var currentUser = userService.requireUser(principal);
UUID userId = currentUser.getUserId();
BdsmDefaultsEntity d = bdsmDefaultsRepository.findByUserId(userId)
.orElse(new BdsmDefaultsEntity());
Map<String, Object> result = new java.util.LinkedHashMap<>();
result.put("geschlecht", currentUser.getGeschlecht() != null ? currentUser.getGeschlecht().name() : null);
result.put("spieltMit", splitOrEmpty(d.getSpieltMit()));
result.put("rollen", splitOrEmpty(d.getRollen()));
result.put("werkzeuge", splitOrEmpty(d.getWerkzeuge()));
return ResponseEntity.ok(result);
}
@GetMapping("/{userId}/bdsm-defaults")
public ResponseEntity<Map<String, Object>> getBdsmDefaultsForUser(@PathVariable("userId") UUID userId) {
var userOpt = userRepository.findById(userId);
if (userOpt.isEmpty()) return ResponseEntity.notFound().build();
UserEntity user = userOpt.get();
BdsmDefaultsEntity d = bdsmDefaultsRepository.findByUserId(userId)
.orElse(new BdsmDefaultsEntity());
Map<String, Object> result = new java.util.LinkedHashMap<>();
result.put("geschlecht", user.getGeschlecht() != null ? user.getGeschlecht().name() : null);
result.put("spieltMit", splitOrEmpty(d.getSpieltMit()));
result.put("rollen", splitOrEmpty(d.getRollen()));
result.put("werkzeuge", splitOrEmpty(d.getWerkzeuge()));
return ResponseEntity.ok(result);
}
@PutMapping("/me/bdsm-defaults")
public ResponseEntity<Void> updateBdsmDefaults(@RequestBody BdsmDefaultsRequest request, Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
BdsmDefaultsEntity d = bdsmDefaultsRepository.findByUserId(userId)
.orElseGet(() -> { BdsmDefaultsEntity n = new BdsmDefaultsEntity(); n.setUserId(userId); return n; });
d.setSpieltMit(request.spieltMit() == null ? "" : String.join(",", request.spieltMit()));
d.setRollen(request.rollen() == null ? "" : String.join(",", request.rollen()));
d.setWerkzeuge(request.werkzeuge() == null ? "" : String.join(",", request.werkzeuge()));
bdsmDefaultsRepository.save(d);
return ResponseEntity.ok().build();
}
private static List<String> splitOrEmpty(String s) {
if (s == null || s.isBlank()) return List.of();
return List.of(s.split(","));
}
@PutMapping("/me/geburtsdatum")
public ResponseEntity<Void> updateGeburtsdatum(@RequestBody GeburtsdatumChangeRequest request, Principal principal) {
if (request.geburtsdatum() == null
|| Period.between(request.geburtsdatum(), LocalDate.now()).getYears() < 18) {
return ResponseEntity.status(422).build();
}
var user = userService.requireUser(principal);
user.setGeburtsdatum(request.geburtsdatum());
userRepository.save(user);
LOGGER.info("User {} hat Geburtsdatum aktualisiert", user.getUserId());
return ResponseEntity.ok().build();
}
@PutMapping("/me/name")
public ResponseEntity<Void> updateName(@RequestBody NameChangeRequest request, Principal principal) {
String newName = request.name();
if (userRepository.findByName(newName).isPresent()
|| registrationRepository.findByName(newName).isPresent()) {
return ResponseEntity.status(409).build();
}
var user = userService.requireUser(principal);
user.setName(newName);
userRepository.save(user);
LOGGER.info("User {} hat Namen zu '{}' geändert", user.getUserId(), newName);
return ResponseEntity.ok().build();
}
@DeleteMapping("/me")
public ResponseEntity<Void> deleteAccount(Principal principal) {
var currentUser = userService.requireUser(principal);
UUID userId = currentUser.getUserId();
String email = currentUser.getEmail();
userService.deleteAccount(userId, email);
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookieFactory.jwtCookie("", java.time.Duration.ZERO).toString())
.build();
}
// ── TTLock-Account ────────────────────────────────────────────────────────
@GetMapping("/me/ttlock")
public ResponseEntity<TtlockUserConfigDto> getTtlockUserConfig(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
TTLockUserConfigEntity cfg = ttLockUserConfigRepository.findById(userId)
.orElse(new TTLockUserConfigEntity());
return ResponseEntity.ok(new TtlockUserConfigDto(
cfg.getUsername(),
cfg.getPasswordMd5() != null && !cfg.getPasswordMd5().isBlank(),
cfg.getLockId(),
cfg.isTestSuccessful()
));
}
@PutMapping("/me/ttlock")
public ResponseEntity<Void> saveTtlockUserConfig(@RequestBody TtlockUserConfigRequest body, Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
TTLockUserConfigEntity cfg = ttLockUserConfigRepository.findById(userId)
.orElseGet(() -> { TTLockUserConfigEntity n = new TTLockUserConfigEntity(); n.setUserId(userId); return n; });
boolean credentialsChanged = !java.util.Objects.equals(cfg.getUsername(), body.username())
|| !java.util.Objects.equals(cfg.getLockId(), body.lockId())
|| (body.password() != null && !body.password().isBlank());
if (credentialsChanged) {
cfg.setTestSuccessful(false);
}
cfg.setUsername(body.username());
if (body.password() != null && !body.password().isBlank()) {
cfg.setPasswordMd5(DigestUtils.md5DigestAsHex(body.password().getBytes(StandardCharsets.UTF_8)));
}
cfg.setLockId(body.lockId());
ttLockUserConfigRepository.save(cfg);
return ResponseEntity.ok().build();
}
@GetMapping("/me/ttlock/test")
public ResponseEntity<Map<String, Object>> testTtlockConnection(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null);
if (userCfg == null || userCfg.getUsername() == null || userCfg.getPasswordMd5() == null || userCfg.getLockId() == null) {
return ResponseEntity.badRequest().body(Map.of("error", "ttlock_not_configured"));
}
var adminCfg = ttLockConfigRepository.findById(1L).orElse(null);
if (adminCfg == null || adminCfg.getClientId() == null || adminCfg.getClientSecret() == null) {
return ResponseEntity.badRequest().body(Map.of("error", "admin_config_missing"));
}
String token = ttAuthService.getAccessToken(
adminCfg.getClientId(), adminCfg.getClientSecret(),
userCfg.getUsername(), userCfg.getPasswordMd5());
if (token == null) {
return ResponseEntity.status(502).body(Map.of("error", "auth_failed"));
}
TTLockService.TTLockDetailResponse detail = ttLockService.getLockDetail(
adminCfg.getClientId(), token, userCfg.getLockId());
if (detail == null || detail.getErrcode() != 0) {
String msg = detail != null ? detail.getErrmsg() : "Keine Antwort";
return ResponseEntity.status(502).body(Map.of("error", "lock_detail_failed", "message", msg));
}
userCfg.setTestSuccessful(true);
ttLockUserConfigRepository.save(userCfg);
Map<String, Object> result = new LinkedHashMap<>();
result.put("lockId", detail.getLockId());
result.put("lockName", detail.getLockName());
result.put("lockAlias", detail.getLockAlias());
result.put("modelNum", detail.getModelNum());
result.put("electricQuantity", detail.getElectricQuantity());
result.put("state", detail.getState());
return ResponseEntity.ok(result);
}
@PostMapping("/me/ttlock/open")
public ResponseEntity<Map<String, Object>> ttlockOpen(Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null);
if (userCfg == null || userCfg.getUsername() == null || userCfg.getPasswordMd5() == null || userCfg.getLockId() == null) {
return ResponseEntity.badRequest().body(Map.of("error", "ttlock_not_configured"));
}
var adminCfg = ttLockConfigRepository.findById(1L).orElse(null);
if (adminCfg == null || adminCfg.getClientId() == null) {
return ResponseEntity.badRequest().body(Map.of("error", "admin_config_missing"));
}
var activeLock = baseLockRepository.findByLockee(userId);
if (activeLock.isPresent() && activeLock.get().getUnlockTime() == null) {
return ResponseEntity.status(409).body(Map.of("error", "active_lock_exists"));
}
String token = ttAuthService.getAccessToken(
adminCfg.getClientId(), adminCfg.getClientSecret(),
userCfg.getUsername(), userCfg.getPasswordMd5());
if (token == null) {
return ResponseEntity.status(502).body(Map.of("error", "auth_failed"));
}
String pin = CodeCreator.createNumeric(6);
Integer pwdId = ttLockService.addCustomPasscode(adminCfg.getClientId(), token, userCfg.getLockId(), pin);
if (pwdId == null) {
return ResponseEntity.status(502).body(Map.of("error", "passcode_failed"));
}
return ResponseEntity.ok(Map.of("pin", pin, "keyboardPwdId", pwdId));
}
@DeleteMapping("/me/ttlock/open/{keyboardPwdId}")
public ResponseEntity<Void> ttlockCloseOpen(@PathVariable("keyboardPwdId") int keyboardPwdId, Principal principal) {
UUID userId = userService.requireUser(principal).getUserId();
var userCfg = ttLockUserConfigRepository.findById(userId).orElse(null);
if (userCfg == null || userCfg.getLockId() == null) return ResponseEntity.badRequest().build();
var adminCfg = ttLockConfigRepository.findById(1L).orElse(null);
if (adminCfg == null) return ResponseEntity.badRequest().build();
String token = ttAuthService.getAccessToken(
adminCfg.getClientId(), adminCfg.getClientSecret(),
userCfg.getUsername(), userCfg.getPasswordMd5());
if (token == null) return ResponseEntity.status(502).build();
ttLockService.deleteCustomPasscode(adminCfg.getClientId(), token, userCfg.getLockId(), keyboardPwdId);
return ResponseEntity.ok().build();
}
@PostMapping
public ResponseEntity<Void> userAnlegen(@RequestBody Registration registration) {
try {
userService.createUser(registration);
return ResponseEntity.status(201).build();
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().build();
} catch (IllegalStateException e) {
return ResponseEntity.status(409).build();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return ResponseEntity.internalServerError().build();
}
}
record NewMemberDto(UUID userId, String name, String profilePicture,
Integer alter, String geschlecht, String neigung,
String datingStadt, String beschreibung) {}
@GetMapping("/new-members")
public ResponseEntity<List<NewMemberDto>> getNewMembers(Principal principal) {
UUID myId = principal != null ? userService.requireUser(principal).getUserId() : null;
LocalDate since = LocalDate.now().minusDays(14);
List<NewMemberDto> result = userRepository
.findByRegistrierungsdatumAfterOrderByRegistrierungsdatumDesc(since)
.stream()
.filter(u -> !u.getUserId().equals(myId))
.map(u -> new NewMemberDto(
u.getUserId(),
u.getName(),
u.getProfilePictureHq() != null ? u.getProfilePictureHq() : u.getProfilePicture(),
u.getAlter(),
u.getGeschlecht() != null ? u.getGeschlecht().name() : null,
u.getNeigung() != null ? u.getNeigung().name() : null,
u.getDatingStadt(),
u.getBeschreibung()))
.collect(Collectors.toList());
return ResponseEntity.ok(result);
}
record LocationFilterRequest(String filterCity, Double filterLat, Double filterLon, Integer filterMaxDistKm) {}
@PutMapping("/me/location-filter")
public ResponseEntity<Void> updateLocationFilter(@RequestBody LocationFilterRequest request, Principal principal) {
var user = userService.requireUser(principal);
if (request.filterCity() != null) user.setFilterCity(request.filterCity());
if (request.filterLat() != null) user.setFilterLat(request.filterLat());
if (request.filterLon() != null) user.setFilterLon(request.filterLon());
if (request.filterMaxDistKm() != null) user.setFilterMaxDistKm(Math.max(1, Math.min(500, request.filterMaxDistKm())));
userRepository.save(user);
return ResponseEntity.ok().build();
}
}