diff --git a/.env b/.env index 34c1b49e..19870ae9 100644 --- a/.env +++ b/.env @@ -67,16 +67,6 @@ ERROR_PAGE_ADMIN_EMAIL='' # If this is set to true, solutions to common problems are shown on error pages. Disable this, if you do not want your users to see them... ERROR_PAGE_SHOW_HELP=1 -################################################################################## -# Part table settings -################################################################################## - -# The default page size for the part table (set to -1 to show all parts on one page) -#TABLE_DEFAULT_PAGE_SIZE=50 -# Configure which columns will be visible by default in the parts table (and in which order). -# This is a comma separated list of column names. See documentation for available values. -#TABLE_PARTS_DEFAULT_COLUMNS=name,description,category,footprint,manufacturer,storage_location,amount - ################################################################################## # Info provider settings ################################################################################## @@ -106,27 +96,6 @@ PROVIDER_OCTOPART_SEARCH_LIMIT=10 # Set to false to include non authorized offers in the results PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS=1 - -# Reichelt provider: -# Reichelt.com offers no official API, so this info provider webscrapes the website to extract info -# It could break at any time, use it at your own risk -# We dont require an API key for Reichelt, just set this to 1 to enable Reichelt support -PROVIDER_REICHELT_ENABLED=0 -# The country to get prices for -PROVIDER_REICHELT_COUNTRY=DE -# The language to get results in (en, de, fr, nl, pl, it, es) -PROVIDER_REICHELT_LANGUAGE=en -# Include VAT in prices (set to 1 to include VAT, 0 to exclude VAT) -PROVIDER_REICHELT_INCLUDE_VAT=1 -# The currency to get prices in (only for countries with countries other than EUR) -PROVIDER_REICHELT_CURRENCY=EUR - -# Pollin provider: -# Pollin.de offers no official API, so this info provider webscrapes the website to extract info -# It could break at any time, use it at your own risk -# We dont require an API key for Pollin, just set this to 1 to enable Pollin support -PROVIDER_POLLIN_ENABLED=0 - ################################################################################## # EDA integration related settings ################################################################################## diff --git a/src/Services/InfoProviderSystem/Providers/PollinProvider.php b/src/Services/InfoProviderSystem/Providers/PollinProvider.php index 09ab8fd4..864effd9 100644 --- a/src/Services/InfoProviderSystem/Providers/PollinProvider.php +++ b/src/Services/InfoProviderSystem/Providers/PollinProvider.php @@ -31,6 +31,7 @@ use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use App\Settings\InfoProviderSystem\PollinSettings; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DomCrawler\Crawler; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -39,8 +40,7 @@ class PollinProvider implements InfoProviderInterface { public function __construct(private readonly HttpClientInterface $client, - #[Autowire(env: 'bool:PROVIDER_POLLIN_ENABLED')] - private readonly bool $enabled = true, + private readonly PollinSettings $settings, ) { } @@ -62,7 +62,7 @@ class PollinProvider implements InfoProviderInterface public function isActive(): bool { - return $this->enabled; + return $this->settings->enabled; } public function searchByKeyword(string $keyword): array diff --git a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php index 0c31c411..ebc62dd5 100644 --- a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php +++ b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php @@ -29,6 +29,7 @@ use App\Services\InfoProviderSystem\DTOs\PartDetailDTO; use App\Services\InfoProviderSystem\DTOs\PriceDTO; use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO; use App\Services\InfoProviderSystem\DTOs\SearchResultDTO; +use App\Settings\InfoProviderSystem\ReicheltSettings; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\DomCrawler\Crawler; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -39,16 +40,7 @@ class ReicheltProvider implements InfoProviderInterface public const DISTRIBUTOR_NAME = "Reichelt"; public function __construct(private readonly HttpClientInterface $client, - #[Autowire(env: "bool:PROVIDER_REICHELT_ENABLED")] - private readonly bool $enabled = true, - #[Autowire(env: "PROVIDER_REICHELT_LANGUAGE")] - private readonly string $language = "en", - #[Autowire(env: "PROVIDER_REICHELT_COUNTRY")] - private readonly string $country = "DE", - #[Autowire(env: "PROVIDER_REICHELT_INCLUDE_VAT")] - private readonly bool $includeVAT = false, - #[Autowire(env: "PROVIDER_REICHELT_CURRENCY")] - private readonly string $currency = "EUR", + private readonly ReicheltSettings $settings, ) { } @@ -70,7 +62,7 @@ class ReicheltProvider implements InfoProviderInterface public function isActive(): bool { - return $this->enabled; + return $this->settings->enabled; } public function searchByKeyword(string $keyword): array @@ -121,8 +113,8 @@ class ReicheltProvider implements InfoProviderInterface sprintf( 'https://www.reichelt.com/?ACTION=514&id=74&article=%s&LANGUAGE=%s&CCOUNTRY=%s', $id, - strtoupper($this->language), - strtoupper($this->country) + strtoupper($this->settings->language), + strtoupper($this->settings->country) ) ); $json = $response->toArray(); @@ -133,8 +125,8 @@ class ReicheltProvider implements InfoProviderInterface $response = $this->client->request('GET', $productPage, [ 'query' => [ - 'CCTYPE' => $this->includeVAT ? 'private' : 'business', - 'currency' => $this->currency, + 'CCTYPE' => $this->settings->includeVAT ? 'private' : 'business', + 'currency' => $this->settings->currency, ], ]); $html = $response->getContent(); @@ -158,7 +150,7 @@ class ReicheltProvider implements InfoProviderInterface distributor_name: self::DISTRIBUTOR_NAME, order_number: $json[0]['article_artnr'], prices: array_merge( - [new PriceDTO(1.0, $priceString, $currency, $this->includeVAT)] + [new PriceDTO(1.0, $priceString, $currency, $this->settings->includeVAT)] , $this->parseBatchPrices($dom, $currency)), product_url: $productPage ); @@ -218,7 +210,7 @@ class ReicheltProvider implements InfoProviderInterface //Strip any non-numeric characters $priceString = preg_replace('/[^0-9.]/', '', $priceString); - $prices[] = new PriceDTO($minAmount, $priceString, $currency, $this->includeVAT); + $prices[] = new PriceDTO($minAmount, $priceString, $currency, $this->settings->includeVAT); }); return $prices; @@ -270,7 +262,7 @@ class ReicheltProvider implements InfoProviderInterface private function getBaseURL(): string { //Without the trailing slash - return 'https://www.reichelt.com/' . strtolower($this->country) . '/' . strtolower($this->language); + return 'https://www.reichelt.com/' . strtolower($this->settings->country) . '/' . strtolower($this->settings->language); } public function getCapabilities(): array diff --git a/src/Settings/InfoProviderSystem/InfoProviderSettings.php b/src/Settings/InfoProviderSystem/InfoProviderSettings.php index d087facc..109fbc02 100644 --- a/src/Settings/InfoProviderSystem/InfoProviderSettings.php +++ b/src/Settings/InfoProviderSystem/InfoProviderSettings.php @@ -46,4 +46,10 @@ class InfoProviderSettings #[EmbeddedSettings] public ?OEMSecretsSettings $oemsecrets = null; + + #[EmbeddedSettings] + public ?ReicheltSettings $reichelt = null; + + #[EmbeddedSettings] + public ?PollinSettings $pollin = null; } \ No newline at end of file diff --git a/src/Settings/InfoProviderSystem/PollinSettings.php b/src/Settings/InfoProviderSystem/PollinSettings.php new file mode 100644 index 00000000..8a7713c6 --- /dev/null +++ b/src/Settings/InfoProviderSystem/PollinSettings.php @@ -0,0 +1,37 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\InfoProviderSystem; + +use App\Settings\SettingsIcon; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Symfony\Component\Translation\TranslatableMessage as TM; + +#[Settings(label: new TM("settings.ips.pollin"), description: new TM("settings.ips.pollin.help"))] +#[SettingsIcon("fa-plug")] +class PollinSettings +{ + #[SettingsParameter(label: new TM("settings.ips.lcsc.enabled"), envVar: "bool:PROVIDER_POLLIN_ENABLED")] + public bool $enabled = false; +} \ No newline at end of file diff --git a/src/Settings/InfoProviderSystem/ReicheltSettings.php b/src/Settings/InfoProviderSystem/ReicheltSettings.php new file mode 100644 index 00000000..8672ae69 --- /dev/null +++ b/src/Settings/InfoProviderSystem/ReicheltSettings.php @@ -0,0 +1,62 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\InfoProviderSystem; + +use App\Settings\SettingsIcon; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Jbtronics\SettingsBundle\Settings\SettingsTrait; +use Symfony\Component\Form\Extension\Core\Type\CountryType; +use Symfony\Component\Form\Extension\Core\Type\CurrencyType; +use Symfony\Component\Form\Extension\Core\Type\LanguageType; +use Symfony\Component\Translation\TranslatableMessage as TM; +use Symfony\Component\Validator\Constraints as Assert; + +#[Settings(label: new TM("settings.ips.reichelt"), description: new TM("settings.ips.reichelt.help"))] +#[SettingsIcon("fa-plug")] +class ReicheltSettings +{ + use SettingsTrait; + + public const SUPPORTED_LANGUAGE = ["en", "de", "fr", "nl", "pl", "it", "es"]; + + #[SettingsParameter(label: new TM("settings.ips.lcsc.enabled"), envVar: "bool:PROVIDER_REICHELT_ENABLED")] + public bool $enabled = false; + + #[SettingsParameter(label: new TM("settings.ips.tme.currency"), formType: CurrencyType::class, formOptions: ["preferred_choices" => ["EUR"]], envVar: "PROVIDER_REICHELT_CURRENCY")] + public string $currency = "EUR"; + + #[SettingsParameter(label: new TM("settings.ips.tme.language"), formType: LanguageType::class, formOptions: ["preferred_choices" => self::SUPPORTED_LANGUAGE], envVar: "PROVIDER_REICHELT_LANGUAGE")] + #[Assert\Language()] + #[Assert\Choice(choices: self::SUPPORTED_LANGUAGE)] + public string $language = "en"; + + #[SettingsParameter(label: new TM("settings.ips.tme.country"), envVar: "PROVIDER_REICHELT_COUNTRY", formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR"]])] + #[Assert\Country] + public string $country = "DE"; + + #[SettingsParameter(label: new TM("settings.ips.reichelt.include_vat"), envVar: "bool:PROVIDER_REICHELT_INCLUDE_VAT")] + public bool $includeVAT = true; + +} \ No newline at end of file diff --git a/src/Settings/InfoProviderSystem/TMESettings.php b/src/Settings/InfoProviderSystem/TMESettings.php index d44e3325..f414e984 100644 --- a/src/Settings/InfoProviderSystem/TMESettings.php +++ b/src/Settings/InfoProviderSystem/TMESettings.php @@ -56,7 +56,7 @@ class TMESettings #[Assert\Language] public string $language = "en"; - #[SettingsParameter(label: new TM("settings.ips.tme.country"), envVar: "PROVIDER_TME_COUNTRY", formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR"]])] + #[SettingsParameter(label: new TM("settings.ips.tme.country"), formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR"]], envVar: "PROVIDER_TME_COUNTRY")] #[Assert\Country] public string $country = "DE"; diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 0a6c97b0..3ca784cd 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -242,7 +242,7 @@ part.info.timetravel_hint - This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i> + Please note that this feature is experimental, so the info may not be correct.]]> @@ -731,10 +731,10 @@ user.edit.tfa.disable_tfa_message - This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>! -<br> -The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br> -<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b> + all active two-factor authentication methods of the user and delete the backup codes! +
+The user will have to set up all two-factor authentication methods again and print new backup codes!

+Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!]]>
@@ -885,9 +885,9 @@ The user will have to set up all two-factor authentication methods again and pri entity.delete.message - This can not be undone! -<br> -Sub elements will be moved upwards. + +Sub elements will be moved upwards.]]> @@ -1441,7 +1441,7 @@ Sub elements will be moved upwards. homepage.github.text - Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a> + GitHub project page]]> @@ -1463,7 +1463,7 @@ Sub elements will be moved upwards. homepage.help.text - Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a> + GitHub page]]> @@ -1705,7 +1705,7 @@ Sub elements will be moved upwards. email.pw_reset.fallback - If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info + %url% and enter the following info]]> @@ -1735,7 +1735,7 @@ Sub elements will be moved upwards. email.pw_reset.valid_unit %date% - The reset token will be valid until <i>%date%</i>. + %date%.]]> @@ -3578,8 +3578,8 @@ Sub elements will be moved upwards. tfa_google.disable.confirm_message - If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br> -Also note that without two-factor authentication, your account is no longer as well protected against attackers! + +Also note that without two-factor authentication, your account is no longer as well protected against attackers!]]> @@ -3599,7 +3599,7 @@ Also note that without two-factor authentication, your account is no longer as w tfa_google.step.download - Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>) + Google Authenticator oder FreeOTP Authenticator)]]> @@ -3841,8 +3841,8 @@ Also note that without two-factor authentication, your account is no longer as w tfa_trustedDevices.explanation - When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed. -If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here. + all computers here.]]> @@ -5313,7 +5313,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can label_options.lines_mode.help - If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://docs.part-db.de/usage/labels.html#twig-mode">Wiki</a> for more information. + Twig documentation and Wiki for more information.]]> @@ -9388,25 +9388,25 @@ Element 3 filter.parameter_value_constraint.operator.< - Typ. Value < + filter.parameter_value_constraint.operator.> - Typ. Value > + ]]> filter.parameter_value_constraint.operator.<= - Typ. Value <= + filter.parameter_value_constraint.operator.>= - Typ. Value >= + =]]> @@ -9514,7 +9514,7 @@ Element 3 parts_list.search.searching_for - Searching parts with keyword <b>%keyword%</b> + %keyword%]]> @@ -10174,13 +10174,13 @@ Element 3 project.builds.number_of_builds_possible - You have enough stocked to build <b>%max_builds%</b> builds of this project. + %max_builds% builds of this project.]]> project.builds.check_project_status - The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status! + "%project_status%". You should check if you really want to build the project with this status!]]> @@ -10282,7 +10282,7 @@ Element 3 entity.select.add_hint - Use -> to create nested structures, e.g. "Node 1->Node 1.1" + to create nested structures, e.g. "Node 1->Node 1.1"]]> @@ -10306,13 +10306,13 @@ Element 3 homepage.first_steps.introduction - Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures: + documentation or start to creating the following data structures:]]> homepage.first_steps.create_part - Or you can directly <a href="%url%">create a new part</a>. + create a new part.]]> @@ -10324,7 +10324,7 @@ Element 3 homepage.forum.text - For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a> + discussion forum]]> @@ -10978,7 +10978,7 @@ Element 3 parts.import.help_documentation - See the <a href="%link%">documentation</a> for more information on the file format. + documentation for more information on the file format.]]> @@ -11158,7 +11158,7 @@ Element 3 part.filter.lessThanDesired - In stock less than desired (total amount < min. amount) + @@ -11970,13 +11970,13 @@ Please note, that you can not impersonate a disabled user. If you try you will g part.merge.confirm.title - Do you really want to merge <b>%other%</b> into <b>%target%</b>? + %other% into %target%?]]> part.merge.confirm.message - <b>%other%</b> will be deleted, and the part will be saved with the shown information. + %other% will be deleted, and the part will be saved with the shown information.]]> @@ -12892,5 +12892,35 @@ Please note, that you can not impersonate a disabled user. If you try you will g This part contains more than one stock. Change the location by hand to select, which stock to choose. + + + settings.ips.reichelt + Reichelt + + + + + settings.ips.reichelt.help + Reichelt.com offers no official API, so this info provider webscrapes the website to extract info. It could break at any time, use it at your own risk. + + + + + settings.ips.reichelt.include_vat + Include VAT in prices + + + + + settings.ips.pollin + Pollin + + + + + settings.ips.pollin.help + Pollin.de offers no official API, so this info provider webscrapes the website to extract info. It could break at any time, use it at your own risk. + +