feat(migrations): add ownership fields to doctors table for IRIMC import

- Introduced new columns: owner_status, source, source_ref, managed_by, and claimed_at to the doctors table.
- Created indexes for owner_status and source to optimize queries related to unclaimed doctors.

feat(auth): implement SystemOwnerCommand for managing system-owner user

- Added command to create, activate, and deactivate a system-owner user for IRIMC crawler.
- Ensured the user has ROLE_ADMIN to access import endpoints.
- Handled password setting and user status management within the command.
This commit is contained in:
hamed
2026-07-11 08:59:36 +03:30
parent f30bf5dfbd
commit 9f56f4aa08
28 changed files with 3694 additions and 989 deletions
@@ -2,12 +2,14 @@
namespace App\Shared\EventSubscriber;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
@@ -108,6 +110,21 @@ class ExceptionSubscriber implements EventSubscriberInterface
return;
}
// Bots/scanners and stray preflight hit disallowed methods on public paths (e.g. POST /).
// Client errors, not server faults: respond 405 and log at notice so they don't flood
// the error channel through the generic fallback below.
if ($exception instanceof MethodNotAllowedHttpException) {
$this->logger->notice('Method not allowed', [
'path' => $event->getRequest()->getPathInfo(),
'method' => $event->getRequest()->getMethod(),
]);
$event->setResponse(new JsonResponse(
['success' => false, 'data' => null, 'errors' => [['code' => ErrorCodes::ERR_METHOD_NOT_ALLOWED_001, 'message' => ErrorCodes::message(ErrorCodes::ERR_METHOD_NOT_ALLOWED_001)]]],
405
));
return;
}
// Generic fallback: never leak stack traces or internal details in API responses.
// The class/message/location go into the log MESSAGE itself so they surface in
// platforms (e.g. Liara) whose default logger only prints the message string.