mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-07-31 21:51:38 +00:00
Compare commits
8 commits
1a8ff831ab
...
43ac8c23c7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43ac8c23c7 | ||
|
|
e80e4a1bcd | ||
|
|
e23dde8208 | ||
|
|
c8a1670f0b | ||
|
|
7edbf35e46 | ||
|
|
30aba1db6f | ||
|
|
dcc431d28c | ||
|
|
5054642d41 |
25 changed files with 14498 additions and 228 deletions
8
.env
8
.env
|
|
@ -5,6 +5,14 @@
|
|||
# Share that value with nobody and keep it secret
|
||||
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
|
||||
|
||||
# Change this and uncomment the following line to set the trusted hosts for your Part-DB installation, aka under which
|
||||
# domain names it is reachable. This is makes things more secure, because it can prevent certain header attacks.
|
||||
# You have to escape dots in the domain name with a backslash
|
||||
#TRUSTED_HOSTS='^(your-domain\.invalid)$'
|
||||
|
||||
# You can also allow multiple domain names, e.g. for testing or development purposes, with an | between the domain names.
|
||||
#TRUSTED_HOSTS='^(localhost|your-domain\.invalid)$'
|
||||
|
||||
###################################################################################
|
||||
# Database settings
|
||||
###################################################################################
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@
|
|||
"scheb/2fa-trusted-device": "^v7.11.0",
|
||||
"shivas/versioning-bundle": "^4.0",
|
||||
"spatie/db-dumper": "^3.3.1",
|
||||
"symfony/ai-bundle": "^0.10.0",
|
||||
"symfony/ai-lm-studio-platform": "^v0.10.0",
|
||||
"symfony/ai-ollama-platform": "^0.10.0",
|
||||
"symfony/ai-open-router-platform": "^0.10.0",
|
||||
"symfony/ai-bundle": "^0.11.0",
|
||||
"symfony/ai-lm-studio-platform": "^v0.11.0",
|
||||
"symfony/ai-ollama-platform": "^0.11.0",
|
||||
"symfony/ai-open-router-platform": "^0.11.0",
|
||||
"symfony/apache-pack": "^1.0",
|
||||
"symfony/asset": "7.4.*",
|
||||
"symfony/console": "7.4.*",
|
||||
|
|
|
|||
343
composer.lock
generated
343
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1b475df042448d8143469da476afbd8f",
|
||||
"content-hash": "71f989737d92309c38cbbf0e4e6e0e6e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amphp/amp",
|
||||
|
|
@ -2512,16 +2512,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.5.12",
|
||||
"version": "1.5.13",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "00a2f4201641d5c53f7fc0195e6c8d9fcc321a78"
|
||||
"reference": "c008272789979f709f7fcb32c2ecf1d2db5e84e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/00a2f4201641d5c53f7fc0195e6c8d9fcc321a78",
|
||||
"reference": "00a2f4201641d5c53f7fc0195e6c8d9fcc321a78",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/c008272789979f709f7fcb32c2ecf1d2db5e84e5",
|
||||
"reference": "c008272789979f709f7fcb32c2ecf1d2db5e84e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2568,7 +2568,7 @@
|
|||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"issues": "https://github.com/composer/ca-bundle/issues",
|
||||
"source": "https://github.com/composer/ca-bundle/tree/1.5.12"
|
||||
"source": "https://github.com/composer/ca-bundle/tree/1.5.13"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2580,7 +2580,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-05-19T11:26:22+00:00"
|
||||
"time": "2026-07-18T12:35:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/package-versions-deprecated",
|
||||
|
|
@ -4638,22 +4638,22 @@
|
|||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "7.14.2",
|
||||
"version": "7.15.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/guzzle.git",
|
||||
"reference": "fa88c57803501ad0770f5cddb1e60525d49da9a1"
|
||||
"reference": "61443dfb33c62f308ee8add20f45b4d6e4bf8d2f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/fa88c57803501ad0770f5cddb1e60525d49da9a1",
|
||||
"reference": "fa88c57803501ad0770f5cddb1e60525d49da9a1",
|
||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/61443dfb33c62f308ee8add20f45b4d6e4bf8d2f",
|
||||
"reference": "61443dfb33c62f308ee8add20f45b4d6e4bf8d2f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"guzzlehttp/promises": "^2.5.1",
|
||||
"guzzlehttp/psr7": "^2.12.5",
|
||||
"guzzlehttp/psr7": "^2.13",
|
||||
"php": "^7.2.5 || ^8.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.5 || ^3.0",
|
||||
|
|
@ -4666,7 +4666,7 @@
|
|||
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||
"ext-curl": "*",
|
||||
"guzzle/client-integration-tests": "3.0.3",
|
||||
"guzzlehttp/test-server": "^0.6",
|
||||
"guzzlehttp/test-server": "^0.7",
|
||||
"php-http/message-factory": "^1.1",
|
||||
"phpunit/phpunit": "^8.5.52 || ^9.6.34",
|
||||
"psr/log": "^1.1 || ^2.0 || ^3.0"
|
||||
|
|
@ -4746,7 +4746,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.14.2"
|
||||
"source": "https://github.com/guzzle/guzzle/tree/7.15.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -4762,7 +4762,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-14T18:15:01+00:00"
|
||||
"time": "2026-07-18T11:23:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
|
|
@ -4850,16 +4850,16 @@
|
|||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"version": "2.12.5",
|
||||
"version": "2.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/psr7.git",
|
||||
"reference": "9365d578a9fd1552ad6ca9c3cb530708526feb09"
|
||||
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/9365d578a9fd1552ad6ca9c3cb530708526feb09",
|
||||
"reference": "9365d578a9fd1552ad6ca9c3cb530708526feb09",
|
||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dad89620b7a6edb60c15858442eb2e408b45d8f4",
|
||||
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4949,7 +4949,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/guzzle/psr7/issues",
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.12.5"
|
||||
"source": "https://github.com/guzzle/psr7/tree/2.13.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -4965,7 +4965,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-13T01:27:20+00:00"
|
||||
"time": "2026-07-16T22:23:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hshn/base64-encoded-file",
|
||||
|
|
@ -7748,16 +7748,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.1.4",
|
||||
"version": "v4.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7"
|
||||
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/7da6c396d7ebe142bc857c20479d5e70a5e1aac7",
|
||||
"reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -7777,7 +7777,7 @@
|
|||
},
|
||||
"suggest": {
|
||||
"ext-gd": "to use Image",
|
||||
"ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()",
|
||||
"ext-iconv": "to use Strings::chr(), ord() and reverse()",
|
||||
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
|
||||
"ext-json": "to use Nette\\Utils\\Json",
|
||||
"ext-mbstring": "to use Strings::lower() etc...",
|
||||
|
|
@ -7833,9 +7833,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.4"
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.5"
|
||||
},
|
||||
"time": "2026-05-11T20:49:54+00:00"
|
||||
"time": "2026-07-17T23:02:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikolaposa/version",
|
||||
|
|
@ -10735,21 +10735,21 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/ai-bundle",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-bundle.git",
|
||||
"reference": "5f6d218ca26a4ac3c2b743e4bfae769c41c556c0"
|
||||
"reference": "a66502ab5ff676be4f318a273eab17ab934c661a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-bundle/zipball/5f6d218ca26a4ac3c2b743e4bfae769c41c556c0",
|
||||
"reference": "5f6d218ca26a4ac3c2b743e4bfae769c41c556c0",
|
||||
"url": "https://api.github.com/repos/symfony/ai-bundle/zipball/a66502ab5ff676be4f318a273eab17ab934c661a",
|
||||
"reference": "a66502ab5ff676be4f318a273eab17ab934c661a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/ai-platform": "^0.10",
|
||||
"symfony/ai-platform": "^0.11",
|
||||
"symfony/clock": "^7.3|^8.0",
|
||||
"symfony/config": "^7.3|^8.0",
|
||||
"symfony/console": "^7.3|^8.0",
|
||||
|
|
@ -10764,74 +10764,76 @@
|
|||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^11.5.53",
|
||||
"symfony/ai-agent": "^0.10",
|
||||
"symfony/ai-ai-ml-api-platform": "^0.10",
|
||||
"symfony/ai-albert-platform": "^0.10",
|
||||
"symfony/ai-amazee-ai-platform": "^0.10",
|
||||
"symfony/ai-anthropic-platform": "^0.10",
|
||||
"symfony/ai-azure-platform": "^0.10",
|
||||
"symfony/ai-azure-search-store": "^0.10",
|
||||
"symfony/ai-bedrock-platform": "^0.10",
|
||||
"symfony/ai-cache-message-store": "^0.10",
|
||||
"symfony/ai-cache-platform": "^0.10",
|
||||
"symfony/ai-cache-store": "^0.10",
|
||||
"symfony/ai-cartesia-platform": "^0.10",
|
||||
"symfony/ai-cerebras-platform": "^0.10",
|
||||
"symfony/ai-chat": "^0.10",
|
||||
"symfony/ai-chroma-db-store": "^0.10",
|
||||
"symfony/ai-click-house-store": "^0.10",
|
||||
"symfony/ai-cloudflare-message-store": "^0.10",
|
||||
"symfony/ai-cloudflare-store": "^0.10",
|
||||
"symfony/ai-cohere-platform": "^0.10",
|
||||
"symfony/ai-decart-platform": "^0.10",
|
||||
"symfony/ai-deep-seek-platform": "^0.10",
|
||||
"symfony/ai-docker-model-runner-platform": "^0.10",
|
||||
"symfony/ai-doctrine-message-store": "^0.10",
|
||||
"symfony/ai-elasticsearch-store": "^0.10",
|
||||
"symfony/ai-eleven-labs-platform": "^0.10",
|
||||
"symfony/ai-failover-platform": "^0.10",
|
||||
"symfony/ai-gemini-platform": "^0.10",
|
||||
"symfony/ai-generic-platform": "^0.10",
|
||||
"symfony/ai-hugging-face-platform": "^0.10",
|
||||
"symfony/ai-lm-studio-platform": "^0.10",
|
||||
"symfony/ai-manticore-search-store": "^0.10",
|
||||
"symfony/ai-maria-db-store": "^0.10",
|
||||
"symfony/ai-meilisearch-message-store": "^0.10",
|
||||
"symfony/ai-meilisearch-store": "^0.10",
|
||||
"symfony/ai-meta-platform": "^0.10",
|
||||
"symfony/ai-milvus-store": "^0.10",
|
||||
"symfony/ai-mistral-platform": "^0.10",
|
||||
"symfony/ai-mongo-db-message-store": "^0.10",
|
||||
"symfony/ai-mongo-db-store": "^0.10",
|
||||
"symfony/ai-neo4j-store": "^0.10",
|
||||
"symfony/ai-ollama-platform": "^0.10",
|
||||
"symfony/ai-open-ai-platform": "^0.10",
|
||||
"symfony/ai-open-responses-platform": "^0.10",
|
||||
"symfony/ai-open-router-platform": "^0.10",
|
||||
"symfony/ai-open-search-store": "^0.10",
|
||||
"symfony/ai-ovh-platform": "^0.10",
|
||||
"symfony/ai-perplexity-platform": "^0.10",
|
||||
"symfony/ai-pinecone-store": "^0.10",
|
||||
"symfony/ai-pogocache-message-store": "^0.10",
|
||||
"symfony/ai-postgres-store": "^0.10",
|
||||
"symfony/ai-qdrant-store": "^0.10",
|
||||
"symfony/ai-redis-message-store": "^0.10",
|
||||
"symfony/ai-redis-store": "^0.10",
|
||||
"symfony/ai-replicate-platform": "^0.10",
|
||||
"symfony/ai-s3vectors-store": "^0.10",
|
||||
"symfony/ai-scaleway-platform": "^0.10",
|
||||
"symfony/ai-session-message-store": "^0.10",
|
||||
"symfony/ai-sqlite-store": "^0.10",
|
||||
"symfony/ai-store": "^0.10",
|
||||
"symfony/ai-supabase-store": "^0.10",
|
||||
"symfony/ai-surreal-db-message-store": "^0.10",
|
||||
"symfony/ai-surreal-db-store": "^0.10",
|
||||
"symfony/ai-transformers-php-platform": "^0.10",
|
||||
"symfony/ai-typesense-store": "^0.10",
|
||||
"symfony/ai-vektor-store": "^0.10",
|
||||
"symfony/ai-vertex-ai-platform": "^0.10",
|
||||
"symfony/ai-voyage-platform": "^0.10",
|
||||
"symfony/ai-weaviate-store": "^0.10",
|
||||
"symfony/ai-agent": "^0.11",
|
||||
"symfony/ai-ai-ml-api-platform": "^0.11",
|
||||
"symfony/ai-albert-platform": "^0.11",
|
||||
"symfony/ai-amazee-ai-platform": "^0.11",
|
||||
"symfony/ai-anthropic-platform": "^0.11",
|
||||
"symfony/ai-azure-platform": "^0.11",
|
||||
"symfony/ai-azure-search-store": "^0.11",
|
||||
"symfony/ai-bedrock-platform": "^0.11",
|
||||
"symfony/ai-cache-message-store": "^0.11",
|
||||
"symfony/ai-cache-platform": "^0.11",
|
||||
"symfony/ai-cache-store": "^0.11",
|
||||
"symfony/ai-cartesia-platform": "^0.11",
|
||||
"symfony/ai-cerebras-platform": "^0.11",
|
||||
"symfony/ai-chat": "^0.11",
|
||||
"symfony/ai-chroma-db-store": "^0.11",
|
||||
"symfony/ai-click-house-store": "^0.11",
|
||||
"symfony/ai-cloudflare-message-store": "^0.11",
|
||||
"symfony/ai-cloudflare-store": "^0.11",
|
||||
"symfony/ai-cohere-platform": "^0.11",
|
||||
"symfony/ai-decart-platform": "^0.11",
|
||||
"symfony/ai-deep-seek-platform": "^0.11",
|
||||
"symfony/ai-deepgram-platform": "^0.11",
|
||||
"symfony/ai-docker-model-runner-platform": "^0.11",
|
||||
"symfony/ai-doctrine-message-store": "^0.11",
|
||||
"symfony/ai-elasticsearch-store": "^0.11",
|
||||
"symfony/ai-eleven-labs-platform": "^0.11",
|
||||
"symfony/ai-failover-platform": "^0.11",
|
||||
"symfony/ai-gemini-platform": "^0.11",
|
||||
"symfony/ai-generic-platform": "^0.11",
|
||||
"symfony/ai-hugging-face-platform": "^0.11",
|
||||
"symfony/ai-lm-studio-platform": "^0.11",
|
||||
"symfony/ai-manticore-search-store": "^0.11",
|
||||
"symfony/ai-maria-db-store": "^0.11",
|
||||
"symfony/ai-meilisearch-message-store": "^0.11",
|
||||
"symfony/ai-meilisearch-store": "^0.11",
|
||||
"symfony/ai-meta-platform": "^0.11",
|
||||
"symfony/ai-milvus-store": "^0.11",
|
||||
"symfony/ai-mini-max-platform": "^0.11",
|
||||
"symfony/ai-mistral-platform": "^0.11",
|
||||
"symfony/ai-mongo-db-message-store": "^0.11",
|
||||
"symfony/ai-mongo-db-store": "^0.11",
|
||||
"symfony/ai-neo4j-store": "^0.11",
|
||||
"symfony/ai-ollama-platform": "^0.11",
|
||||
"symfony/ai-open-ai-platform": "^0.11",
|
||||
"symfony/ai-open-responses-platform": "^0.11",
|
||||
"symfony/ai-open-router-platform": "^0.11",
|
||||
"symfony/ai-open-search-store": "^0.11",
|
||||
"symfony/ai-ovh-platform": "^0.11",
|
||||
"symfony/ai-perplexity-platform": "^0.11",
|
||||
"symfony/ai-pinecone-store": "^0.11",
|
||||
"symfony/ai-pogocache-message-store": "^0.11",
|
||||
"symfony/ai-postgres-store": "^0.11",
|
||||
"symfony/ai-qdrant-store": "^0.11",
|
||||
"symfony/ai-redis-message-store": "^0.11",
|
||||
"symfony/ai-redis-store": "^0.11",
|
||||
"symfony/ai-replicate-platform": "^0.11",
|
||||
"symfony/ai-s3vectors-store": "^0.11",
|
||||
"symfony/ai-scaleway-platform": "^0.11",
|
||||
"symfony/ai-session-message-store": "^0.11",
|
||||
"symfony/ai-sqlite-store": "^0.11",
|
||||
"symfony/ai-store": "^0.11",
|
||||
"symfony/ai-supabase-store": "^0.11",
|
||||
"symfony/ai-surreal-db-message-store": "^0.11",
|
||||
"symfony/ai-surreal-db-store": "^0.11",
|
||||
"symfony/ai-transformers-php-platform": "^0.11",
|
||||
"symfony/ai-typesense-store": "^0.11",
|
||||
"symfony/ai-vektor-store": "^0.11",
|
||||
"symfony/ai-vertex-ai-platform": "^0.11",
|
||||
"symfony/ai-voyage-platform": "^0.11",
|
||||
"symfony/ai-weaviate-store": "^0.11",
|
||||
"symfony/expression-language": "^7.3|^8.0",
|
||||
"symfony/security-core": "^7.3|^8.0",
|
||||
"symfony/translation": "^7.3|^8.0",
|
||||
|
|
@ -10869,7 +10871,7 @@
|
|||
],
|
||||
"description": "Integration bundle for Symfony AI components",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-bundle/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-bundle/tree/v0.11.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -10889,25 +10891,25 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-16T07:10:08+00:00"
|
||||
"time": "2026-07-16T11:42:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ai-generic-platform",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-generic-platform.git",
|
||||
"reference": "a099d8a35ea9f7254a159b9c17bc7a4927f9ebb2"
|
||||
"reference": "b56ea991a4232ea16204960ab8dc8a1da44cb320"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-generic-platform/zipball/a099d8a35ea9f7254a159b9c17bc7a4927f9ebb2",
|
||||
"reference": "a099d8a35ea9f7254a159b9c17bc7a4927f9ebb2",
|
||||
"url": "https://api.github.com/repos/symfony/ai-generic-platform/zipball/b56ea991a4232ea16204960ab8dc8a1da44cb320",
|
||||
"reference": "b56ea991a4232ea16204960ab8dc8a1da44cb320",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/ai-platform": "^0.10",
|
||||
"symfony/ai-platform": "^0.11",
|
||||
"symfony/http-client": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -10954,7 +10956,7 @@
|
|||
"platform"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-generic-platform/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-generic-platform/tree/v0.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -10974,26 +10976,26 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-16T07:10:08+00:00"
|
||||
"time": "2026-07-15T00:58:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ai-lm-studio-platform",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-lm-studio-platform.git",
|
||||
"reference": "b6c4a3a5bedf2fd613953447602945c104e75a30"
|
||||
"reference": "b9725715569184ed80ebecb01a17893660cc550b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-lm-studio-platform/zipball/b6c4a3a5bedf2fd613953447602945c104e75a30",
|
||||
"reference": "b6c4a3a5bedf2fd613953447602945c104e75a30",
|
||||
"url": "https://api.github.com/repos/symfony/ai-lm-studio-platform/zipball/b9725715569184ed80ebecb01a17893660cc550b",
|
||||
"reference": "b9725715569184ed80ebecb01a17893660cc550b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/ai-generic-platform": "^0.10",
|
||||
"symfony/ai-platform": "^0.10",
|
||||
"symfony/ai-generic-platform": "^0.11",
|
||||
"symfony/ai-platform": "^0.11",
|
||||
"symfony/http-client": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -11041,7 +11043,7 @@
|
|||
"platform"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-lm-studio-platform/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-lm-studio-platform/tree/v0.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -11061,25 +11063,25 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-15T22:48:31+00:00"
|
||||
"time": "2026-07-15T00:58:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ai-ollama-platform",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-ollama-platform.git",
|
||||
"reference": "1542f19b78362cafc034c219f5bc9a5a239a0ffb"
|
||||
"reference": "b42c359a7f414053d1b30f70e6508528853a8704"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-ollama-platform/zipball/1542f19b78362cafc034c219f5bc9a5a239a0ffb",
|
||||
"reference": "1542f19b78362cafc034c219f5bc9a5a239a0ffb",
|
||||
"url": "https://api.github.com/repos/symfony/ai-ollama-platform/zipball/b42c359a7f414053d1b30f70e6508528853a8704",
|
||||
"reference": "b42c359a7f414053d1b30f70e6508528853a8704",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/ai-platform": "^0.10",
|
||||
"symfony/ai-platform": "^0.11",
|
||||
"symfony/http-client": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -11127,7 +11129,7 @@
|
|||
"platform"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-ollama-platform/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-ollama-platform/tree/v0.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -11147,26 +11149,26 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-15T22:48:31+00:00"
|
||||
"time": "2026-07-15T00:58:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ai-open-router-platform",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-open-router-platform.git",
|
||||
"reference": "cfadb7858fca98b28b968b032b1bbeb5c9cc985b"
|
||||
"reference": "5ad625058227bf628ca0f504ba035599a1e8c91d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-open-router-platform/zipball/cfadb7858fca98b28b968b032b1bbeb5c9cc985b",
|
||||
"reference": "cfadb7858fca98b28b968b032b1bbeb5c9cc985b",
|
||||
"url": "https://api.github.com/repos/symfony/ai-open-router-platform/zipball/5ad625058227bf628ca0f504ba035599a1e8c91d",
|
||||
"reference": "5ad625058227bf628ca0f504ba035599a1e8c91d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/ai-generic-platform": "^0.10",
|
||||
"symfony/ai-platform": "^0.10",
|
||||
"symfony/ai-generic-platform": "^0.11",
|
||||
"symfony/ai-platform": "^0.11",
|
||||
"symfony/http-client": "^7.3|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -11214,7 +11216,7 @@
|
|||
"platform"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-open-router-platform/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-open-router-platform/tree/v0.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -11234,20 +11236,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-16T08:09:36+00:00"
|
||||
"time": "2026-07-15T00:58:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/ai-platform",
|
||||
"version": "v0.10.0",
|
||||
"version": "v0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/ai-platform.git",
|
||||
"reference": "8100507aa9c46f3ad56d0272e8e46b558f451052"
|
||||
"reference": "dce4285eaf891cbdcb9526e576e3df6f8220fd1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/ai-platform/zipball/8100507aa9c46f3ad56d0272e8e46b558f451052",
|
||||
"reference": "8100507aa9c46f3ad56d0272e8e46b558f451052",
|
||||
"url": "https://api.github.com/repos/symfony/ai-platform/zipball/dce4285eaf891cbdcb9526e576e3df6f8220fd1d",
|
||||
"reference": "dce4285eaf891cbdcb9526e576e3df6f8220fd1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -11346,7 +11348,7 @@
|
|||
"voyage"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/ai-platform/tree/v0.10.0"
|
||||
"source": "https://github.com/symfony/ai-platform/tree/v0.11.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -11366,7 +11368,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-06-16T06:39:24+00:00"
|
||||
"time": "2026-07-15T01:10:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/apache-pack",
|
||||
|
|
@ -17561,16 +17563,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symplify/easy-coding-standard",
|
||||
"version": "13.2.7",
|
||||
"version": "13.2.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ecsphp/ecs.git",
|
||||
"reference": "735c742244ae3b3b067d5aae3d1dd4b7a48759f7"
|
||||
"reference": "f4730d9fde79bf27993e31d9fd7f9df00da0d1aa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ecsphp/ecs/zipball/735c742244ae3b3b067d5aae3d1dd4b7a48759f7",
|
||||
"reference": "735c742244ae3b3b067d5aae3d1dd4b7a48759f7",
|
||||
"url": "https://api.github.com/repos/ecsphp/ecs/zipball/f4730d9fde79bf27993e31d9fd7f9df00da0d1aa",
|
||||
"reference": "f4730d9fde79bf27993e31d9fd7f9df00da0d1aa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -17605,29 +17607,29 @@
|
|||
"static analysis"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/ecsphp/ecs/tree/13.2.7"
|
||||
"source": "https://github.com/ecsphp/ecs/tree/13.2.9"
|
||||
},
|
||||
"time": "2026-07-11T07:53:39+00:00"
|
||||
"time": "2026-07-17T15:05:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tecnickcom/tc-lib-barcode",
|
||||
"version": "2.11.4",
|
||||
"version": "2.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tecnickcom/tc-lib-barcode.git",
|
||||
"reference": "8e8486a84b12ae55f8b233588a1ae64f08bf1b6d"
|
||||
"reference": "0614e905c903600c2491d3a90174a9a87a2fab9b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/8e8486a84b12ae55f8b233588a1ae64f08bf1b6d",
|
||||
"reference": "8e8486a84b12ae55f8b233588a1ae64f08bf1b6d",
|
||||
"url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/0614e905c903600c2491d3a90174a9a87a2fab9b",
|
||||
"reference": "0614e905c903600c2491d3a90174a9a87a2fab9b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-bcmath": "*",
|
||||
"ext-gd": "*",
|
||||
"php": ">=8.2",
|
||||
"tecnickcom/tc-lib-color": "^2.12"
|
||||
"tecnickcom/tc-lib-color": "^2.13"
|
||||
},
|
||||
"require-dev": {
|
||||
"pdepend/pdepend": "^2.16",
|
||||
|
|
@ -17703,20 +17705,20 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-13T08:24:02+00:00"
|
||||
"time": "2026-07-17T19:05:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tecnickcom/tc-lib-color",
|
||||
"version": "2.12.5",
|
||||
"version": "2.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tecnickcom/tc-lib-color.git",
|
||||
"reference": "71b30de968ca51832b64728a2727210adb3a1708"
|
||||
"reference": "38303066464928bbcfe8e54d006c828b02e4c62f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/71b30de968ca51832b64728a2727210adb3a1708",
|
||||
"reference": "71b30de968ca51832b64728a2727210adb3a1708",
|
||||
"url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/38303066464928bbcfe8e54d006c828b02e4c62f",
|
||||
"reference": "38303066464928bbcfe8e54d006c828b02e4c62f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -17769,7 +17771,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-13T08:22:14+00:00"
|
||||
"time": "2026-07-17T19:02:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "thecodingmachine/safe",
|
||||
|
|
@ -19725,27 +19727,28 @@
|
|||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "2.0.11",
|
||||
"version": "2.0.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "9b000a578b85b32945b358b172c7b20e91189024"
|
||||
"reference": "2bc5ae19ae965663b62ac907ee6342c3903ec93b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/9b000a578b85b32945b358b172c7b20e91189024",
|
||||
"reference": "9b000a578b85b32945b358b172c7b20e91189024",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2bc5ae19ae965663b62ac907ee6342c3903ec93b",
|
||||
"reference": "2bc5ae19ae965663b62ac907ee6342c3903ec93b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpstan/phpstan": "^2.1.39"
|
||||
"phpstan/phpstan": "^2.1.52"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"shipmonk/name-collision-detector": "^2.1"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
|
|
@ -19770,9 +19773,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.11"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.12"
|
||||
},
|
||||
"time": "2026-05-02T06:54:10+00:00"
|
||||
"time": "2026-07-19T07:24:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-symfony",
|
||||
|
|
@ -20355,12 +20358,12 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||
"reference": "526c3e9555f6912cb025c1357e66956b1a1621c9"
|
||||
"reference": "4fac0729c45b6dba8d6171a94eccb1d5d9514bf9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/526c3e9555f6912cb025c1357e66956b1a1621c9",
|
||||
"reference": "526c3e9555f6912cb025c1357e66956b1a1621c9",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/4fac0729c45b6dba8d6171a94eccb1d5d9514bf9",
|
||||
"reference": "4fac0729c45b6dba8d6171a94eccb1d5d9514bf9",
|
||||
"shasum": ""
|
||||
},
|
||||
"conflict": {
|
||||
|
|
@ -21254,7 +21257,7 @@
|
|||
"tecnickcom/tcpdf": "<6.8",
|
||||
"terminal42/contao-tablelookupwizard": "<3.3.5",
|
||||
"thelia/backoffice-default-template": ">=2.1,<2.1.2",
|
||||
"thelia/thelia": ">=2.1,<2.1.3",
|
||||
"thelia/thelia": ">=2.0.0.0-beta1,<2.1.3",
|
||||
"theonedemon/phpwhois": "<=4.2.5",
|
||||
"thinkcmf/thinkcmf": "<6.0.8",
|
||||
"thorsten/phpmyfaq": "<4.1.4",
|
||||
|
|
@ -21321,7 +21324,7 @@
|
|||
"uvdesk/core-framework": "<=1.1.1",
|
||||
"vanilla/safecurl": "<0.9.2",
|
||||
"verbb/comments": "<1.5.5",
|
||||
"verbb/formie": "<3.1.27",
|
||||
"verbb/formie": "<3.1.28",
|
||||
"verbb/image-resizer": "<2.0.9",
|
||||
"verbb/knock-knock": "<1.2.8",
|
||||
"verot/class.upload.php": "<=2.1.6",
|
||||
|
|
@ -21469,7 +21472,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-16T20:57:14+00:00"
|
||||
"time": "2026-07-17T19:07:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ parameters:
|
|||
|
||||
# This is used as workaround for places where we can not access the settings directly (like the 2FA application names)
|
||||
partdb.title: '%env(string:settings:customization:instanceName)%' # The title shown inside of Part-DB (e.g. in the navbar and on homepage)
|
||||
partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl', 'hu'] # The languages that are shown in user drop down menu
|
||||
partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl', 'hu', 'ko'] # The languages that are shown in user drop down menu
|
||||
|
||||
partdb.default_uri: '%env(addSlash:string:DEFAULT_URI)%' # The default URI to use for the Part-DB instance (e.g. https://part-db.example.com/). This is used for generating links in emails
|
||||
|
||||
|
|
|
|||
|
|
@ -2770,6 +2770,11 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||
* host?: string|Param, // Default: "https://api.decart.ai/v1"
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
* },
|
||||
* deepgram?: array{
|
||||
* api_key?: string|Param,
|
||||
* endpoint?: string|Param, // Deepgram REST API endpoint // Default: "https://api.deepgram.com/v1/"
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
* },
|
||||
* deepseek?: array{
|
||||
* api_key?: string|Param,
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
|
|
@ -2810,6 +2815,11 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||
* host_url?: string|Param, // Default: "http://127.0.0.1:1234"
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
* },
|
||||
* minimax?: array{
|
||||
* endpoint?: string|Param, // Default: "https://api.minimax.io/v1"
|
||||
* api_key?: string|Param,
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
* },
|
||||
* mistral?: array{
|
||||
* api_key?: string|Param,
|
||||
* http_client?: string|Param, // Service ID of the HTTP client to use // Default: "http_client"
|
||||
|
|
@ -2931,6 +2941,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||
* account_id?: string|Param,
|
||||
* api_key?: string|Param,
|
||||
* index_name?: string|Param,
|
||||
* http_client?: string|Param, // Default: "http_client"
|
||||
* dimensions?: int|Param, // Default: 1536
|
||||
* metric?: string|Param, // Default: "cosine"
|
||||
* endpoint?: string|Param,
|
||||
|
|
@ -3087,6 +3098,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||
* namespace?: string|Param,
|
||||
* database?: string|Param,
|
||||
* table?: string|Param,
|
||||
* http_client?: string|Param, // Default: "http_client"
|
||||
* vector_field?: string|Param, // Default: "_vectors"
|
||||
* strategy?: string|Param, // Default: "cosine"
|
||||
* dimensions?: int|Param, // Default: 1536
|
||||
|
|
@ -3096,6 +3108,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||
* endpoint?: string|Param,
|
||||
* api_key?: string|Param,
|
||||
* collection?: string|Param,
|
||||
* http_client?: string|Param, // Default: "http_client"
|
||||
* vector_field?: string|Param, // Default: "_vectors"
|
||||
* dimensions?: int|Param, // Default: 1536
|
||||
* }>,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use App\Entity\Parts\Part;
|
|||
use App\Services\System\AppSecretChecker;
|
||||
use App\Services\System\BannerHelper;
|
||||
use App\Services\System\GitVersionInfoProvider;
|
||||
use App\Services\System\TrustedHostsChecker;
|
||||
use App\Services\System\UpdateAvailableFacade;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Omines\DataTablesBundle\DataTableFactory;
|
||||
|
|
@ -41,6 +42,7 @@ class HomepageController extends AbstractController
|
|||
private readonly DataTableFactory $dataTable,
|
||||
private readonly BannerHelper $bannerHelper,
|
||||
private readonly AppSecretChecker $appSecretChecker,
|
||||
private readonly TrustedHostsChecker $trustedHostsChecker,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +92,7 @@ class HomepageController extends AbstractController
|
|||
'new_version_url' => $updateAvailableManager->getLatestVersionUrl(),
|
||||
'insecure_app_secret' => $this->appSecretChecker->isInsecureSecret(),
|
||||
'suggested_app_secret' => $this->appSecretChecker->isInsecureSecret() ? $this->appSecretChecker->generateSecret() : null,
|
||||
'trusted_hosts_unconfigured' => $this->trustedHostsChecker->isTrustedHostsUnconfigured(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ class BarcodeHelper
|
|||
{
|
||||
$svg = $this->barcodeAsSVG($content, $type);
|
||||
$base64 = $this->dataUri($svg, 'image/svg+xml');
|
||||
$alt_text ??= $content;
|
||||
|
||||
$alt_text ??= htmlspecialchars($content);
|
||||
|
||||
return '<img src="'.$base64.'" width="'.$width.'" style="min-height: 25px;" alt="'.$alt_text.'"/>';
|
||||
}
|
||||
|
||||
|
|
@ -94,4 +94,4 @@ class BarcodeHelper
|
|||
|
||||
return $repr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ namespace App\Services\LabelSystem\PlaceholderProviders;
|
|||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
|
||||
final class AbstractDBElementProvider implements PlaceholderProviderInterface
|
||||
final readonly class AbstractDBElementProvider implements PlaceholderProviderInterface
|
||||
{
|
||||
public function __construct(private readonly ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
public function __construct(private ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ final class AbstractDBElementProvider implements PlaceholderProviderInterface
|
|||
{
|
||||
if ($label_target instanceof AbstractDBElement) {
|
||||
if ('[[TYPE]]' === $placeholder) {
|
||||
return $this->elementTypeNameGenerator->getLocalizedTypeLabel($label_target);
|
||||
return $this->elementTypeNameGenerator->typeLabel($label_target);
|
||||
}
|
||||
|
||||
if ('[[ID]]' === $placeholder) {
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ use App\Services\LabelSystem\LabelBarcodeGenerator;
|
|||
use App\Services\LabelSystem\Barcodes\BarcodeContentGenerator;
|
||||
use Com\Tecnick\Barcode\Exception;
|
||||
|
||||
final class BarcodeProvider implements PlaceholderProviderInterface
|
||||
final readonly class BarcodeProvider implements PlaceholderProviderInterface
|
||||
{
|
||||
public function __construct(private readonly LabelBarcodeGenerator $barcodeGenerator,
|
||||
private readonly BarcodeContentGenerator $barcodeContentGenerator,
|
||||
private readonly BarcodeHelper $barcodeHelper)
|
||||
public function __construct(private LabelBarcodeGenerator $barcodeGenerator,
|
||||
private BarcodeContentGenerator $barcodeContentGenerator,
|
||||
private BarcodeHelper $barcodeHelper)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|||
* Provides Placeholders for infos about global infos like Installation name or datetimes.
|
||||
* @see \App\Tests\Services\LabelSystem\PlaceholderProviders\GlobalProvidersTest
|
||||
*/
|
||||
final class GlobalProviders implements PlaceholderProviderInterface
|
||||
final readonly class GlobalProviders implements PlaceholderProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Security $security,
|
||||
private readonly UrlGeneratorInterface $url_generator,
|
||||
private Security $security,
|
||||
private UrlGeneratorInterface $url_generator,
|
||||
private CustomizationSettings $customizationSettings,
|
||||
)
|
||||
{
|
||||
|
|
@ -66,13 +66,13 @@ final class GlobalProviders implements PlaceholderProviderInterface
|
|||
public function replace(string $placeholder, object $label_target, array $options = []): ?string
|
||||
{
|
||||
if ('[[INSTALL_NAME]]' === $placeholder) {
|
||||
return $this->customizationSettings->instanceName;
|
||||
return htmlspecialchars($this->customizationSettings->instanceName);
|
||||
}
|
||||
|
||||
$user = $this->security->getUser();
|
||||
if ('[[USERNAME]]' === $placeholder) {
|
||||
if ($user instanceof User) {
|
||||
return $user->getName();
|
||||
return htmlspecialchars($user->getName());
|
||||
}
|
||||
|
||||
return 'anonymous';
|
||||
|
|
@ -80,7 +80,7 @@ final class GlobalProviders implements PlaceholderProviderInterface
|
|||
|
||||
if ('[[USERNAME_FULL]]' === $placeholder) {
|
||||
if ($user instanceof User) {
|
||||
return $user->getFullName(true);
|
||||
return htmlspecialchars($user->getFullName(true));
|
||||
}
|
||||
|
||||
return 'anonymous';
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ final class NamedElementProvider implements PlaceholderProviderInterface
|
|||
public function replace(string $placeholder, object $label_target, array $options = []): ?string
|
||||
{
|
||||
if ($label_target instanceof NamedElementInterface && '[[NAME]]' === $placeholder) {
|
||||
return $label_target->getName();
|
||||
return htmlspecialchars($label_target->getName());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ use Locale;
|
|||
/**
|
||||
* @see \App\Tests\Services\LabelSystem\PlaceholderProviders\PartLotProviderTest
|
||||
*/
|
||||
final class PartLotProvider implements PlaceholderProviderInterface
|
||||
final readonly class PartLotProvider implements PlaceholderProviderInterface
|
||||
{
|
||||
public function __construct(private readonly LabelTextReplacer $labelTextReplacer, private readonly AmountFormatter $amountFormatter)
|
||||
public function __construct(private LabelTextReplacer $labelTextReplacer, private AmountFormatter $amountFormatter)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -66,11 +66,11 @@ final class PartLotProvider implements PlaceholderProviderInterface
|
|||
}
|
||||
|
||||
if ('[[LOT_NAME]]' === $placeholder) {
|
||||
return $label_target->getName();
|
||||
return htmlspecialchars($label_target->getName());
|
||||
}
|
||||
|
||||
if ('[[LOT_COMMENT]]' === $placeholder) {
|
||||
return $label_target->getComment();
|
||||
return htmlspecialchars($label_target->getComment());
|
||||
}
|
||||
|
||||
if ('[[EXPIRATION_DATE]]' === $placeholder) {
|
||||
|
|
@ -95,19 +95,19 @@ final class PartLotProvider implements PlaceholderProviderInterface
|
|||
}
|
||||
|
||||
if ('[[LOCATION]]' === $placeholder) {
|
||||
return $label_target->getStorageLocation() instanceof StorageLocation ? $label_target->getStorageLocation()->getName() : '';
|
||||
return $label_target->getStorageLocation() instanceof StorageLocation ? htmlspecialchars($label_target->getStorageLocation()->getName()) : '';
|
||||
}
|
||||
|
||||
if ('[[LOCATION_FULL]]' === $placeholder) {
|
||||
return $label_target->getStorageLocation() instanceof StorageLocation ? $label_target->getStorageLocation()->getFullPath() : '';
|
||||
return $label_target->getStorageLocation() instanceof StorageLocation ? htmlspecialchars($label_target->getStorageLocation()->getFullPath()) : '';
|
||||
}
|
||||
|
||||
if ('[[OWNER]]' === $placeholder) {
|
||||
return $label_target->getOwner() instanceof User ? $label_target->getOwner()->getFullName() : '';
|
||||
return $label_target->getOwner() instanceof User ? htmlspecialchars($label_target->getOwner()->getFullName()) : '';
|
||||
}
|
||||
|
||||
if ('[[OWNER_USERNAME]]' === $placeholder) {
|
||||
return $label_target->getOwner() instanceof User ? $label_target->getOwner()->getUsername() : '';
|
||||
return $label_target->getOwner() instanceof User ? htmlspecialchars($label_target->getOwner()->getUsername()) : '';
|
||||
}
|
||||
|
||||
return $this->labelTextReplacer->handlePlaceholder($placeholder, $label_target->getPart());
|
||||
|
|
|
|||
|
|
@ -54,11 +54,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
/**
|
||||
* @see \App\Tests\Services\LabelSystem\PlaceholderProviders\PartProviderTest
|
||||
*/
|
||||
final class PartProvider implements PlaceholderProviderInterface
|
||||
final readonly class PartProvider implements PlaceholderProviderInterface
|
||||
{
|
||||
private readonly MarkdownConverter $inlineConverter;
|
||||
private MarkdownConverter $inlineConverter;
|
||||
|
||||
public function __construct(private readonly SIFormatter $siFormatter, private readonly TranslatorInterface $translator)
|
||||
public function __construct(private SIFormatter $siFormatter, private TranslatorInterface $translator)
|
||||
{
|
||||
$environment = new Environment();
|
||||
$environment->addExtension(new InlinesOnlyExtension());
|
||||
|
|
@ -72,27 +72,27 @@ final class PartProvider implements PlaceholderProviderInterface
|
|||
}
|
||||
|
||||
if ('[[CATEGORY]]' === $placeholder) {
|
||||
return $part->getCategory() instanceof Category ? $part->getCategory()->getName() : '';
|
||||
return $part->getCategory() instanceof Category ? htmlspecialchars($part->getCategory()->getName()) : '';
|
||||
}
|
||||
|
||||
if ('[[CATEGORY_FULL]]' === $placeholder) {
|
||||
return $part->getCategory() instanceof Category ? $part->getCategory()->getFullPath() : '';
|
||||
return $part->getCategory() instanceof Category ? htmlspecialchars($part->getCategory()->getFullPath()) : '';
|
||||
}
|
||||
|
||||
if ('[[MANUFACTURER]]' === $placeholder) {
|
||||
return $part->getManufacturer() instanceof Manufacturer ? $part->getManufacturer()->getName() : '';
|
||||
return $part->getManufacturer() instanceof Manufacturer ? htmlspecialchars($part->getManufacturer()->getName()) : '';
|
||||
}
|
||||
|
||||
if ('[[MANUFACTURER_FULL]]' === $placeholder) {
|
||||
return $part->getManufacturer() instanceof Manufacturer ? $part->getManufacturer()->getFullPath() : '';
|
||||
return $part->getManufacturer() instanceof Manufacturer ? htmlspecialchars($part->getManufacturer()->getFullPath()) : '';
|
||||
}
|
||||
|
||||
if ('[[FOOTPRINT]]' === $placeholder) {
|
||||
return $part->getFootprint() instanceof Footprint ? $part->getFootprint()->getName() : '';
|
||||
return $part->getFootprint() instanceof Footprint ? htmlspecialchars($part->getFootprint()->getName()) : '';
|
||||
}
|
||||
|
||||
if ('[[FOOTPRINT_FULL]]' === $placeholder) {
|
||||
return $part->getFootprint() instanceof Footprint ? $part->getFootprint()->getFullPath() : '';
|
||||
return $part->getFootprint() instanceof Footprint ? htmlspecialchars($part->getFootprint()->getFullPath()) : '';
|
||||
}
|
||||
|
||||
if ('[[MASS]]' === $placeholder) {
|
||||
|
|
@ -100,15 +100,15 @@ final class PartProvider implements PlaceholderProviderInterface
|
|||
}
|
||||
|
||||
if ('[[MPN]]' === $placeholder) {
|
||||
return $part->getManufacturerProductNumber();
|
||||
return htmlspecialchars($part->getManufacturerProductNumber());
|
||||
}
|
||||
|
||||
if ('[[IPN]]' === $placeholder) {
|
||||
return $part->getIpn() ?? '';
|
||||
return $part->getIpn() ? htmlspecialchars($part->getIpn()) : '';
|
||||
}
|
||||
|
||||
if ('[[TAGS]]' === $placeholder) {
|
||||
return $part->getTags();
|
||||
return htmlspecialchars($part->getTags());
|
||||
}
|
||||
|
||||
if ('[[M_STATUS]]' === $placeholder) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ interface PlaceholderProviderInterface
|
|||
/**
|
||||
* Determines the real value of this placeholder.
|
||||
* If the placeholder is not supported, null must be returned.
|
||||
* The placeholder provider has to handle HTML escaping, as the output of this function will be used directly in the label template.
|
||||
*
|
||||
* @param string $placeholder The placeholder (e.g. "%%PLACEHOLDER%%") that should be replaced
|
||||
* @param object $label_target The object that is targeted by the label
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ class StorelocationProvider implements PlaceholderProviderInterface
|
|||
{
|
||||
if ($label_target instanceof StorageLocation) {
|
||||
if ('[[OWNER]]' === $placeholder) {
|
||||
return $label_target->getOwner() instanceof User ? $label_target->getOwner()->getFullName() : '';
|
||||
return $label_target->getOwner() instanceof User ? htmlspecialchars($label_target->getOwner()->getFullName()) : '';
|
||||
}
|
||||
|
||||
if ('[[OWNER_USERNAME]]' === $placeholder) {
|
||||
return $label_target->getOwner() instanceof User ? $label_target->getOwner()->getUsername() : '';
|
||||
return $label_target->getOwner() instanceof User ? htmlspecialchars($label_target->getOwner()->getUsername()) : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,13 +55,13 @@ final class StructuralDBElementProvider implements PlaceholderProviderInterface
|
|||
return strip_tags((string) $label_target->getComment());
|
||||
}
|
||||
if ('[[FULL_PATH]]' === $placeholder) {
|
||||
return $label_target->getFullPath();
|
||||
return htmlspecialchars($label_target->getFullPath());
|
||||
}
|
||||
if ('[[PARENT]]' === $placeholder) {
|
||||
return $label_target->getParent() instanceof AbstractStructuralDBElement ? $label_target->getParent()->getName() : '';
|
||||
return $label_target->getParent() instanceof AbstractStructuralDBElement ? htmlspecialchars($label_target->getParent()->getName()) : '';
|
||||
}
|
||||
if ('[[PARENT_FULL_PATH]]' === $placeholder) {
|
||||
return $label_target->getParent() instanceof AbstractStructuralDBElement ? $label_target->getParent()->getFullPath() : '';
|
||||
return $label_target->getParent() instanceof AbstractStructuralDBElement ? htmlspecialchars($label_target->getParent()->getFullPath()) : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
45
src/Services/System/TrustedHostsChecker.php
Normal file
45
src/Services/System/TrustedHostsChecker.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\System;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
|
||||
/**
|
||||
* Checks whether the TRUSTED_HOSTS environment variable has been configured.
|
||||
*/
|
||||
final readonly class TrustedHostsChecker
|
||||
{
|
||||
public function __construct(
|
||||
#[Autowire('%env(TRUSTED_HOSTS)%')]
|
||||
private string $trustedHosts,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if TRUSTED_HOSTS is not configured (meaning Part-DB accepts requests with any Host header), false otherwise.
|
||||
*/
|
||||
public function isTrustedHostsUnconfigured(): bool
|
||||
{
|
||||
return trim($this->trustedHosts) === '';
|
||||
}
|
||||
}
|
||||
39
templates/bundles/TwigBundle/Exception/error400.html.twig
Normal file
39
templates/bundles/TwigBundle/Exception/error400.html.twig
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{% extends "bundles/TwigBundle/Exception/error.html.twig" %}
|
||||
|
||||
{% set untrusted_host = exception.message starts with 'Untrusted Host' or exception.message starts with 'Invalid Host' %}
|
||||
{% set seen_host = untrusted_host ? (exception.message|split('"'))[1]|default(null) : null %}
|
||||
|
||||
{% block status_comment %}
|
||||
{% if untrusted_host %}
|
||||
Part-DB was accessed using a host name that is not marked as trusted.<br>
|
||||
{% if seen_host %}
|
||||
The host name Part-DB saw was: <code>{{ seen_host }}</code>
|
||||
{% else %}
|
||||
<code>{{ exception.message }}</code>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
Your browser sent a request that the server could not understand.
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block admin_info %}
|
||||
{% if untrusted_host %}
|
||||
<b><i>Untrusted host name.</i></b><br>
|
||||
<p>For security reasons (to prevent HTTP Host header attacks), Part-DB only responds to requests using host names that were explicitly marked as trusted, once more than one host name is used to access it (e.g. behind a reverse proxy).</p>
|
||||
<p>Try following things:</p>
|
||||
<ul>
|
||||
<li>Ensure that you are using the correct URL to access Part-DB.</li>
|
||||
<li>Set the <code>TRUSTED_HOSTS</code> environment variable in your <code>.env.local</code> file (or your docker-compose environment) to a regular expression matching all host names Part-DB should be reachable under, e.g.
|
||||
{% if seen_host %}
|
||||
<code>TRUSTED_HOSTS='^({{ seen_host|replace({'.': '\\.'}) }})$'</code> (if <code>{{ seen_host }}</code> is a host name you trust)
|
||||
{% else %}
|
||||
<code>TRUSTED_HOSTS='^(localhost|example\.com)$'</code>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>If Part-DB is running behind a reverse proxy, also make sure that <code>TRUSTED_PROXIES</code> is configured correctly, so the original host name is forwarded properly.</li>
|
||||
<li>Run <kbd>php bin/console cache:clear</kbd> after changing the configuration.</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
{{ parent() }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -95,6 +95,16 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if trusted_hosts_unconfigured and is_granted('@system.server_infos') %}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h5><i class="fa-solid fa-triangle-exclamation fa-fw"></i> {% trans %}system.trusted_hosts.unconfigured.title{% endtrans %}</h5>
|
||||
<p class="mb-1">{% trans %}system.trusted_hosts.unconfigured.message{% endtrans %}</p>
|
||||
<p class="mb-0">{% trans %}system.trusted_hosts.unconfigured.suggestion{% endtrans %}
|
||||
<br><code>TRUSTED_HOSTS='^({{ app.request.host|replace({'.': '\\.'}) }})$'</code></p>
|
||||
<small>{% trans %}update_manager.new_version_available.only_administrators_can_see{% endtrans %}</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('@system.show_updates') %}
|
||||
{{ nv.new_version_alert(new_version_available, new_version, new_version_url) }}
|
||||
{% endif %}
|
||||
|
|
|
|||
83
translations/frontend.ko.xlf
Normal file
83
translations/frontend.ko.xlf
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="ko">
|
||||
<file id="frontend.en">
|
||||
<unit id="eLrezdb" name="search.placeholder">
|
||||
<segment state="translated">
|
||||
<source>search.placeholder</source>
|
||||
<target>검색</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="R4hoCqe" name="part.labelp">
|
||||
<segment state="translated">
|
||||
<source>part.labelp</source>
|
||||
<target>부품</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
||||
<segment state="translated">
|
||||
<source>entity.select.group.new_not_added_to_DB</source>
|
||||
<target>신규 (아직 DB에 추가되지 않음)</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="9rnHbSK" name="user.password_strength.very_weak">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.very_weak</source>
|
||||
<target>매우 약함</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gKHmHwM" name="user.password_strength.weak">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.weak</source>
|
||||
<target>약함</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="c44gN8b" name="user.password_strength.medium">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.medium</source>
|
||||
<target>보통</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="NwiBLHc" name="user.password_strength.strong">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.strong</source>
|
||||
<target>강함</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Bw.iCUm" name="user.password_strength.very_strong">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.very_strong</source>
|
||||
<target>매우 강함</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="U5IhkwB" name="search.submit">
|
||||
<segment state="translated">
|
||||
<source>search.submit</source>
|
||||
<target>이동!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8d38e7538" name="user.password_strength.crack_time">
|
||||
<segment state="translated">
|
||||
<source>user.password_strength.crack_time</source>
|
||||
<target>예상 해독 시간: %time%</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dBtnOk01" name="dialog.btn.ok">
|
||||
<segment state="translated">
|
||||
<source>dialog.btn.ok</source>
|
||||
<target>확인</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dBtnCcl1" name="dialog.btn.cancel">
|
||||
<segment state="translated">
|
||||
<source>dialog.btn.cancel</source>
|
||||
<target>취소</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dBtnDny1" name="dialog.btn.deny">
|
||||
<segment state="translated">
|
||||
<source>dialog.btn.deny</source>
|
||||
<target>아니요</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
@ -13697,6 +13697,24 @@ Buerklin-API Authentication server:
|
|||
<target>You can use this randomly generated value (share it with nobody):</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OP7MacF" name="system.trusted_hosts.unconfigured.title">
|
||||
<segment state="translated">
|
||||
<source>system.trusted_hosts.unconfigured.title</source>
|
||||
<target>TRUSTED_HOSTS not configured</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="88NkHLV" name="system.trusted_hosts.unconfigured.message">
|
||||
<segment state="translated">
|
||||
<source>system.trusted_hosts.unconfigured.message</source>
|
||||
<target>The <code>TRUSTED_HOSTS</code> environment variable is not set. This means Part-DB will accept requests for any host name, which can be a security risk (e.g. HTTP Host header injection). It is recommended to restrict this to the host names Part-DB is actually reachable under.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="qZ_kgWT" name="system.trusted_hosts.unconfigured.suggestion">
|
||||
<segment state="translated">
|
||||
<source>system.trusted_hosts.unconfigured.suggestion</source>
|
||||
<target>Set it to a regular expression matching all host names Part-DB should be reachable under in your <code>.env.local</code> or <code>docker-compose.yaml</code> file, e.g. based on the host name you used to access this page:</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cEwxoSj" name="info_providers.provider_key">
|
||||
<segment state="translated">
|
||||
<source>info_providers.provider_key</source>
|
||||
|
|
|
|||
13749
translations/messages.ko.xlf
Normal file
13749
translations/messages.ko.xlf
Normal file
File diff suppressed because it is too large
Load diff
23
translations/security.ko.xlf
Normal file
23
translations/security.ko.xlf
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="ko">
|
||||
<file id="security.en">
|
||||
<unit id="GrLNa9P" name="user.login_error.user_disabled">
|
||||
<segment state="translated">
|
||||
<source>user.login_error.user_disabled</source>
|
||||
<target>계정이 비활성화되어 있습니다! 오류라고 생각되면 관리자에게 문의하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="IFQ5XrG" name="saml.error.cannot_login_local_user_per_saml">
|
||||
<segment state="translated">
|
||||
<source>saml.error.cannot_login_local_user_per_saml</source>
|
||||
<target>로컬 사용자는 SSO로 로그인할 수 없습니다! 로컬 사용자 비밀번호를 사용하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="wOYPZmb" name="saml.error.cannot_login_saml_user_locally">
|
||||
<segment state="translated">
|
||||
<source>saml.error.cannot_login_saml_user_locally</source>
|
||||
<target>SAML 사용자는 로컬 인증으로 로그인할 수 없습니다! SSO 로그인을 사용하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
275
translations/validators.ko.xlf
Normal file
275
translations/validators.ko.xlf
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="ko">
|
||||
<file id="validators.en">
|
||||
<unit id="cRbk.cm" name="part.master_attachment.must_be_picture">
|
||||
<segment state="translated">
|
||||
<source>part.master_attachment.must_be_picture</source>
|
||||
<target>미리보기 첨부파일은 유효한 사진이어야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="v8HkcJB" name="structural.entity.unique_name">
|
||||
<segment state="translated">
|
||||
<source>structural.entity.unique_name</source>
|
||||
<target>이 계층에 같은 이름의 요소가 이미 있습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="dW7b2B_" name="parameters.validator.min_lesser_typical">
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.min_lesser_typical</source>
|
||||
<target>값은 일반값({{ compared_value }}) 이하여야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Yfp2uC5" name="parameters.validator.min_lesser_max">
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.min_lesser_max</source>
|
||||
<target>값은 최대값({{ compared_value }})보다 작아야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="P6b.8Ou" name="parameters.validator.max_greater_typical">
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.max_greater_typical</source>
|
||||
<target>값은 일반값({{ compared_value }}) 이상이어야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="P41193Y" name="validator.user.username_already_used">
|
||||
<segment state="translated">
|
||||
<source>validator.user.username_already_used</source>
|
||||
<target>같은 이름의 사용자가 이미 있습니다</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="EKPQiyf" name="user.invalid_username">
|
||||
<segment state="translated">
|
||||
<source>user.invalid_username</source>
|
||||
<target>사용자 이름은 문자, 숫자, 밑줄, 마침표, 더하기, 빼기만 포함할 수 있으며 @로 시작할 수 없습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="_v.DMg." name="validator.noneofitschild.self">
|
||||
<notes>
|
||||
<note category="state" priority="1">obsolete</note>
|
||||
</notes>
|
||||
<segment state="translated">
|
||||
<source>validator.noneofitschild.self</source>
|
||||
<target>요소는 자기 자신의 상위가 될 수 없습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="W90LyFQ" name="validator.noneofitschild.children">
|
||||
<notes>
|
||||
<note category="state" priority="1">obsolete</note>
|
||||
</notes>
|
||||
<segment state="translated">
|
||||
<source>validator.noneofitschild.children</source>
|
||||
<target>하위 요소를 상위 요소로 지정할 수 없습니다 (순환이 발생합니다)!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GAUS.LK" name="validator.select_valid_category">
|
||||
<segment state="translated">
|
||||
<source>validator.select_valid_category</source>
|
||||
<target>유효한 카테고리를 선택하세요!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="h6qELde" name="validator.part_lot.only_existing">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.only_existing</source>
|
||||
<target>이 위치는 "기존 항목만"으로 표시되어 새 부품을 추가할 수 없습니다</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Prriyy0" name="validator.part_lot.location_full.no_increase">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.location_full.no_increase</source>
|
||||
<target>위치가 가득 찼습니다. 수량을 늘릴 수 없습니다 (새 값은 {{ old_amount }}보다 작아야 합니다).</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="eeEjB4s" name="validator.part_lot.location_full">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.location_full</source>
|
||||
<target>위치가 가득 찼습니다. 새 부품을 추가할 수 없습니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2yWi8eP" name="validator.part_lot.single_part">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.single_part</source>
|
||||
<target>이 위치는 단일 부품만 보관할 수 있으며 이미 가득 찼습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="A.TFhbb" name="validator.attachment.must_not_be_null">
|
||||
<segment state="translated">
|
||||
<source>validator.attachment.must_not_be_null</source>
|
||||
<target>첨부파일 형식을 선택해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id=".lqKoij" name="validator.orderdetail.supplier_must_not_be_null">
|
||||
<segment state="translated">
|
||||
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
||||
<target>판매처를 선택해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="bcNZzK." name="validator.measurement_unit.use_si_prefix_needs_unit">
|
||||
<segment state="translated">
|
||||
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
||||
<target>SI 접두사를 사용하려면 단위 기호를 설정해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gZ5FFL1" name="part.ipn.must_be_unique">
|
||||
<segment state="translated">
|
||||
<source>part.ipn.must_be_unique</source>
|
||||
<target>내부 부품 번호는 고유해야 합니다. {{ value }}은(는) 이미 사용 중입니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="P31Yg.d" name="validator.project.bom_entry.name_or_part_needed">
|
||||
<segment state="translated">
|
||||
<source>validator.project.bom_entry.name_or_part_needed</source>
|
||||
<target>부품 BOM 항목에는 부품을 선택하고, 부품이 아닌 BOM 항목에는 이름을 설정해야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.name_already_in_bom</source>
|
||||
<target>같은 이름의 BOM 항목이 이미 있습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="jB3B50E" name="project.bom_entry.part_already_in_bom">
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.part_already_in_bom</source>
|
||||
<target>이 부품은 이미 BOM에 있습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="NdkzP1n" name="project.bom_entry.mountnames_quantity_mismatch">
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
||||
<target>장착 이름의 수는 BOM 수량과 일치해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="8teRCgR" name="project.bom_entry.can_not_add_own_builds_part">
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
||||
<target>프로젝트 자신의 빌드 부품을 BOM에 추가할 수 없습니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="asBxPxe" name="project.bom_has_to_include_all_subelement_parts">
|
||||
<segment state="translated">
|
||||
<source>project.bom_has_to_include_all_subelement_parts</source>
|
||||
<target>프로젝트 BOM에는 모든 하위 프로젝트의 빌드 부품이 포함되어야 합니다. %project_name% 프로젝트의 %part_name% 부품이 누락되었습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="uxaE9Ct" name="project.bom_entry.price_not_allowed_on_parts">
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
||||
<target>부품과 연결된 BOM 항목에는 가격을 설정할 수 없습니다. 대신 부품에 가격을 정의하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="xZ68Nzl" name="validator.project_build.lot_bigger_than_needed">
|
||||
<segment state="translated">
|
||||
<source>validator.project_build.lot_bigger_than_needed</source>
|
||||
<target>필요한 것보다 많은 출고 수량을 선택했습니다! 불필요한 수량을 제거하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="68_.V_X" name="validator.project_build.lot_smaller_than_needed">
|
||||
<segment state="translated">
|
||||
<source>validator.project_build.lot_smaller_than_needed</source>
|
||||
<target>제작에 필요한 것보다 적은 출고 수량을 선택했습니다! 수량을 추가하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yZGS8uZ" name="part.name.must_match_category_regex">
|
||||
<segment state="translated">
|
||||
<source>part.name.must_match_category_regex</source>
|
||||
<target>부품 이름이 카테고리에서 지정한 정규 표현식과 일치하지 않습니다: %regex%</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Q8wP5Jd" name="validator.attachment.name_not_blank">
|
||||
<segment state="translated">
|
||||
<source>validator.attachment.name_not_blank</source>
|
||||
<target>여기에 값을 설정하거나, 파일을 업로드하여 파일 이름을 첨부파일 이름으로 자동 사용하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DH0IkNR" name="validator.part_lot.owner_must_match_storage_location_owner">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.owner_must_match_storage_location_owner</source>
|
||||
<target>이 로트의 소유자는 선택한 보관 위치의 소유자(%owner_name%)와 일치해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="TzySicw" name="validator.part_lot.owner_must_not_be_anonymous">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.owner_must_not_be_anonymous</source>
|
||||
<target>로트 소유자는 익명 사용자일 수 없습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GthNWUb" name="validator.part_association.must_set_an_value_if_type_is_other">
|
||||
<segment state="translated">
|
||||
<source>validator.part_association.must_set_an_value_if_type_is_other</source>
|
||||
<target>유형을 "기타"로 설정한 경우 이를 설명하는 값을 설정해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Be4Im81" name="validator.part_association.part_cannot_be_associated_with_itself">
|
||||
<segment state="translated">
|
||||
<source>validator.part_association.part_cannot_be_associated_with_itself</source>
|
||||
<target>부품은 자기 자신과 연관될 수 없습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="q5Ej6Xm" name="validator.part_association.already_exists">
|
||||
<segment state="translated">
|
||||
<source>validator.part_association.already_exists</source>
|
||||
<target>이 부품과의 연관이 이미 있습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="HbI5bga" name="validator.part_lot.vendor_barcode_must_be_unique">
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.vendor_barcode_must_be_unique</source>
|
||||
<target>이 공급업체 바코드 값은 다른 로트에서 이미 사용되었습니다. 바코드는 고유해야 합니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ufQJh7E" name="validator.year_2038_bug_on_32bit">
|
||||
<segment state="translated">
|
||||
<source>validator.year_2038_bug_on_32bit</source>
|
||||
<target>기술적 제약으로 인해 32비트 시스템에서는 2038-01-19 이후의 날짜를 선택할 수 없습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="iM9yb_p" name="validator.fileSize.invalidFormat">
|
||||
<segment state="translated">
|
||||
<source>validator.fileSize.invalidFormat</source>
|
||||
<target>유효하지 않은 파일 크기 형식입니다. 정수와 함께 킬로, 메가, 기가바이트를 뜻하는 K, M, G 접미사를 사용하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ZFxQ0BZ" name="validator.invalid_range">
|
||||
<segment state="translated">
|
||||
<source>validator.invalid_range</source>
|
||||
<target>지정한 범위가 유효하지 않습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="m4gp2P_" name="validator.google_code.wrong_code">
|
||||
<segment state="translated">
|
||||
<source>validator.google_code.wrong_code</source>
|
||||
<target>유효하지 않은 코드입니다. 인증 앱이 올바르게 설정되어 있는지, 서버와 인증 기기의 시간이 정확한지 확인하세요.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="I330cr5" name="settings.synonyms.type_synonyms.collection_type.duplicate">
|
||||
<segment state="translated">
|
||||
<source>settings.synonyms.type_synonyms.collection_type.duplicate</source>
|
||||
<target>이 유형과 언어에 대한 번역이 이미 정의되어 있습니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="zT_j_oQ" name="validator.invalid_gtin">
|
||||
<segment state="translated">
|
||||
<source>validator.invalid_gtin</source>
|
||||
<target>유효한 GTIN / EAN이 아닙니다!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vnpejmb" name="info_providers.validation.provider_id_without_key">
|
||||
<segment state="translated">
|
||||
<source>info_providers.validation.provider_id_without_key</source>
|
||||
<target>제공자 ID를 지정하려면 정보 제공자도 지정하거나, 둘 다 제거해야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="yFlA5OA" name="info_providers.validation.provider_url_without_key">
|
||||
<segment state="translated">
|
||||
<source>info_providers.validation.provider_url_without_key</source>
|
||||
<target>제공자 URL을 지정하려면 정보 제공자도 지정해야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="gUHUXoV" name="info_providers.validation.provider_key_without_id">
|
||||
<segment state="translated">
|
||||
<source>info_providers.validation.provider_key_without_id</source>
|
||||
<target>정보 제공자를 지정하려면 제공자 ID도 지정하거나, 둘 다 제거해야 합니다.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
22
yarn.lock
22
yarn.lock
|
|
@ -2926,9 +2926,9 @@ domutils@^3.0.1:
|
|||
domhandler "^5.0.3"
|
||||
|
||||
electron-to-chromium@^1.5.389:
|
||||
version "1.5.392"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.392.tgz#31e9f9af0d8df3d1489468a4242b173605617482"
|
||||
integrity sha512-1yQq3VQCZRwsnYc67Oc+1fge6Lwtn0hzi6zmEVkB61Zx21kTbwJAW4dFLadl5Rc1tKhG/kSpYXnfiAhu0f0a1g==
|
||||
version "1.5.393"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.393.tgz#aec971df2a6f4f7e51fbacb200d66cebfc7d3c17"
|
||||
integrity sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg==
|
||||
|
||||
emoji-regex@^8.0.0:
|
||||
version "8.0.0"
|
||||
|
|
@ -3048,9 +3048,9 @@ fast-deep-equal@^3.1.3:
|
|||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-uri@^3.0.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.3.tgz#f695a40f006aba505631573a0021ddb21194ad11"
|
||||
integrity sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==
|
||||
version "3.1.4"
|
||||
resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.4.tgz#3b3daf9ce68f41f956df0b505132c0cfce9ec7af"
|
||||
integrity sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==
|
||||
|
||||
fastest-levenshtein@1.0.16, fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.0.16:
|
||||
version "1.0.16"
|
||||
|
|
@ -4065,7 +4065,7 @@ ms@^2.1.3:
|
|||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
nanoid@^3.3.12:
|
||||
nanoid@^3.3.16:
|
||||
version "3.3.16"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.16.tgz#a04d8ec4b1f10009d2d533947aefe4293737816c"
|
||||
integrity sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==
|
||||
|
|
@ -4455,11 +4455,11 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
|
|||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
postcss@^8.2.14, postcss@^8.4.40:
|
||||
version "8.5.19"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.19.tgz#45ad5cfde499408e20147348237551381a922037"
|
||||
integrity sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==
|
||||
version "8.5.20"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.20.tgz#316a139da79484ce55969fa7bb6f2f1abcc14060"
|
||||
integrity sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==
|
||||
dependencies:
|
||||
nanoid "^3.3.12"
|
||||
nanoid "^3.3.16"
|
||||
picocolors "^1.1.1"
|
||||
source-map-js "^1.2.1"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue