PATCH /api/user/password — verifies the current password, enforces 8-char minimum on the new one, and rehashes via the configured password hasher. Returns 204 on success, 422 with an `error` body on every validation failure (wrong current, too-short new, missing fields). Settings adds a "Change password" link under the Account section that opens a modal with current/new/confirm fields and posts to the new endpoint. Confirm-mismatch and submit-disabled wiring is client-side; backend errors surface inline. Tests: 4 new controller tests cover success, wrong-current, short-new, and missing-fields; success path also re-fetches the user and checks the hash actually changed.
This commit is contained in:
@@ -10,6 +10,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -72,6 +73,35 @@ class UserApiController extends AbstractController
|
||||
return $this->json(['theme' => $theme]);
|
||||
}
|
||||
|
||||
#[Route('/password', name: 'api_user_password', methods: ['PATCH'])]
|
||||
public function updatePassword(
|
||||
Request $request,
|
||||
EntityManagerInterface $em,
|
||||
UserPasswordHasherInterface $hasher,
|
||||
): JsonResponse {
|
||||
$body = json_decode($request->getContent(), true);
|
||||
$currentPassword = $body['currentPassword'] ?? null;
|
||||
$newPassword = $body['newPassword'] ?? null;
|
||||
|
||||
if (!is_string($currentPassword) || !is_string($newPassword)) {
|
||||
return $this->json(['error' => 'Both currentPassword and newPassword are required'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
if (strlen($newPassword) < 8) {
|
||||
return $this->json(['error' => 'New password must be at least 8 characters'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
if (!$hasher->isPasswordValid($user, $currentPassword)) {
|
||||
return $this->json(['error' => 'Current password is incorrect'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
$user->setPassword($hasher->hashPassword($user, $newPassword));
|
||||
$em->flush();
|
||||
|
||||
return $this->json(null, Response::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
#[Route('/timezone', name: 'api_user_timezone', methods: ['PATCH'])]
|
||||
public function updateTimezone(Request $request, EntityManagerInterface $em): JsonResponse
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user