first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
<?php
declare(strict_types=1);
namespace External\HannahBundle\SAP\Security;
use External\HannahBundle\SAP\Exception\SAPManyException;
use External\HannahBundle\SAP\MappingType;
use External\HannahBundle\SAP\Util\SAPClient;
use External\HannahBundle\SAP\Util\SAPUtil;
use External\HannahBundle\Util\Configuration;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\UserBundle\Security\CustomAuthenticator;
use KupShop\UserBundle\Security\LegacyPasswordEncoder;
use Query\Operator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\SecurityRequestAttributes;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use Symfony\Contracts\Service\Attribute\Required;
class SAPAuthenticator extends CustomAuthenticator
{
use TargetPathTrait;
#[Required]
public Configuration $configuration;
private SAPClient $client;
private SAPUtil $sapUtil;
private LegacyPasswordEncoder $passwordEncoder;
#[Required]
final public function setSAPClient(SAPClient $client): void
{
$this->client = $client;
}
#[Required]
final public function setSAPUtil(SAPUtil $sapUtil): void
{
$this->sapUtil = $sapUtil;
}
#[Required]
final public function setPasswordEncoder(LegacyPasswordEncoder $passwordEncoder): void
{
$this->passwordEncoder = $passwordEncoder;
}
public function authenticate(Request $request): Passport
{
$email = $request->get('login');
$password = $request->get('password');
if (($url = $request->get('url')) && $request->getSession()) {
$this->saveTargetPath($request->getSession(), 'main', $url);
}
if (empty($email) || empty($password)) {
throw new AuthenticationCredentialsNotFoundException();
}
try {
$email = mb_strtolower($email);
// nevalidni email ani nezkousim
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new AuthenticationCredentialsNotFoundException();
}
$user = \User::createFromLogin($email);
$process = $user ? $this->configuration->getProcessByUser($user) : null;
$result = $this->client->customerValidate(
$email,
$this->passwordEncoder->encodePassword($password, ''),
$process
);
} catch (SAPManyException $e) {
if ($e->hasExceptionWithCode(['005', '020', '095', '148', '318'])) {
throw new AuthenticationCredentialsNotFoundException();
}
$this->sapUtil->getLogger()->log(
$e,
sprintf('Při příhlašování uživatele "%s" vznikla chyba: %s', $email, $e->getMessage())
);
// Nalezen více než jeden BP ... - chyba, kterou si musi OC opravit v SAPu
if ($e->hasExceptionWithCode(['018'])) {
throw new CustomUserMessageAuthenticationException(
translate('error_login_generic', 'oc')
);
}
throw $e;
}
$customer = $result->CustomerData;
if (empty($customer)) {
throw new AuthenticationCredentialsNotFoundException();
}
// check that user exists, or create new one
/** @var \User $user */
$user = sqlGetConnection()->transactional(function () use ($customer) {
if (!($userId = $this->sapUtil->getMapping(MappingType::USERS, $customer->CustomerId))) {
$userId = $this->createUser($customer);
$this->sapUtil->createMapping(MappingType::USERS, $customer->CustomerId, $userId);
}
return \User::createFromId($userId);
});
$this->sapUtil->updateUser($user, $customer);
if (!$this->passwordEncoder->isPasswordValid(trim($customer->PaswdData->PaswdHash ?? ''), $password, '')) {
throw new AuthenticationCredentialsNotFoundException();
}
return new SelfValidatingPassport(
new UserBadge($email),
[new RememberMeBadge()]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($request->getSession() && ($url = $this->getTargetPath($request->getSession(), 'main'))) {
$this->removeTargetPath($request->getSession(), 'main');
return new RedirectResponse($url);
}
return new RedirectResponse(
$request->headers->get('referer', '/')
);
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
// pass to next authenticator
if ($exception instanceof AuthenticationCredentialsNotFoundException) {
return null;
}
if ($request->hasSession()) {
$request->getSession()->set(SecurityRequestAttributes::AUTHENTICATION_ERROR, $exception);
}
$url = $this->getLoginUrl($request);
return new RedirectResponse($url);
}
public function supports(Request $request): bool
{
return $request->isMethod('POST')
&& StringUtil::startsWith($request->getPathInfo(), path('kupshop_user_login_login'));
}
private function createUser(\stdClass $data): int
{
// check if user exists
$userId = sqlQueryBuilder()
->select('id')
->from('users')
->where(Operator::equals(
[
'email' => $data->PersonalData->Email,
]
))->execute()->fetchColumn();
if ($userId) {
return (int) $userId;
}
$addressData = [
'name' => '',
'surname' => '',
'firm' => '',
'ico' => '',
'dic' => '',
'street' => '',
'city' => '',
'zip' => '',
'country' => '',
'delivery_name' => '',
'delivery_surname' => '',
'delivery_street' => '',
'delivery_city' => '',
'delivery_zip' => '',
'delivery_country' => '',
];
$addresses = $this->sapUtil->prepareSAPItems($data->AddressData);
foreach ($addresses as $address) {
foreach ($address as $key => $value) {
if ($address->AddressType === 'COMPANY') {
if (!in_array($key, ['Company', 'VatIdentNumber', 'CompRegNumber'])) {
continue;
}
}
if ($field = $this->getAddressField($key)) {
$addressData[$this->getAddressPrefix($address->AddressType).$field] = $value;
}
}
}
return sqlGetConnection()->transactional(function () use ($data, $addressData) {
sqlQueryBuilder()
->insert('users')
->directValues(
array_merge(
[
'email' => $data->PersonalData->Email,
'phone' => $data->PersonalData->TelNo ?? '',
'passw' => $data->PaswdData->PaswdHash ?? '',
'date_reg' => (new \DateTime())->format('Y-m-d H:i:s'),
'custom_data' => json_encode(
[
'passwordInSap' => $data->PaswdData->PaswdHash ?? '',
'sap' => [
'discountIndex' => $data->PersonalData->DiscountIndex,
'cards' => [],
],
]
),
],
$addressData
)
)->execute();
return (int) sqlInsertId();
});
}
private function updatePriceLevelByDiscountIndex(\User $user, string $discountIndex): void
{
$priceLevelId = sqlQueryBuilder()
->select('id')
->from('price_levels')
->where(Operator::equals(['descr' => $discountIndex]))
->execute()->fetchColumn();
sqlGetConnection()->transactional(function () use ($user, $priceLevelId) {
sqlQueryBuilder()
->delete('users_dealer_price_level')
->where(Operator::equals(
[
'id_user' => $user->id,
]
))->execute();
if ($priceLevelId) {
sqlQueryBuilder()
->insert('users_dealer_price_level')
->directValues(
[
'id_user' => $user->id,
'id_price_level' => $priceLevelId,
]
)->execute();
}
});
}
private function getAddressPrefix(string $type): string
{
if ($type === 'SHIPPING') {
return 'delivery_';
}
return '';
}
private function getAddressField(string $key): ?string
{
$map = [
'FirstName' => 'name',
'LastName' => 'surname',
'Street' => 'street',
'City' => 'city',
'PostlCod' => 'zip',
'Country' => 'country',
'Company' => 'firm',
'VatIdentNumber' => 'ico',
'CompRegNumber' => 'dic',
];
return $map[$key] ?? null;
}
}