From aac5b8e0becf1d87b764e5a76082a9f561d53221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sat, 2 May 2026 23:23:20 +0200 Subject: [PATCH] Allow to select which method should be used to in "Create from URL feature" --- src/Controller/InfoProviderController.php | 25 +++--- .../InfoProviderSystem/FromURLFormType.php | 82 +++++++++++++++++++ .../CreateFromUrlHelper.php | 52 ++++++++++++ src/Twig/MiscExtension.php | 13 ++- templates/_navbar.html.twig | 2 +- .../from_url/from_url.html.twig | 15 ++++ translations/messages.en.xlf | 24 ++++++ 7 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 src/Form/InfoProviderSystem/FromURLFormType.php create mode 100644 src/Services/InfoProviderSystem/CreateFromUrlHelper.php diff --git a/src/Controller/InfoProviderController.php b/src/Controller/InfoProviderController.php index cd076d67..074d3894 100644 --- a/src/Controller/InfoProviderController.php +++ b/src/Controller/InfoProviderController.php @@ -26,8 +26,10 @@ namespace App\Controller; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\Part; use App\Exceptions\OAuthReconnectRequiredException; +use App\Form\InfoProviderSystem\FromURLFormType; use App\Form\InfoProviderSystem\PartSearchType; use App\Services\InfoProviderSystem\ExistingPartFinder; +use App\Services\InfoProviderSystem\CreateFromUrlHelper; use App\Services\InfoProviderSystem\PartInfoRetriever; use App\Services\InfoProviderSystem\ProviderRegistry; use App\Services\InfoProviderSystem\Providers\GenericWebProvider; @@ -219,35 +221,31 @@ class InfoProviderController extends AbstractController } #[Route('/from_url', name: 'info_providers_from_url')] - public function fromURL(Request $request, GenericWebProvider $provider): Response + public function fromURL(Request $request, GenericWebProvider $provider, CreateFromUrlHelper $fromUrlHelper): Response { $this->denyAccessUnlessGranted('@info_providers.create_parts'); - if (!$provider->isActive()) { + if (!$fromUrlHelper->canCreateFromUrl()) { $this->addFlash('error', "Generic Web Provider is not active. Please enable it in the provider settings."); return $this->redirectToRoute('info_providers_list'); } - $formBuilder = $this->createFormBuilder(); - $formBuilder->add('url', UrlType::class, [ - 'label' => 'info_providers.from_url.url.label', - 'required' => true, - ]); - $formBuilder->add('submit', SubmitType::class, [ - 'label' => 'info_providers.search.submit', - ]); - - $form = $formBuilder->getForm(); + $form = $this->createForm(FromURLFormType::class); $form->handleRequest($request); $partDetail = null; if ($form->isSubmitted() && $form->isValid()) { //Try to retrieve the part detail from the given URL $url = $form->get('url')->getData(); + + $method = $form->get('method')->getData(); + $no_cache = $form->get('no_cache')->getData(); + try { + //It's okay if we use the cached results here, as its just for convenience $searchResult = $this->infoRetriever->searchByKeyword( keyword: $url, - providers: [$provider] + providers: [$method], ); if (count($searchResult) === 0) { @@ -258,6 +256,7 @@ class InfoProviderController extends AbstractController return $this->redirectToRoute('info_providers_create_part', [ 'providerKey' => $searchResult->provider_key, 'providerId' => $searchResult->provider_id, + 'no_cache' => $no_cache ? 1 : null, ]); } } catch (ExceptionInterface $e) { diff --git a/src/Form/InfoProviderSystem/FromURLFormType.php b/src/Form/InfoProviderSystem/FromURLFormType.php new file mode 100644 index 00000000..cad7a0f5 --- /dev/null +++ b/src/Form/InfoProviderSystem/FromURLFormType.php @@ -0,0 +1,82 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Form\InfoProviderSystem; + +use App\Services\InfoProviderSystem\ProviderRegistry; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\UrlType; +use Symfony\Component\Form\FormBuilderInterface; + +class FromURLFormType extends AbstractType +{ + public function __construct(private readonly ProviderRegistry $providerRegistry) + { + + } + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder->add('url', UrlType::class, [ + 'label' => 'info_providers.from_url.url.label', + 'required' => true, + ]); + + + $builder->add('method', ChoiceType::class, [ + 'expanded' => true, + 'data' => 'generic_web', //Default value + 'label' => 'info_providers.from_url.method', + 'choices' => [ + 'info_providers.from_url.method.generic_web' => 'generic_web', + 'info_providers.from_url.method.ai_web' => 'ai_web', + ], + 'choice_attr' => function ($choice, $key, $value) { + //Disable all providers that are not active + $provider = $this->providerRegistry->getProviderByKey($value); + if (!$provider->isActive()) { + return ['disabled' => 'disabled']; + } + + return []; + }, + + //Render the choices as inline radio buttons + 'label_attr' => [ + 'class' => 'radio-inline', + ], + ]); + + $builder->add('no_cache', CheckboxType::class, [ + 'label' => 'info_providers.from_url.no_cache', + 'required' => false, + ]); + + $builder->add('submit', SubmitType::class, [ + 'label' => 'info_providers.search.submit', + ]); + } +} diff --git a/src/Services/InfoProviderSystem/CreateFromUrlHelper.php b/src/Services/InfoProviderSystem/CreateFromUrlHelper.php new file mode 100644 index 00000000..46a2f767 --- /dev/null +++ b/src/Services/InfoProviderSystem/CreateFromUrlHelper.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Services\InfoProviderSystem; + +use App\Entity\UserSystem\User; +use Symfony\Bundle\SecurityBundle\Security; + +final readonly class CreateFromUrlHelper +{ + public function __construct(private Security $security, private ProviderRegistry $providerRegistry) + { + } + + /** + * Checks if at least one provider can create parts from an URL and the current user is allowed to use it. + * This is used to determine if the "From URL" feature should be shown to the user. + * @return bool + */ + public function canCreateFromUrl(): bool + { + if (!$this->security->isGranted('@info_providers.create_parts')) { + return false; + } + + //Check if either the generic web provider or the ai web provider is active + $genericWebProvider = $this->providerRegistry->getProviderByKey('generic_web'); + $aiWebProvider = $this->providerRegistry->getProviderByKey('ai_web'); + + return $genericWebProvider->isActive() || $aiWebProvider->isActive(); + } +} diff --git a/src/Twig/MiscExtension.php b/src/Twig/MiscExtension.php index 390ad084..565d56f2 100644 --- a/src/Twig/MiscExtension.php +++ b/src/Twig/MiscExtension.php @@ -22,6 +22,7 @@ declare(strict_types=1); */ namespace App\Twig; +use App\Services\InfoProviderSystem\CreateFromUrlHelper; use Twig\Attribute\AsTwigFunction; use App\Settings\SettingsIcon; use Symfony\Component\HttpFoundation\Request; @@ -34,7 +35,7 @@ use Twig\Extension\AbstractExtension; final readonly class MiscExtension { - public function __construct(private EventCommentNeededHelper $eventCommentNeededHelper) + public function __construct(private EventCommentNeededHelper $eventCommentNeededHelper, private CreateFromUrlHelper $fromUrlHelper) { } @@ -84,4 +85,14 @@ final readonly class MiscExtension return $request->getBaseUrl().$request->getPathInfo().$qs; } + + /** + * Returns true if the from url provider is active, false otherwise. + * @return bool + */ + #[AsTwigFunction(name: 'create_from_url_active')] + public function create_from_url_active(): bool + { + return $this->fromUrlHelper->canCreateFromUrl(); + } } diff --git a/templates/_navbar.html.twig b/templates/_navbar.html.twig index 57331370..7719ab2b 100644 --- a/templates/_navbar.html.twig +++ b/templates/_navbar.html.twig @@ -52,7 +52,7 @@ {% trans %}info_providers.search.title{% endtrans %} - {% if settings_instance('generic_web_provider').enabled %} + {% if create_from_url_active() %}
  • diff --git a/templates/info_providers/from_url/from_url.html.twig b/templates/info_providers/from_url/from_url.html.twig index 3370a94c..15aa225f 100644 --- a/templates/info_providers/from_url/from_url.html.twig +++ b/templates/info_providers/from_url/from_url.html.twig @@ -16,6 +16,21 @@ {{ form_start(form) }} {{ form_row(form.url) }} + + {{ form_row(form.method) }} + + + +
    +
    + {{ form_row(form.no_cache) }} +
    +
    + {{ form_row(form.submit) }} {{ form_end(form) }} {% endblock %} diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index f30ffb9f..cb071128 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -13157,5 +13157,29 @@ Buerklin-API Authentication server: Do not cache result details / Force fresh part detail retrieval + + + info_providers.from_url.method.generic_web + Classic Web Scraper + + + + + info_providers.from_url.method.ai_web + AI Web Scraper + + + + + info_providers.from_url.method + Method + + + + + info_providers.from_url.no_cache + Ignore cache / Force fresh info retrieval + +