diff --git a/.env b/.env index 19870ae9..70f22e5d 100644 --- a/.env +++ b/.env @@ -67,6 +67,16 @@ 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 ################################################################################## @@ -82,6 +92,26 @@ PROVIDER_DIGIKEY_LANGUAGE=en # The country to get results for PROVIDER_DIGIKEY_COUNTRY=DE +# Farnell Provider: +# You can get your API key from https://partner.element14.com/ +PROVIDER_ELEMENT14_KEY= +# Configure the store domain you want to use. This decides the language and currency of results. You can get a list of available stores from https://partner.element14.com/docs/Product_Search_API_REST__Description +PROVIDER_ELEMENT14_STORE_ID=de.farnell.com + +# TME Provider: +# You can get your API key from https://developers.tme.eu/en/ +PROVIDER_TME_KEY= +PROVIDER_TME_SECRET= +# The currency to get prices in +PROVIDER_TME_CURRENCY=EUR +# The language to get results in (en, de, pl) +PROVIDER_TME_LANGUAGE=en +# The country to get results for +PROVIDER_TME_COUNTRY=DE +# [DEPRECATED] Set this to 1 to get gross prices (including VAT) instead of net prices +# With private API keys, this option cannot be used anymore is ignored by Part-DB. The VAT inclusion depends on your TME account settings. +PROVIDER_TME_GET_GROSS_PRICES=1 + # Octopart / Nexar Provider: # You can get your API key from https://nexar.com/api PROVIDER_OCTOPART_CLIENT_ID= @@ -96,6 +126,82 @@ PROVIDER_OCTOPART_SEARCH_LIMIT=10 # Set to false to include non authorized offers in the results PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS=1 +# Mouser Provider API V2: +# You can get your API key from https://www.mouser.it/api-hub/ +PROVIDER_MOUSER_KEY= +# Filter search results by RoHS compliance and stock availability: +# Available options: None | Rohs | InStock | RohsAndInStock +PROVIDER_MOUSER_SEARCH_OPTION='None' +# The number of results to get from Mouser while searching (please note that this value is max 50) +PROVIDER_MOUSER_SEARCH_LIMIT=50 +# It is recommended to leave this set to 'true'. The option is not really good doumented by Mouser: +# Used when searching for keywords in the language specified when you signed up for Search API. +PROVIDER_MOUSER_SEARCH_WITH_SIGNUP_LANGUAGE='true' + +# LCSC Provider: +# LCSC does not provide an offical API, so this used the API LCSC uses to render their webshop. +# LCSC did not intended the use of this API and it could break any time, so use it at your own risk. + +# We dont require an API key for LCSC, just set this to 1 to enable LCSC support +PROVIDER_LCSC_ENABLED=0 +# The currency to get prices in (e.g. EUR, USD, etc.) +PROVIDER_LCSC_CURRENCY=EUR + +# Oemsecrets Provider API 3.0.1: +# You can get your API key from https://www.oemsecrets.com/api +PROVIDER_OEMSECRETS_KEY= +# The country you want the output for +PROVIDER_OEMSECRETS_COUNTRY_CODE=DE +# Available country code are: +# AD, AE, AQ, AR, AT, AU, BE, BO, BR, BV, BY, CA, CH, CL, CN, CO, CZ, DE, DK, EC, EE, EH, +# ES, FI, FK, FO, FR, GB, GE, GF, GG, GI, GL, GR, GS, GY, HK, HM, HR, HU, IE, IM, IN, IS, +# IT, JM, JP, KP, KR, KZ, LI, LK, LT, LU, MC, MD, ME, MK, MT, NL, NO, NZ, PE, PH, PL, PT, +# PY, RO, RS, RU, SB, SD, SE, SG, SI, SJ, SK, SM, SO, SR, SY, SZ, TC, TF, TG, TH, TJ, TK, +# TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VE, VG, VI, VN, VU, WF, YE, +# ZA, ZM, ZW +# +# The currency you want the prices to be displayed in +PROVIDER_OEMSECRETS_CURRENCY=EUR +# Available currency are:AUD, CAD, CHF, CNY, DKK, EUR, GBP, HKD, ILS, INR, JPY, KRW, NOK, +# NZD, RUB, SEK, SGD, TWD, USD +# +# If PROVIDER_OEMSECRETS_ZERO_PRICE is set to 0, distributors with zero prices +# will be discarded from the creation of a new part (set to 1 otherwise) +PROVIDER_OEMSECRETS_ZERO_PRICE=0 +# +# When PROVIDER_OEMSECRETS_SET_PARAM is set to 1 the parameters for the part are generated +# from the description transforming unstructured descriptions into structured parameters; +# each parameter in description should have the form: "...;name1:value1;name2:value2" +PROVIDER_OEMSECRETS_SET_PARAM=1 +# +# This environment variable determines the sorting criteria for product results. +# The sorting process first arranges items based on the provided keyword. +# Then, if set to 'C', it further sorts by completeness (prioritizing items with the most +# detailed information). If set to 'M', it further sorts by manufacturer name. +#If unset or set to any other value, no sorting is performed. +PROVIDER_OEMSECRETS_SORT_CRITERIA=C + + +# 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 864effd9..09ab8fd4 100644 --- a/src/Services/InfoProviderSystem/Providers/PollinProvider.php +++ b/src/Services/InfoProviderSystem/Providers/PollinProvider.php @@ -31,7 +31,6 @@ 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; @@ -40,7 +39,8 @@ class PollinProvider implements InfoProviderInterface { public function __construct(private readonly HttpClientInterface $client, - private readonly PollinSettings $settings, + #[Autowire(env: 'bool:PROVIDER_POLLIN_ENABLED')] + private readonly bool $enabled = true, ) { } @@ -62,7 +62,7 @@ class PollinProvider implements InfoProviderInterface public function isActive(): bool { - return $this->settings->enabled; + return $this->enabled; } public function searchByKeyword(string $keyword): array diff --git a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php index ebc62dd5..0c31c411 100644 --- a/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php +++ b/src/Services/InfoProviderSystem/Providers/ReicheltProvider.php @@ -29,7 +29,6 @@ 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; @@ -40,7 +39,16 @@ class ReicheltProvider implements InfoProviderInterface public const DISTRIBUTOR_NAME = "Reichelt"; public function __construct(private readonly HttpClientInterface $client, - private readonly ReicheltSettings $settings, + #[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", ) { } @@ -62,7 +70,7 @@ class ReicheltProvider implements InfoProviderInterface public function isActive(): bool { - return $this->settings->enabled; + return $this->enabled; } public function searchByKeyword(string $keyword): array @@ -113,8 +121,8 @@ class ReicheltProvider implements InfoProviderInterface sprintf( 'https://www.reichelt.com/?ACTION=514&id=74&article=%s&LANGUAGE=%s&CCOUNTRY=%s', $id, - strtoupper($this->settings->language), - strtoupper($this->settings->country) + strtoupper($this->language), + strtoupper($this->country) ) ); $json = $response->toArray(); @@ -125,8 +133,8 @@ class ReicheltProvider implements InfoProviderInterface $response = $this->client->request('GET', $productPage, [ 'query' => [ - 'CCTYPE' => $this->settings->includeVAT ? 'private' : 'business', - 'currency' => $this->settings->currency, + 'CCTYPE' => $this->includeVAT ? 'private' : 'business', + 'currency' => $this->currency, ], ]); $html = $response->getContent(); @@ -150,7 +158,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->settings->includeVAT)] + [new PriceDTO(1.0, $priceString, $currency, $this->includeVAT)] , $this->parseBatchPrices($dom, $currency)), product_url: $productPage ); @@ -210,7 +218,7 @@ class ReicheltProvider implements InfoProviderInterface //Strip any non-numeric characters $priceString = preg_replace('/[^0-9.]/', '', $priceString); - $prices[] = new PriceDTO($minAmount, $priceString, $currency, $this->settings->includeVAT); + $prices[] = new PriceDTO($minAmount, $priceString, $currency, $this->includeVAT); }); return $prices; @@ -262,7 +270,7 @@ class ReicheltProvider implements InfoProviderInterface private function getBaseURL(): string { //Without the trailing slash - return 'https://www.reichelt.com/' . strtolower($this->settings->country) . '/' . strtolower($this->settings->language); + return 'https://www.reichelt.com/' . strtolower($this->country) . '/' . strtolower($this->language); } public function getCapabilities(): array diff --git a/src/Settings/InfoProviderSystem/InfoProviderSettings.php b/src/Settings/InfoProviderSystem/InfoProviderSettings.php index 109fbc02..d087facc 100644 --- a/src/Settings/InfoProviderSystem/InfoProviderSettings.php +++ b/src/Settings/InfoProviderSystem/InfoProviderSettings.php @@ -46,10 +46,4 @@ 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 deleted file mode 100644 index 8a7713c6..00000000 --- a/src/Settings/InfoProviderSystem/PollinSettings.php +++ /dev/null @@ -1,37 +0,0 @@ -. - */ - -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 deleted file mode 100644 index 8672ae69..00000000 --- a/src/Settings/InfoProviderSystem/ReicheltSettings.php +++ /dev/null @@ -1,62 +0,0 @@ -. - */ - -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 f414e984..d44e3325 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"), formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR"]], envVar: "PROVIDER_TME_COUNTRY")] + #[SettingsParameter(label: new TM("settings.ips.tme.country"), envVar: "PROVIDER_TME_COUNTRY", formType: CountryType::class, formOptions: ["preferred_choices" => ["DE", "PL", "GB", "FR"]])] #[Assert\Country] public string $country = "DE"; diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 3ca784cd..0a6c97b0 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -242,7 +242,7 @@ part.info.timetravel_hint - Please note that this feature is experimental, so the info may not be correct.]]> + This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the info may not be correct.</i> @@ -731,10 +731,10 @@ user.edit.tfa.disable_tfa_message - 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!]]>
+ 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>
@@ -885,9 +885,9 @@ The user will have to set up all two-factor authentication methods again and pri entity.delete.message - -Sub elements will be moved upwards.]]> + This can not be undone! +<br> +Sub elements will be moved upwards. @@ -1441,7 +1441,7 @@ Sub elements will be moved upwards.]]> homepage.github.text - GitHub project page]]> + Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a> @@ -1463,7 +1463,7 @@ Sub elements will be moved upwards.]]> homepage.help.text - GitHub page]]> + Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a> @@ -1705,7 +1705,7 @@ Sub elements will be moved upwards.]]> email.pw_reset.fallback - %url% and enter the following info]]> + If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info @@ -1735,7 +1735,7 @@ Sub elements will be moved upwards.]]> email.pw_reset.valid_unit %date% - %date%.]]> + The reset token will be valid until <i>%date%</i>. @@ -3578,8 +3578,8 @@ Sub elements will be moved upwards.]]> tfa_google.disable.confirm_message - -Also note that without two-factor authentication, your account is no longer as well protected against attackers!]]> + 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! @@ -3599,7 +3599,7 @@ Also note that without two-factor authentication, your account is no longer as w tfa_google.step.download - Google Authenticator oder FreeOTP Authenticator)]]> + 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>) @@ -3841,8 +3841,8 @@ Also note that without two-factor authentication, your account is no longer as w tfa_trustedDevices.explanation - all computers here.]]> + 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. @@ -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 - Twig documentation and Wiki for more information.]]> + 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. @@ -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 - %keyword%]]> + Searching parts with keyword <b>%keyword%</b> @@ -10174,13 +10174,13 @@ Element 3 project.builds.number_of_builds_possible - %max_builds% builds of this project.]]> + You have enough stocked to build <b>%max_builds%</b> builds of this project. project.builds.check_project_status - "%project_status%". You should check if you really want to build the project with this status!]]> + The current project status is <b>"%project_status%"</b>. You should check if you really want to build the project with this status! @@ -10282,7 +10282,7 @@ Element 3 entity.select.add_hint - to create nested structures, e.g. "Node 1->Node 1.1"]]> + Use -> to create nested structures, e.g. "Node 1->Node 1.1" @@ -10306,13 +10306,13 @@ Element 3 homepage.first_steps.introduction - documentation or start to creating the following data structures:]]> + Your database is still empty. You might want to read the <a href="%url%">documentation</a> or start to creating the following data structures: homepage.first_steps.create_part - create a new part.]]> + Or you can directly <a href="%url%">create a new part</a>. @@ -10324,7 +10324,7 @@ Element 3 homepage.forum.text - discussion forum]]> + For questions about Part-DB use the <a href="%href%" class="link-external" target="_blank">discussion forum</a> @@ -10978,7 +10978,7 @@ Element 3 parts.import.help_documentation - documentation for more information on the file format.]]> + See the <a href="%link%">documentation</a> 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 - %other% into %target%?]]> + Do you really want to merge <b>%other%</b> into <b>%target%</b>? part.merge.confirm.message - %other% will be deleted, and the part will be saved with the shown information.]]> + <b>%other%</b> will be deleted, and the part will be saved with the shown information. @@ -12892,35 +12892,5 @@ 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. - -