From 97d3db3f5638eca6869e399e5310521df34be896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 15:43:30 +0200 Subject: [PATCH 001/257] feat: add docker support --- .env | 34 +-- Dockerfile | 94 +++++++ compose.override.yaml | 26 +- compose.prod.yaml | 10 + compose.yaml | 44 +++- frankenphp/Caddyfile | 47 ++++ frankenphp/conf.d/10-app.ini | 13 + frankenphp/conf.d/20-app.dev.ini | 5 + frankenphp/conf.d/20-app.prod.ini | 2 + frankenphp/docker-entrypoint.sh | 60 +++++ frankenphp/worker.Caddyfile | 4 + importmap.php | 28 --- package.json | 80 ++---- phpstan.dist.neon | 2 +- symfony.lock | 396 ------------------------------ webpack.config.js | 20 +- 16 files changed, 349 insertions(+), 516 deletions(-) create mode 100644 Dockerfile create mode 100644 compose.prod.yaml create mode 100644 frankenphp/Caddyfile create mode 100644 frankenphp/conf.d/10-app.ini create mode 100644 frankenphp/conf.d/20-app.dev.ini create mode 100644 frankenphp/conf.d/20-app.prod.ini create mode 100755 frankenphp/docker-entrypoint.sh create mode 100644 frankenphp/worker.Caddyfile delete mode 100644 importmap.php delete mode 100644 symfony.lock diff --git a/.env b/.env index 221b2c4..cc68264 100644 --- a/.env +++ b/.env @@ -16,7 +16,7 @@ ###> symfony/framework-bundle ### APP_ENV=dev -APP_SECRET=9bf13abc0017f7656f631c6ca2510e02 +APP_SECRET=cacb7ba341ce4afca66611c4956a4699 ###< symfony/framework-bundle ### ###> doctrine/doctrine-bundle ### @@ -29,33 +29,33 @@ APP_SECRET=9bf13abc0017f7656f631c6ca2510e02 DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" ###< doctrine/doctrine-bundle ### -###> symfony/messenger ### -# Choose one of the transports below -# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages -# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages -MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 -###< symfony/messenger ### - -###> symfony/mailer ### -# MAILER_DSN=null://null -###< symfony/mailer ### +###> lexik/jwt-authentication-bundle ### +JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem +JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem +JWT_PASSPHRASE=0456f23bb41aa797092f1422dc9295e9855c3518fa82969a10716bf09f99d24d +###< lexik/jwt-authentication-bundle ### ###> nelmio/cors-bundle ### CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' ###< nelmio/cors-bundle ### -###> lexik/jwt-authentication-bundle ### -JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem -JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem -JWT_PASSPHRASE=827c9f8cce8bb82e75b2aec4a14a61f572ac28c7a8531f08dcdf1652573a7049 -###< lexik/jwt-authentication-bundle ### - ###> symfony/lock ### # Choose one of the stores below # postgresql+advisory://db_user:db_password@localhost/db_name LOCK_DSN=flock ###< symfony/lock ### +###> symfony/mailer ### +# MAILER_DSN=null://null +###< symfony/mailer ### + +###> symfony/messenger ### +# Choose one of the transports below +# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages +# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages +MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 +###< symfony/messenger ### + MAILER_SENDER_NAME="Domain Watchdog" MAILER_SENDER_EMAIL=notifications@example.com diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..efeb744 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,94 @@ +#syntax=docker/dockerfile:1.4 + +# Versions +FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream + +# The different stages of this Dockerfile are meant to be built into separate images +# https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage +# https://docs.docker.com/compose/compose-file/#target + + +# Base FrankenPHP image +FROM frankenphp_upstream AS frankenphp_base + +WORKDIR /app + +VOLUME /app/var/ + +# persistent / runtime deps +# hadolint ignore=DL3008 +RUN apt-get update && apt-get install -y --no-install-recommends \ + acl \ + file \ + gettext \ + git \ + && rm -rf /var/lib/apt/lists/* + +RUN set -eux; \ + install-php-extensions \ + @composer \ + apcu \ + intl \ + opcache \ + zip \ + ; + +# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser +ENV COMPOSER_ALLOW_SUPERUSER=1 + +ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d" + +###> recipes ### +###< recipes ### + +COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/ +COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-entrypoint +COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile + +ENTRYPOINT ["docker-entrypoint"] + +HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1 +CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ] + +# Dev FrankenPHP image +FROM frankenphp_base AS frankenphp_dev + +ENV APP_ENV=dev XDEBUG_MODE=off + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" + +RUN set -eux; \ + install-php-extensions \ + xdebug \ + ; + +COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/ + +CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile", "--watch" ] + +# Prod FrankenPHP image +FROM frankenphp_base AS frankenphp_prod + +ENV APP_ENV=prod +ENV FRANKENPHP_CONFIG="import worker.Caddyfile" + +RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" + +COPY --link frankenphp/conf.d/20-app.prod.ini $PHP_INI_DIR/app.conf.d/ +COPY --link frankenphp/worker.Caddyfile /etc/caddy/worker.Caddyfile + +# prevent the reinstallation of vendors at every changes in the source code +COPY --link composer.* symfony.* ./ +RUN set -eux; \ + composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress + +# copy sources +COPY --link . ./ +RUN rm -Rf frankenphp/ + +RUN set -eux; \ + mkdir -p var/cache var/log; \ + composer dump-autoload --classmap-authoritative --no-dev; \ + composer dump-env prod; \ + composer run-script --no-dev post-install-cmd; \ + chmod +x bin/console; sync; \ diff --git a/compose.override.yaml b/compose.override.yaml index 4ddb3ff..3821899 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -1,6 +1,28 @@ -version: '3' - +# Development environment override services: + php: + build: + context: . + target: frankenphp_dev + volumes: + - ./:/app + - ./frankenphp/Caddyfile:/etc/caddy/Caddyfile:ro + - ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/app.conf.d/20-app.dev.ini:ro + # If you develop on Mac or Windows you can remove the vendor/ directory + # from the bind-mount for better performance by enabling the next line: + #- /app/vendor + environment: + MERCURE_EXTRA_DIRECTIVES: demo + # See https://xdebug.org/docs/all_settings#mode + XDEBUG_MODE: "${XDEBUG_MODE:-off}" + extra_hosts: + # Ensure that host.docker.internal is correctly defined on Linux + - host.docker.internal:host-gateway + tty: true + +###> symfony/mercure-bundle ### +###< symfony/mercure-bundle ### + ###> doctrine/doctrine-bundle ### database: ports: diff --git a/compose.prod.yaml b/compose.prod.yaml new file mode 100644 index 0000000..f0db05d --- /dev/null +++ b/compose.prod.yaml @@ -0,0 +1,10 @@ +# Production environment override +services: + php: + build: + context: . + target: frankenphp_prod + environment: + APP_SECRET: ${APP_SECRET} + MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} + MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} diff --git a/compose.yaml b/compose.yaml index d563bf9..f53e21f 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,6 +1,41 @@ -version: '3' - services: + php: + image: ${IMAGES_PREFIX:-}app-php + restart: unless-stopped + environment: + SERVER_NAME: ${SERVER_NAME:-localhost}, php:80 + MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} + MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} + # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM + DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8} + # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration + MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure} + MERCURE_PUBLIC_URL: ${CADDY_MERCURE_PUBLIC_URL:-https://${SERVER_NAME:-localhost}/.well-known/mercure} + MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} + # The two next lines can be removed after initial installation + SYMFONY_VERSION: ${SYMFONY_VERSION:-} + STABILITY: ${STABILITY:-stable} + volumes: + - caddy_data:/data + - caddy_config:/config + ports: + # HTTP + - target: 80 + published: ${HTTP_PORT:-80} + protocol: tcp + # HTTPS + - target: 443 + published: ${HTTPS_PORT:-443} + protocol: tcp + # HTTP/3 + - target: 443 + published: ${HTTP3_PORT:-443} + protocol: udp + +# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service +###> symfony/mercure-bundle ### +###< symfony/mercure-bundle ### + ###> doctrine/doctrine-bundle ### database: image: postgres:${POSTGRES_VERSION:-16}-alpine @@ -21,6 +56,11 @@ services: ###< doctrine/doctrine-bundle ### volumes: + caddy_data: + caddy_config: +###> symfony/mercure-bundle ### +###< symfony/mercure-bundle ### + ###> doctrine/doctrine-bundle ### database_data: ###< doctrine/doctrine-bundle ### diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile new file mode 100644 index 0000000..b8bb57d --- /dev/null +++ b/frankenphp/Caddyfile @@ -0,0 +1,47 @@ +{ + {$CADDY_GLOBAL_OPTIONS} + + frankenphp { + {$FRANKENPHP_CONFIG} + } +} + +{$CADDY_EXTRA_CONFIG} + +{$SERVER_NAME:localhost} { + log { + # Redact the authorization query parameter that can be set by Mercure + format filter { + request>uri query { + replace authorization REDACTED + } + } + } + + root * /app/public + encode zstd br gzip + + mercure { + # Transport to use (default to Bolt) + transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db} + # Publisher JWT key + publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG} + # Subscriber JWT key + subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG} + # Allow anonymous subscribers (double-check that it's what you want) + anonymous + # Enable the subscription API (double-check that it's what you want) + subscriptions + # Extra directives + {$MERCURE_EXTRA_DIRECTIVES} + } + + vulcain + + {$CADDY_SERVER_EXTRA_DIRECTIVES} + + # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics + header ?Permissions-Policy "browsing-topics=()" + + php_server +} diff --git a/frankenphp/conf.d/10-app.ini b/frankenphp/conf.d/10-app.ini new file mode 100644 index 0000000..79a17dd --- /dev/null +++ b/frankenphp/conf.d/10-app.ini @@ -0,0 +1,13 @@ +expose_php = 0 +date.timezone = UTC +apc.enable_cli = 1 +session.use_strict_mode = 1 +zend.detect_unicode = 0 + +; https://symfony.com/doc/current/performance.html +realpath_cache_size = 4096K +realpath_cache_ttl = 600 +opcache.interned_strings_buffer = 16 +opcache.max_accelerated_files = 20000 +opcache.memory_consumption = 256 +opcache.enable_file_override = 1 diff --git a/frankenphp/conf.d/20-app.dev.ini b/frankenphp/conf.d/20-app.dev.ini new file mode 100644 index 0000000..e50f43d --- /dev/null +++ b/frankenphp/conf.d/20-app.dev.ini @@ -0,0 +1,5 @@ +; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host +; See https://github.com/docker/for-linux/issues/264 +; The `client_host` below may optionally be replaced with `discover_client_host=yes` +; Add `start_with_request=yes` to start debug session on each request +xdebug.client_host = host.docker.internal diff --git a/frankenphp/conf.d/20-app.prod.ini b/frankenphp/conf.d/20-app.prod.ini new file mode 100644 index 0000000..3bcaa71 --- /dev/null +++ b/frankenphp/conf.d/20-app.prod.ini @@ -0,0 +1,2 @@ +opcache.preload_user = root +opcache.preload = /app/config/preload.php diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh new file mode 100755 index 0000000..9823560 --- /dev/null +++ b/frankenphp/docker-entrypoint.sh @@ -0,0 +1,60 @@ +#!/bin/sh +set -e + +if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then + # Install the project the first time PHP is started + # After the installation, the following block can be deleted + if [ ! -f composer.json ]; then + rm -Rf tmp/ + composer create-project "symfony/skeleton $SYMFONY_VERSION" tmp --stability="$STABILITY" --prefer-dist --no-progress --no-interaction --no-install + + cd tmp + cp -Rp . .. + cd - + rm -Rf tmp/ + + composer require "php:>=$PHP_VERSION" runtime/frankenphp-symfony + composer config --json extra.symfony.docker 'true' + + if grep -q ^DATABASE_URL= .env; then + echo "To finish the installation please press Ctrl+C to stop Docker Compose and run: docker compose up --build -d --wait" + sleep infinity + fi + fi + + if [ -z "$(ls -A 'vendor/' 2>/dev/null)" ]; then + composer install --prefer-dist --no-progress --no-interaction + fi + + if grep -q ^DATABASE_URL= .env; then + echo "Waiting for database to be ready..." + ATTEMPTS_LEFT_TO_REACH_DATABASE=60 + until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || DATABASE_ERROR=$(php bin/console dbal:run-sql -q "SELECT 1" 2>&1); do + if [ $? -eq 255 ]; then + # If the Doctrine command exits with 255, an unrecoverable error occurred + ATTEMPTS_LEFT_TO_REACH_DATABASE=0 + break + fi + sleep 1 + ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE - 1)) + echo "Still waiting for database to be ready... Or maybe the database is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left." + done + + if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then + echo "The database is not up or not reachable:" + echo "$DATABASE_ERROR" + exit 1 + else + echo "The database is now ready and reachable" + fi + + if [ "$( find ./migrations -iname '*.php' -print -quit )" ]; then + php bin/console doctrine:migrations:migrate --no-interaction --all-or-nothing + fi + fi + + setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var + setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var +fi + +exec docker-php-entrypoint "$@" diff --git a/frankenphp/worker.Caddyfile b/frankenphp/worker.Caddyfile new file mode 100644 index 0000000..d384ae4 --- /dev/null +++ b/frankenphp/worker.Caddyfile @@ -0,0 +1,4 @@ +worker { + file ./public/index.php + env APP_RUNTIME Runtime\FrankenPhpSymfony\Runtime +} diff --git a/importmap.php b/importmap.php deleted file mode 100644 index b73b323..0000000 --- a/importmap.php +++ /dev/null @@ -1,28 +0,0 @@ - [ - 'path' => './assets/app.js', - 'entrypoint' => true, - ], - '@hotwired/stimulus' => [ - 'version' => '3.2.2', - ], - '@symfony/stimulus-bundle' => [ - 'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js', - ], - '@hotwired/turbo' => [ - 'version' => '7.3.0', - ], -]; diff --git a/package.json b/package.json index b4d3eed..b4ce2a6 100644 --- a/package.json +++ b/package.json @@ -1,64 +1,20 @@ { - "name": "domain-watchdog", - "author": { - "name": "Maël Gangloff", - "email": "contact@maelgangloff.fr" - }, - "homepage": "https://github.com/maelgangloff/domain-watchdog", - "readme": "https://github.com/maelgangloff/domain-watchdog", - "keywords": [ - "Domain", - "RDAP", - "WHOIS" - ], - "bugs": { - "url": "https://github.com/maelgangloff/domain-watchdog/issues" - }, - "devDependencies": { - "@babel/core": "^7.17.0", - "@babel/preset-env": "^7.16.0", - "@babel/preset-react": "^7.24.7", - "@fontsource/noto-color-emoji": "^5.0.27", - "@symfony/webpack-encore": "^4.0.0", - "@types/axios": "^0.14.0", - "@types/jsonld": "^1.5.15", - "@types/punycode": "^2.1.4", - "@types/react": "^18.3.3", - "@types/react-dom": "^18.3.0", - "@types/react-responsive": "^8.0.8", - "@types/vcf": "^2.0.7", - "antd": "^5.19.3", - "axios": "^1.7.2", - "core-js": "^3.23.0", - "html-loader": "^5.1.0", - "jsonld": "^8.3.2", - "punycode": "^2.3.1", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "react-responsive": "^10.0.0", - "react-router-dom": "^6.25.1", - "regenerator-runtime": "^0.13.9", - "snarkdown": "^2.0.0", - "ts-loader": "^9.5.1", - "ttag": "^1.8.7", - "ttag-cli": "^1.10.12", - "typescript": "^5.5.3", - "vcf": "^2.1.2", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0", - "webpack-notifier": "^1.15.0" - }, - "license": "AGPL-3.0-or-later", - "private": true, - "scripts": { - "dev-server": "encore dev-server", - "dev": "encore dev", - "watch": "encore dev --watch", - "build": "encore production --progress", - "ttag:po2json": "cd translations; for i in $(find . -name \"*.po\"); do ttag po2json $i > ../public/locales/$i.json; done; cd ..", - "ttag:extract": "ttag extract $(find assets -name '*.ts' -or -name '*.tsx') -o translations/translations.pot" - }, - "dependencies": { - "remove": "^0.1.5" - } + "devDependencies": { + "@babel/core": "^7.17.0", + "@babel/preset-env": "^7.16.0", + "@symfony/webpack-encore": "^4.0.0", + "core-js": "^3.23.0", + "regenerator-runtime": "^0.13.9", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-notifier": "^1.15.0" + }, + "license": "UNLICENSED", + "private": true, + "scripts": { + "dev-server": "encore dev-server", + "dev": "encore dev", + "watch": "encore dev --watch", + "build": "encore production --progress" + } } diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 77a0da7..e0de575 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,5 @@ parameters: - level: 5 + level: 6 paths: - bin/ - config/ diff --git a/symfony.lock b/symfony.lock deleted file mode 100644 index e266829..0000000 --- a/symfony.lock +++ /dev/null @@ -1,396 +0,0 @@ -{ - "api-platform/core": { - "version": "3.3", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.3", - "ref": "74b45ac570c57eb1fbe56c984091a9ff87e18bab" - }, - "files": [ - "config/packages/api_platform.yaml", - "config/routes/api_platform.yaml", - "src/ApiResource/.gitignore" - ] - }, - "doctrine/doctrine-bundle": { - "version": "2.12", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.12", - "ref": "7266981c201efbbe02ae53c87f8bb378e3f825ae" - }, - "files": [ - "config/packages/doctrine.yaml", - "src/Entity/.gitignore", - "src/Repository/.gitignore" - ] - }, - "doctrine/doctrine-migrations-bundle": { - "version": "3.3", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.1", - "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" - }, - "files": [ - "config/packages/doctrine_migrations.yaml", - "migrations/.gitignore" - ] - }, - "friendsofphp/php-cs-fixer": { - "version": "3.61", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.0", - "ref": "be2103eb4a20942e28a6dd87736669b757132435" - }, - "files": [ - ".php-cs-fixer.dist.php" - ] - }, - "knpuniversity/oauth2-client-bundle": { - "version": "2.18", - "recipe": { - "repo": "github.com/symfony/recipes-contrib", - "branch": "main", - "version": "1.20", - "ref": "1ff300d8c030f55c99219cc55050b97a695af3f6" - }, - "files": [ - "config/packages/knpu_oauth2_client.yaml" - ] - }, - "lexik/jwt-authentication-bundle": { - "version": "3.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.5", - "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7" - }, - "files": [ - "config/packages/lexik_jwt_authentication.yaml" - ] - }, - "nelmio/cors-bundle": { - "version": "2.5", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "1.5", - "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c" - }, - "files": [ - "config/packages/nelmio_cors.yaml" - ] - }, - "phpstan/phpstan": { - "version": "1.11", - "recipe": { - "repo": "github.com/symfony/recipes-contrib", - "branch": "main", - "version": "1.0", - "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" - }, - "files": [ - "phpstan.dist.neon" - ] - }, - "phpunit/phpunit": { - "version": "9.6", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "9.6", - "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326" - }, - "files": [ - ".env.test", - "phpunit.xml.dist", - "tests/bootstrap.php" - ] - }, - "symfony/asset-mapper": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.4", - "ref": "6c28c471640cc2c6e60812ebcb961c526ef8997f" - }, - "files": [ - "assets/app.js", - "assets/styles/app.css", - "config/packages/asset_mapper.yaml", - "importmap.php" - ] - }, - "symfony/console": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "5.3", - "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" - }, - "files": [ - "bin/console" - ] - }, - "symfony/debug-bundle": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "5.3", - "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b" - }, - "files": [ - "config/packages/debug.yaml" - ] - }, - "symfony/flex": { - "version": "2.4", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "1.0", - "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" - }, - "files": [ - ".env" - ] - }, - "symfony/framework-bundle": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.0", - "ref": "6356c19b9ae08e7763e4ba2d9ae63043efc75db5" - }, - "files": [ - "config/packages/cache.yaml", - "config/packages/framework.yaml", - "config/preload.php", - "config/routes/framework.yaml", - "config/services.yaml", - "public/index.php", - "src/Controller/.gitignore", - "src/Kernel.php" - ] - }, - "symfony/lock": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "5.2", - "ref": "8e937ff2b4735d110af1770f242c1107fdab4c8e" - }, - "files": [ - "config/packages/lock.yaml" - ] - }, - "symfony/mailer": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "4.3", - "ref": "df66ee1f226c46f01e85c29c2f7acce0596ba35a" - }, - "files": [ - "config/packages/mailer.yaml" - ] - }, - "symfony/maker-bundle": { - "version": "1.60", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "1.0", - "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" - } - }, - "symfony/messenger": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.0", - "ref": "ba1ac4e919baba5644d31b57a3284d6ba12d52ee" - }, - "files": [ - "config/packages/messenger.yaml" - ] - }, - "symfony/monolog-bundle": { - "version": "3.10", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "3.7", - "ref": "aff23899c4440dd995907613c1dd709b6f59503f" - }, - "files": [ - "config/packages/monolog.yaml" - ] - }, - "symfony/notifier": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "5.0", - "ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc" - }, - "files": [ - "config/packages/notifier.yaml" - ] - }, - "symfony/phpunit-bridge": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.3", - "ref": "a411a0480041243d97382cac7984f7dce7813c08" - }, - "files": [ - ".env.test", - "bin/phpunit", - "phpunit.xml.dist", - "tests/bootstrap.php" - ] - }, - "symfony/routing": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.0", - "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" - }, - "files": [ - "config/packages/routing.yaml", - "config/routes.yaml" - ] - }, - "symfony/security-bundle": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.4", - "ref": "2ae08430db28c8eb4476605894296c82a642028f" - }, - "files": [ - "config/packages/security.yaml", - "config/routes/security.yaml" - ] - }, - "symfony/stimulus-bundle": { - "version": "2.18", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.13", - "ref": "6acd9ff4f7fd5626d2962109bd4ebab351d43c43" - }, - "files": [ - "assets/bootstrap.js", - "assets/controllers.json", - "assets/controllers/hello_controller.js" - ] - }, - "symfony/translation": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.3", - "ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" - }, - "files": [ - "config/packages/translation.yaml", - "translations/.gitignore" - ] - }, - "symfony/twig-bundle": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.4", - "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" - }, - "files": [ - "config/packages/twig.yaml", - "templates/base.html.twig" - ] - }, - "symfony/uid": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.0", - "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5" - } - }, - "symfony/ux-turbo": { - "version": "v2.18.0" - }, - "symfony/validator": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "7.0", - "ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd" - }, - "files": [ - "config/packages/validator.yaml" - ] - }, - "symfony/web-profiler-bundle": { - "version": "7.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "6.1", - "ref": "e42b3f0177df239add25373083a564e5ead4e13a" - }, - "files": [ - "config/packages/web_profiler.yaml", - "config/routes/web_profiler.yaml" - ] - }, - "symfony/webpack-encore-bundle": { - "version": "2.1", - "recipe": { - "repo": "github.com/symfony/recipes", - "branch": "main", - "version": "2.0", - "ref": "082d754b3bd54b3fc669f278f1eea955cfd23cf5" - }, - "files": [ - "assets/app.js", - "assets/styles/app.css", - "config/packages/webpack_encore.yaml", - "package.json", - "webpack.config.js" - ] - }, - "symfonycasts/verify-email-bundle": { - "version": "v1.17.0" - }, - "twig/extra-bundle": { - "version": "v3.10.0" - } -} diff --git a/webpack.config.js b/webpack.config.js index e3d324f..eabdb81 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,11 +20,14 @@ Encore * Each entry will result in one JavaScript file (e.g. app.js) * and one CSS file (e.g. app.css) if your JavaScript imports CSS. */ - .addEntry('app', './assets/index.tsx') + .addEntry('app', './assets/app.js') // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() + // enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js) + .enableStimulusBridge('./assets/controllers.json') + // will require an extra script tag for runtime.js // but, you probably want this, unless you're building a single-page app .enableSingleRuntimeChunk() @@ -57,16 +60,17 @@ Encore //.enableSassLoader() // uncomment if you use TypeScript - .enableTypeScriptLoader() + //.enableTypeScriptLoader() // uncomment if you use React - .enableReactPreset() -// uncomment to get integrity="..." attributes on your script & link tags -// requires WebpackEncoreBundle 1.4 or higher -//.enableIntegrityHashes(Encore.isProduction()) + //.enableReactPreset() -// uncomment if you're having problems with a jQuery plugin -//.autoProvidejQuery() + // uncomment to get integrity="..." attributes on your script & link tags + // requires WebpackEncoreBundle 1.4 or higher + //.enableIntegrityHashes(Encore.isProduction()) + + // uncomment if you're having problems with a jQuery plugin + //.autoProvidejQuery() ; module.exports = Encore.getWebpackConfig(); From afcf242f759180f6a787e99b4d62ca36b2ab092f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 15:53:36 +0200 Subject: [PATCH 002/257] fix: remove Mercure server --- .dockerignore | 34 ++++++++++++++++++++++++++++++++++ compose.override.yaml | 4 ---- compose.prod.yaml | 2 -- compose.yaml | 13 ------------- frankenphp/Caddyfile | 24 ------------------------ 5 files changed, 34 insertions(+), 43 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dc5a875 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,34 @@ +**/*.log +**/*.md +**/*.php~ +**/*.dist.php +**/*.dist +**/*.cache +**/._* +**/.dockerignore +**/.DS_Store +**/.git/ +**/.gitattributes +**/.gitignore +**/.gitmodules +**/compose.*.yaml +**/compose.*.yml +**/compose.yaml +**/compose.yml +**/docker-compose.*.yaml +**/docker-compose.*.yml +**/docker-compose.yaml +**/docker-compose.yml +**/Dockerfile +**/Thumbs.db +.github/ +docs/ +public/bundles/ +tests/ +var/ +vendor/ +.editorconfig +.env.*.local +.env.local +.env.local.php +.env.test diff --git a/compose.override.yaml b/compose.override.yaml index 3821899..dca2286 100644 --- a/compose.override.yaml +++ b/compose.override.yaml @@ -12,7 +12,6 @@ services: # from the bind-mount for better performance by enabling the next line: #- /app/vendor environment: - MERCURE_EXTRA_DIRECTIVES: demo # See https://xdebug.org/docs/all_settings#mode XDEBUG_MODE: "${XDEBUG_MODE:-off}" extra_hosts: @@ -20,9 +19,6 @@ services: - host.docker.internal:host-gateway tty: true -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### - ###> doctrine/doctrine-bundle ### database: ports: diff --git a/compose.prod.yaml b/compose.prod.yaml index f0db05d..d49a419 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -6,5 +6,3 @@ services: target: frankenphp_prod environment: APP_SECRET: ${APP_SECRET} - MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} - MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET} diff --git a/compose.yaml b/compose.yaml index f53e21f..564654c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -4,14 +4,8 @@ services: restart: unless-stopped environment: SERVER_NAME: ${SERVER_NAME:-localhost}, php:80 - MERCURE_PUBLISHER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} - MERCURE_SUBSCRIBER_JWT_KEY: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} # Run "composer require symfony/orm-pack" to install and configure Doctrine ORM DATABASE_URL: postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-!ChangeMe!}@database:5432/${POSTGRES_DB:-app}?serverVersion=${POSTGRES_VERSION:-15}&charset=${POSTGRES_CHARSET:-utf8} - # Run "composer require symfony/mercure-bundle" to install and configure the Mercure integration - MERCURE_URL: ${CADDY_MERCURE_URL:-http://php/.well-known/mercure} - MERCURE_PUBLIC_URL: ${CADDY_MERCURE_PUBLIC_URL:-https://${SERVER_NAME:-localhost}/.well-known/mercure} - MERCURE_JWT_SECRET: ${CADDY_MERCURE_JWT_SECRET:-!ChangeThisMercureHubJWTSecretKey!} # The two next lines can be removed after initial installation SYMFONY_VERSION: ${SYMFONY_VERSION:-} STABILITY: ${STABILITY:-stable} @@ -32,10 +26,6 @@ services: published: ${HTTP3_PORT:-443} protocol: udp -# Mercure is installed as a Caddy module, prevent the Flex recipe from installing another service -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### - ###> doctrine/doctrine-bundle ### database: image: postgres:${POSTGRES_VERSION:-16}-alpine @@ -58,9 +48,6 @@ services: volumes: caddy_data: caddy_config: -###> symfony/mercure-bundle ### -###< symfony/mercure-bundle ### - ###> doctrine/doctrine-bundle ### database_data: ###< doctrine/doctrine-bundle ### diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile index b8bb57d..9bbff76 100644 --- a/frankenphp/Caddyfile +++ b/frankenphp/Caddyfile @@ -9,33 +9,9 @@ {$CADDY_EXTRA_CONFIG} {$SERVER_NAME:localhost} { - log { - # Redact the authorization query parameter that can be set by Mercure - format filter { - request>uri query { - replace authorization REDACTED - } - } - } - root * /app/public encode zstd br gzip - mercure { - # Transport to use (default to Bolt) - transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db} - # Publisher JWT key - publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG} - # Subscriber JWT key - subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG} - # Allow anonymous subscribers (double-check that it's what you want) - anonymous - # Enable the subscription API (double-check that it's what you want) - subscriptions - # Extra directives - {$MERCURE_EXTRA_DIRECTIVES} - } - vulcain {$CADDY_SERVER_EXTRA_DIRECTIVES} From 8d0f2f6791830bfdfe5ce92f9aeb5a58f73965a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 15:57:40 +0200 Subject: [PATCH 003/257] fix: do not modify webpack.config.js --- webpack.config.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index eabdb81..e3d324f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,14 +20,11 @@ Encore * Each entry will result in one JavaScript file (e.g. app.js) * and one CSS file (e.g. app.css) if your JavaScript imports CSS. */ - .addEntry('app', './assets/app.js') + .addEntry('app', './assets/index.tsx') // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() - // enables the Symfony UX Stimulus bridge (used in assets/bootstrap.js) - .enableStimulusBridge('./assets/controllers.json') - // will require an extra script tag for runtime.js // but, you probably want this, unless you're building a single-page app .enableSingleRuntimeChunk() @@ -60,17 +57,16 @@ Encore //.enableSassLoader() // uncomment if you use TypeScript - //.enableTypeScriptLoader() + .enableTypeScriptLoader() // uncomment if you use React - //.enableReactPreset() + .enableReactPreset() +// uncomment to get integrity="..." attributes on your script & link tags +// requires WebpackEncoreBundle 1.4 or higher +//.enableIntegrityHashes(Encore.isProduction()) - // uncomment to get integrity="..." attributes on your script & link tags - // requires WebpackEncoreBundle 1.4 or higher - //.enableIntegrityHashes(Encore.isProduction()) - - // uncomment if you're having problems with a jQuery plugin - //.autoProvidejQuery() +// uncomment if you're having problems with a jQuery plugin +//.autoProvidejQuery() ; module.exports = Encore.getWebpackConfig(); From e916ce37bde2fbd221be791f503dd4a2d7c7301f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 15:58:51 +0200 Subject: [PATCH 004/257] fix: do not modify package.json --- package.json | 80 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index b4ce2a6..b4d3eed 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,64 @@ { - "devDependencies": { - "@babel/core": "^7.17.0", - "@babel/preset-env": "^7.16.0", - "@symfony/webpack-encore": "^4.0.0", - "core-js": "^3.23.0", - "regenerator-runtime": "^0.13.9", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0", - "webpack-notifier": "^1.15.0" - }, - "license": "UNLICENSED", - "private": true, - "scripts": { - "dev-server": "encore dev-server", - "dev": "encore dev", - "watch": "encore dev --watch", - "build": "encore production --progress" - } + "name": "domain-watchdog", + "author": { + "name": "Maël Gangloff", + "email": "contact@maelgangloff.fr" + }, + "homepage": "https://github.com/maelgangloff/domain-watchdog", + "readme": "https://github.com/maelgangloff/domain-watchdog", + "keywords": [ + "Domain", + "RDAP", + "WHOIS" + ], + "bugs": { + "url": "https://github.com/maelgangloff/domain-watchdog/issues" + }, + "devDependencies": { + "@babel/core": "^7.17.0", + "@babel/preset-env": "^7.16.0", + "@babel/preset-react": "^7.24.7", + "@fontsource/noto-color-emoji": "^5.0.27", + "@symfony/webpack-encore": "^4.0.0", + "@types/axios": "^0.14.0", + "@types/jsonld": "^1.5.15", + "@types/punycode": "^2.1.4", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@types/react-responsive": "^8.0.8", + "@types/vcf": "^2.0.7", + "antd": "^5.19.3", + "axios": "^1.7.2", + "core-js": "^3.23.0", + "html-loader": "^5.1.0", + "jsonld": "^8.3.2", + "punycode": "^2.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-responsive": "^10.0.0", + "react-router-dom": "^6.25.1", + "regenerator-runtime": "^0.13.9", + "snarkdown": "^2.0.0", + "ts-loader": "^9.5.1", + "ttag": "^1.8.7", + "ttag-cli": "^1.10.12", + "typescript": "^5.5.3", + "vcf": "^2.1.2", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-notifier": "^1.15.0" + }, + "license": "AGPL-3.0-or-later", + "private": true, + "scripts": { + "dev-server": "encore dev-server", + "dev": "encore dev", + "watch": "encore dev --watch", + "build": "encore production --progress", + "ttag:po2json": "cd translations; for i in $(find . -name \"*.po\"); do ttag po2json $i > ../public/locales/$i.json; done; cd ..", + "ttag:extract": "ttag extract $(find assets -name '*.ts' -or -name '*.tsx') -o translations/translations.pot" + }, + "dependencies": { + "remove": "^0.1.5" + } } From 1e2062205243dda9650ec4963202f845a71fc6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 15:59:44 +0200 Subject: [PATCH 005/257] fix: do not modify phpstan.dist.neon --- phpstan.dist.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.dist.neon b/phpstan.dist.neon index e0de575..77a0da7 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,5 @@ parameters: - level: 6 + level: 5 paths: - bin/ - config/ From 1ef446e38b5e01325457ae7dd9bacc6b5de2b8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 16:11:20 +0200 Subject: [PATCH 006/257] feat: docker support --- Dockerfile | 3 + compose.yaml | 3 + composer.json | 1 + composer.lock | 54 ++++++- symfony.lock | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 symfony.lock diff --git a/Dockerfile b/Dockerfile index efeb744..caf94af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,9 @@ ENV COMPOSER_ALLOW_SUPERUSER=1 ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d" ###> recipes ### +###> doctrine/doctrine-bundle ### +RUN install-php-extensions pdo_pgsql +###< doctrine/doctrine-bundle ### ###< recipes ### COPY --link frankenphp/conf.d/10-app.ini $PHP_INI_DIR/app.conf.d/ diff --git a/compose.yaml b/compose.yaml index 564654c..2fef85a 100644 --- a/compose.yaml +++ b/compose.yaml @@ -51,3 +51,6 @@ volumes: ###> doctrine/doctrine-bundle ### database_data: ###< doctrine/doctrine-bundle ### + +networks: + dw-net: \ No newline at end of file diff --git a/composer.json b/composer.json index 6a8c06f..930771c 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,7 @@ "phpstan/phpdoc-parser": "^1.29", "protonlabs/vobject": "^4.31", "psr/http-client": "^1.0", + "runtime/frankenphp-symfony": "^0.2.0", "symfony/asset": "7.1.*", "symfony/asset-mapper": "7.1.*", "symfony/console": "7.1.*", diff --git a/composer.lock b/composer.lock index a35c991..46447c6 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "69d672f9e5a01b48f871fa5c81714f8d", + "content-hash": "bab584811b8175e404608e6738549f52", "packages": [ { "name": "api-platform/core", @@ -3434,6 +3434,58 @@ }, "time": "2019-03-08T08:55:37+00:00" }, + { + "name": "runtime/frankenphp-symfony", + "version": "0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-runtime/frankenphp-symfony.git", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-runtime/frankenphp-symfony/zipball/56822c3631d9522a3136a4c33082d006bdfe4bad", + "reference": "56822c3631d9522a3136a4c33082d006bdfe4bad", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/runtime": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Runtime\\FrankenPhpSymfony\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "kevin@dunglas.dev" + } + ], + "description": "FrankenPHP runtime for Symfony", + "support": { + "issues": "https://github.com/php-runtime/frankenphp-symfony/issues", + "source": "https://github.com/php-runtime/frankenphp-symfony/tree/0.2.0" + }, + "funding": [ + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2023-12-12T12:06:11+00:00" + }, { "name": "sabre/uri", "version": "3.0.1", diff --git a/symfony.lock b/symfony.lock new file mode 100644 index 0000000..e266829 --- /dev/null +++ b/symfony.lock @@ -0,0 +1,396 @@ +{ + "api-platform/core": { + "version": "3.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.3", + "ref": "74b45ac570c57eb1fbe56c984091a9ff87e18bab" + }, + "files": [ + "config/packages/api_platform.yaml", + "config/routes/api_platform.yaml", + "src/ApiResource/.gitignore" + ] + }, + "doctrine/doctrine-bundle": { + "version": "2.12", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.12", + "ref": "7266981c201efbbe02ae53c87f8bb378e3f825ae" + }, + "files": [ + "config/packages/doctrine.yaml", + "src/Entity/.gitignore", + "src/Repository/.gitignore" + ] + }, + "doctrine/doctrine-migrations-bundle": { + "version": "3.3", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.1", + "ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33" + }, + "files": [ + "config/packages/doctrine_migrations.yaml", + "migrations/.gitignore" + ] + }, + "friendsofphp/php-cs-fixer": { + "version": "3.61", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.0", + "ref": "be2103eb4a20942e28a6dd87736669b757132435" + }, + "files": [ + ".php-cs-fixer.dist.php" + ] + }, + "knpuniversity/oauth2-client-bundle": { + "version": "2.18", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.20", + "ref": "1ff300d8c030f55c99219cc55050b97a695af3f6" + }, + "files": [ + "config/packages/knpu_oauth2_client.yaml" + ] + }, + "lexik/jwt-authentication-bundle": { + "version": "3.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.5", + "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7" + }, + "files": [ + "config/packages/lexik_jwt_authentication.yaml" + ] + }, + "nelmio/cors-bundle": { + "version": "2.5", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.5", + "ref": "6bea22e6c564fba3a1391615cada1437d0bde39c" + }, + "files": [ + "config/packages/nelmio_cors.yaml" + ] + }, + "phpstan/phpstan": { + "version": "1.11", + "recipe": { + "repo": "github.com/symfony/recipes-contrib", + "branch": "main", + "version": "1.0", + "ref": "5e490cc197fb6bb1ae22e5abbc531ddc633b6767" + }, + "files": [ + "phpstan.dist.neon" + ] + }, + "phpunit/phpunit": { + "version": "9.6", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "9.6", + "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326" + }, + "files": [ + ".env.test", + "phpunit.xml.dist", + "tests/bootstrap.php" + ] + }, + "symfony/asset-mapper": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "6c28c471640cc2c6e60812ebcb961c526ef8997f" + }, + "files": [ + "assets/app.js", + "assets/styles/app.css", + "config/packages/asset_mapper.yaml", + "importmap.php" + ] + }, + "symfony/console": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" + }, + "files": [ + "bin/console" + ] + }, + "symfony/debug-bundle": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b" + }, + "files": [ + "config/packages/debug.yaml" + ] + }, + "symfony/flex": { + "version": "2.4", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172" + }, + "files": [ + ".env" + ] + }, + "symfony/framework-bundle": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "6356c19b9ae08e7763e4ba2d9ae63043efc75db5" + }, + "files": [ + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/preload.php", + "config/routes/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] + }, + "symfony/lock": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.2", + "ref": "8e937ff2b4735d110af1770f242c1107fdab4c8e" + }, + "files": [ + "config/packages/lock.yaml" + ] + }, + "symfony/mailer": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "4.3", + "ref": "df66ee1f226c46f01e85c29c2f7acce0596ba35a" + }, + "files": [ + "config/packages/mailer.yaml" + ] + }, + "symfony/maker-bundle": { + "version": "1.60", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" + } + }, + "symfony/messenger": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.0", + "ref": "ba1ac4e919baba5644d31b57a3284d6ba12d52ee" + }, + "files": [ + "config/packages/messenger.yaml" + ] + }, + "symfony/monolog-bundle": { + "version": "3.10", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "3.7", + "ref": "aff23899c4440dd995907613c1dd709b6f59503f" + }, + "files": [ + "config/packages/monolog.yaml" + ] + }, + "symfony/notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.0", + "ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc" + }, + "files": [ + "config/packages/notifier.yaml" + ] + }, + "symfony/phpunit-bridge": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.3", + "ref": "a411a0480041243d97382cac7984f7dce7813c08" + }, + "files": [ + ".env.test", + "bin/phpunit", + "phpunit.xml.dist", + "tests/bootstrap.php" + ] + }, + "symfony/routing": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" + }, + "files": [ + "config/packages/routing.yaml", + "config/routes.yaml" + ] + }, + "symfony/security-bundle": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "2ae08430db28c8eb4476605894296c82a642028f" + }, + "files": [ + "config/packages/security.yaml", + "config/routes/security.yaml" + ] + }, + "symfony/stimulus-bundle": { + "version": "2.18", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.13", + "ref": "6acd9ff4f7fd5626d2962109bd4ebab351d43c43" + }, + "files": [ + "assets/bootstrap.js", + "assets/controllers.json", + "assets/controllers/hello_controller.js" + ] + }, + "symfony/translation": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.3", + "ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b" + }, + "files": [ + "config/packages/translation.yaml", + "translations/.gitignore" + ] + }, + "symfony/twig-bundle": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" + }, + "files": [ + "config/packages/twig.yaml", + "templates/base.html.twig" + ] + }, + "symfony/uid": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5" + } + }, + "symfony/ux-turbo": { + "version": "v2.18.0" + }, + "symfony/validator": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd" + }, + "files": [ + "config/packages/validator.yaml" + ] + }, + "symfony/web-profiler-bundle": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.1", + "ref": "e42b3f0177df239add25373083a564e5ead4e13a" + }, + "files": [ + "config/packages/web_profiler.yaml", + "config/routes/web_profiler.yaml" + ] + }, + "symfony/webpack-encore-bundle": { + "version": "2.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.0", + "ref": "082d754b3bd54b3fc669f278f1eea955cfd23cf5" + }, + "files": [ + "assets/app.js", + "assets/styles/app.css", + "config/packages/webpack_encore.yaml", + "package.json", + "webpack.config.js" + ] + }, + "symfonycasts/verify-email-bundle": { + "version": "v1.17.0" + }, + "twig/extra-bundle": { + "version": "v3.10.0" + } +} From 2def3bbc8eba66abced15a12eb73a6431881ebf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sun, 11 Aug 2024 20:24:04 +0200 Subject: [PATCH 007/257] fix: docker support --- Dockerfile | 56 ++++++++++++++++++++++------------------ templates/base.html.twig | 6 ++--- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Dockerfile b/Dockerfile index caf94af..79e1791 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -#syntax=docker/dockerfile:1.4 +# syntax=docker/dockerfile:1.4 # Versions FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream @@ -7,7 +7,6 @@ FROM dunglas/frankenphp:1-php8.3 AS frankenphp_upstream # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage # https://docs.docker.com/compose/compose-file/#target - # Base FrankenPHP image FROM frankenphp_upstream AS frankenphp_base @@ -18,24 +17,27 @@ VOLUME /app/var/ # persistent / runtime deps # hadolint ignore=DL3008 RUN apt-get update && apt-get install -y --no-install-recommends \ - acl \ - file \ - gettext \ - git \ - && rm -rf /var/lib/apt/lists/* + acl \ + file \ + gettext \ + git \ + && rm -rf /var/lib/apt/lists/* RUN set -eux; \ - install-php-extensions \ - @composer \ - apcu \ - intl \ - opcache \ - zip \ - ; + install-php-extensions \ + @composer \ + apcu \ + intl \ + opcache \ + zip + +RUN set -eux; \ + curl -fsSL https://deb.nodesource.com/setup_22.x | bash -; \ + apt-get install -y nodejs; \ + npm install -g yarn # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser ENV COMPOSER_ALLOW_SUPERUSER=1 - ENV PHP_INI_SCAN_DIR=":$PHP_INI_DIR/app.conf.d" ###> recipes ### @@ -49,7 +51,6 @@ COPY --link --chmod=755 frankenphp/docker-entrypoint.sh /usr/local/bin/docker-en COPY --link frankenphp/Caddyfile /etc/caddy/Caddyfile ENTRYPOINT ["docker-entrypoint"] - HEALTHCHECK --start-period=60s CMD curl -f http://localhost:2019/metrics || exit 1 CMD [ "frankenphp", "run", "--config", "/etc/caddy/Caddyfile" ] @@ -61,9 +62,8 @@ ENV APP_ENV=dev XDEBUG_MODE=off RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" RUN set -eux; \ - install-php-extensions \ - xdebug \ - ; + install-php-extensions \ + xdebug COPY --link frankenphp/conf.d/20-app.dev.ini $PHP_INI_DIR/app.conf.d/ @@ -83,15 +83,21 @@ COPY --link frankenphp/worker.Caddyfile /etc/caddy/worker.Caddyfile # prevent the reinstallation of vendors at every changes in the source code COPY --link composer.* symfony.* ./ RUN set -eux; \ - composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress + composer install --no-cache --prefer-dist --no-dev --no-autoloader --no-scripts --no-progress # copy sources COPY --link . ./ RUN rm -Rf frankenphp/ RUN set -eux; \ - mkdir -p var/cache var/log; \ - composer dump-autoload --classmap-authoritative --no-dev; \ - composer dump-env prod; \ - composer run-script --no-dev post-install-cmd; \ - chmod +x bin/console; sync; \ + mkdir -p var/cache var/log; \ + composer dump-autoload --classmap-authoritative --no-dev; \ + composer dump-env prod; \ + composer run-script --no-dev post-install-cmd; \ + chmod +x bin/console; \ + sync + +RUN php bin/console assets:install +RUN yarn install +RUN yarn run build +RUN yarn run ttag:po2json diff --git a/templates/base.html.twig b/templates/base.html.twig index 9d6eec5..881b698 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -12,7 +12,7 @@ - + @@ -21,11 +21,11 @@ - + - + Domain Watchdog {{ encore_entry_link_tags('app') }} From 628c65fd0bcf1c24981725aa74c29ab3feab591a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Mon, 12 Aug 2024 16:57:31 +0200 Subject: [PATCH 008/257] feat: logging validation link --- INSTALL.md | 10 +++++++++- src/Controller/RegistrationController.php | 8 +++++++- src/Security/EmailVerifier.php | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 055e261..888f083 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -45,7 +45,11 @@ git clone https://github.com/maelgangloff/domain-watchdog.git ```shell symfony server:start ``` -6. Don't forget to set up workers to process the [message queue](https://symfony.com/doc/current/messenger.html) +6. Build assets: + ```shell + php bin/console assets:install + ``` +7. Don't forget to set up workers to process the [message queue](https://symfony.com/doc/current/messenger.html) #### Frontend @@ -96,6 +100,10 @@ git pull origin master ```shell php bin/console cache:clear ``` +4. Build assets: + ```shell + php bin/console assets:install + ``` ### Frontend diff --git a/src/Controller/RegistrationController.php b/src/Controller/RegistrationController.php index 8b16124..1b44baf 100644 --- a/src/Controller/RegistrationController.php +++ b/src/Controller/RegistrationController.php @@ -82,7 +82,7 @@ class RegistrationController extends AbstractController 'username' => $user->getUserIdentifier(), ]); - $this->emailVerifier->sendEmailConfirmation('app_verify_email', $user, + $email = $this->emailVerifier->sendEmailConfirmation('app_verify_email', $user, (new TemplatedEmail()) ->from(new Address($this->mailerSenderEmail, $this->mailerSenderName)) ->to($user->getEmail()) @@ -91,6 +91,12 @@ class RegistrationController extends AbstractController ->htmlTemplate('emails/success/confirmation_email.html.twig') ); + $signedUrl = (string) $email->getContext()['signedUrl']; + $this->logger->notice('The validation link for user {username} is {signedUrl}', [ + 'username' => $user->getUserIdentifier(), + 'signedUrl' => $signedUrl, + ]); + return new Response(null, 201); } diff --git a/src/Security/EmailVerifier.php b/src/Security/EmailVerifier.php index 7d09bfb..233ac87 100644 --- a/src/Security/EmailVerifier.php +++ b/src/Security/EmailVerifier.php @@ -22,7 +22,7 @@ readonly class EmailVerifier /** * @throws TransportExceptionInterface */ - public function sendEmailConfirmation(string $verifyEmailRouteName, User $user, TemplatedEmail $email): void + public function sendEmailConfirmation(string $verifyEmailRouteName, User $user, TemplatedEmail $email): TemplatedEmail { $signatureComponents = $this->verifyEmailHelper->generateSignature( $verifyEmailRouteName, @@ -39,6 +39,8 @@ readonly class EmailVerifier $email->context($context); $this->mailer->send($email); + + return $email; } public function handleEmailConfirmation(Request $request, User $user): void From 582f2b4018933de53d5b9b05e6bab36762ebfec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Mon, 12 Aug 2024 17:08:39 +0200 Subject: [PATCH 009/257] docs: update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maël Gangloff --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index cd5097c..0410bf2 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,19 @@ Although the RDAP and WHOIS protocols allow you to obtain precise information ab perform a reverse search to discover a list of domain names associated with an entity. Additionally, accessing a detailed history of events (ownership changes, renewals, etc.) is not feasible with these protocols. +## Install +For more details on the installation procedure, please refer to [INSTALL.md](/INSTALL.md). This project is compatible with Docker. +1. Clone the GitHub repository +2. Build the Docker image locally + ```shell + docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache + ``` +3. Modify environment variables and add static files to customize your instance +4. Start the project in production environment + ```shell + docker compose -f compose.yaml -f compose.prod.yaml up + ``` + ## How it works? ### RDAP search From e3a0e0faff46bacd89452350e05d0dfe84ba0a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Mon, 12 Aug 2024 17:12:30 +0200 Subject: [PATCH 010/257] docs: update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maël Gangloff --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0410bf2..39ba9bf 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,13 @@ perform a reverse search to discover a list of domain names associated with an e detailed history of events (ownership changes, renewals, etc.) is not feasible with these protocols. ## Install -For more details on the installation procedure, please refer to [INSTALL.md](/INSTALL.md). This project is compatible with Docker. -1. Clone the GitHub repository + +> [!TIP] +> For more details on the installation procedure, please refer to [INSTALL.md](/INSTALL.md). + +### Docker Deployment + +1. Clone the repository 2. Build the Docker image locally ```shell docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache From 0095e26c222f54341a4d9978a6bfe60570fe668e Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 12 Aug 2024 22:08:15 +0200 Subject: [PATCH 011/257] fix: project name and desc --- CITATION.cff | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 9640114..81bf282 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -13,9 +13,9 @@ identifiers: - type: url value: >- https://github.com/maelgangloff/domain-watcher/releases - description: Release of scolengo-api + description: Release of domain watchdog repository-code: 'https://github.com/maelgangloff/domain-watchdog' -abstract: Unofficial Node.js API client of Skolengo EMS. +abstract: An app that utilizes RDAP to gather publicly accessible information about domain names, track their history, and automatically purchase them. keywords: - DOMAIN - RDAP From ded72c651ed82b6707b5934f35f8c533ecefa33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Mon, 12 Aug 2024 22:17:46 +0200 Subject: [PATCH 012/257] docs: update CITATION.cff --- CITATION.cff | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 81bf282..9df3d67 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -13,14 +13,14 @@ identifiers: - type: url value: >- https://github.com/maelgangloff/domain-watcher/releases - description: Release of domain watchdog + description: Release of domain-watchdog repository-code: 'https://github.com/maelgangloff/domain-watchdog' -abstract: An app that utilizes RDAP to gather publicly accessible information about domain names, track their history, and automatically purchase them. +abstract: An app that utilizes RDAP to gather publicly accessible information about domain names, track their history, and automatically purchase them keywords: - DOMAIN - RDAP - WHOIS license: AGPL-3.0-or-later -version: 0.0.1 -date-released: '2024-07-11' -license-url: 'https://github.com/maelgangloff/domain-watchdog/blob/master/LICENSE' \ No newline at end of file +version: 0.1.0 +date-released: '2024-08-08' +license-url: 'https://github.com/maelgangloff/domain-watchdog/blob/master/LICENSE' From 884fbaa5b946bf1d34e0def7451d1c9baf6bcc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 08:50:14 +0000 Subject: [PATCH 013/257] Added translation using Weblate (German) --- translations/de.po | 587 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 587 insertions(+) create mode 100644 translations/de.po diff --git a/translations/de.po b/translations/de.po new file mode 100644 index 0000000..20d2d72 --- /dev/null +++ b/translations/de.po @@ -0,0 +1,587 @@ +msgid "" +msgstr "" +"Language: de\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: assets/components/LoginForm.tsx:51 +#: assets/components/RegisterForm.tsx:38 +msgid "Email address" +msgstr "" + +#: assets/components/LoginForm.tsx:53 +#: assets/components/LoginForm.tsx:61 +#: assets/components/RegisterForm.tsx:40 +#: assets/components/RegisterForm.tsx:48 +#: assets/components/search/DomainSearchBar.tsx:23 +#: assets/components/tracking/ConnectorForm.tsx:43 +#: assets/components/tracking/ConnectorForm.tsx:69 +#: assets/components/tracking/ConnectorForm.tsx:77 +#: assets/components/tracking/ConnectorForm.tsx:84 +#: assets/components/tracking/ConnectorForm.tsx:92 +#: assets/components/tracking/ConnectorForm.tsx:122 +#: assets/components/tracking/ConnectorForm.tsx:142 +#: assets/components/tracking/ConnectorForm.tsx:156 +#: assets/components/tracking/ConnectorForm.tsx:165 +#: assets/components/tracking/WatchlistForm.tsx:103 +msgid "Required" +msgstr "" + +#: assets/components/LoginForm.tsx:59 +#: assets/components/RegisterForm.tsx:46 +msgid "Password" +msgstr "" + +#: assets/components/LoginForm.tsx:69 +msgid "Submit" +msgstr "" + +#: assets/components/LoginForm.tsx:74 +msgid "Log in with SSO" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:25 +msgid "Registration" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:26 +msgid "Reregistration" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:27 +msgid "Last changed" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:28 +msgid "Expiration" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:29 +msgid "Deletion" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:30 +msgid "Reinstantiation" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:31 +msgid "Transfer" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:32 +msgid "Locked" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:33 +msgid "Unlocked" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:34 +msgid "Registrar expiration" +msgstr "" + +#: assets/components/search/EventTimeline.tsx:35 +msgid "ENUM validation expiration" +msgstr "" + +#: assets/components/search/DomainSearchBar.tsx:26 +#: assets/components/tracking/WatchlistForm.tsx:106 +msgid "This domain name does not appear to be valid" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:10 +msgid "Registrant" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:11 +msgid "Technical" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:12 +msgid "Administrative" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:13 +msgid "Abuse" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:14 +msgid "Billing" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:15 +msgid "Registrar" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:16 +msgid "Reseller" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:17 +msgid "Sponsor" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:18 +msgid "Proxy" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:19 +msgid "Notifications" +msgstr "" + +#: assets/components/search/EntitiesList.tsx:20 +msgid "Noc" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:60 +msgid "Name" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:71 +msgid "Watchlist Name" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:72 +msgid "Naming the Watchlist makes it easier to find in the list below." +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:83 +msgid "At least one domain name" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:94 +#: assets/components/tracking/WatchlistsList.tsx:21 +msgid "Domain names" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:112 +msgid "Domain name" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:129 +msgid "Add a Domain name" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:136 +#: assets/components/tracking/WatchlistsList.tsx:25 +msgid "Tracked events" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:138 +msgid "At least one trigger" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:160 +#: assets/components/tracking/WatchlistForm.tsx:174 +msgid "Connector" +msgstr "" + +#: assets/components/tracking/WatchlistForm.tsx:170 +msgid "" +"Please make sure the connector information is valid to purchase a domain " +"that may be available soon." +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:176 +#: assets/components/tracking/WatchlistForm.tsx:186 +msgid "Create" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:179 +#: assets/components/tracking/WatchlistForm.tsx:189 +msgid "Reset" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:40 +msgid "Provider" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:47 +msgid "Please select a Provider" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:75 +msgid "OVH Endpoint" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:82 +msgid "OVH subsidiary" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:90 +msgid "OVH pricing mode" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:95 +msgid "Confirm pricing mode" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:96 +msgid "" +"Are you sure about this setting? This may result in additional charges from " +"the API Provider" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:120 +msgid "Personal Access Token (PAT)" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:126 +msgid "Organization sharing ID" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:129 +msgid "It indicates the organization that will pay for the ordered product" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:140 +msgid "API Terms of Service" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:148 +msgid "" +"I have read and accepted the conditions of use of the Provider API, " +"accessible from this hyperlink" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:154 +msgid "Legal age" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:159 +msgid "I am of the minimum age required to consent to these conditions" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:163 +msgid "Withdrawal period" +msgstr "" + +#: assets/components/tracking/ConnectorForm.tsx:168 +msgid "" +"I waive my right of withdrawal regarding the purchase of domain names via " +"the Provider's API" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:40 +msgid "This Watchlist is not linked to a Connector." +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:43 +msgid "Watchlist" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:51 +msgid "Export events to iCalendar format" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:54 +#: assets/components/tracking/WatchlistsList.tsx:60 +msgid "Delete the Watchlist" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:55 +msgid "Are you sure to delete this Watchlist?" +msgstr "" + +#: assets/components/tracking/ConnectorsList.tsx:25 +#: assets/components/tracking/WatchlistsList.tsx:57 +msgid "Yes" +msgstr "" + +#: assets/components/tracking/ConnectorsList.tsx:26 +#: assets/components/tracking/WatchlistsList.tsx:58 +msgid "No" +msgstr "" + +#: assets/components/tracking/ConnectorsList.tsx:19 +#, javascript-format +msgid "Connector ${ connector.provider }" +msgstr "" + +#: assets/components/tracking/ConnectorsList.tsx:22 +msgid "Delete the Connector" +msgstr "" + +#: assets/components/tracking/ConnectorsList.tsx:23 +msgid "Are you sure to delete this Connector?" +msgstr "" + +#: assets/components/Sider.tsx:29 +msgid "Home" +msgstr "" + +#: assets/components/Sider.tsx:35 +msgid "Search" +msgstr "" + +#: assets/components/Sider.tsx:41 +msgid "Domain" +msgstr "" + +#: assets/components/Sider.tsx:42 +msgid "Domain Finder" +msgstr "" + +#: assets/components/Sider.tsx:49 +#: assets/pages/info/TldPage.tsx:79 +msgid "TLD" +msgstr "" + +#: assets/components/Sider.tsx:50 +msgid "TLD list" +msgstr "" + +#: assets/components/Sider.tsx:57 +msgid "Entity" +msgstr "" + +#: assets/components/Sider.tsx:58 +msgid "Entity Finder" +msgstr "" + +#: assets/components/Sider.tsx:65 +msgid "Nameserver" +msgstr "" + +#: assets/components/Sider.tsx:66 +msgid "Nameserver Finder" +msgstr "" + +#: assets/components/Sider.tsx:73 +msgid "Tracking" +msgstr "" + +#: assets/components/Sider.tsx:79 +msgid "My Watchlists" +msgstr "" + +#: assets/components/Sider.tsx:86 +msgid "My Connectors" +msgstr "" + +#: assets/components/Sider.tsx:95 +msgid "Statistics" +msgstr "" + +#: assets/components/Sider.tsx:105 +#: assets/pages/watchdog/UserPage.tsx:16 +msgid "My Account" +msgstr "" + +#: assets/components/Sider.tsx:111 +msgid "Log out" +msgstr "" + +#: assets/components/Sider.tsx:119 +#: assets/pages/LoginPage.tsx:30 +#: assets/pages/LoginPage.tsx:38 +msgid "Log in" +msgstr "" + +#: assets/components/RegisterForm.tsx:55 +#: assets/pages/LoginPage.tsx:30 +msgid "Register" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:21 +msgid "Found !" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:29 +msgid "Domain finder" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:50 +msgid "EPP Status Codes" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:60 +msgid "Timeline" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:65 +msgid "Entities" +msgstr "" + +#: assets/pages/search/DomainSearchPage.tsx:73 +msgid "" +"Although the domain exists in my database, it has been deleted from the " +"WHOIS by its registrar." +msgstr "" + +#: assets/pages/info/TldPage.tsx:85 +msgid "Flag" +msgstr "" + +#: assets/pages/info/TldPage.tsx:88 +msgid "Country" +msgstr "" + +#: assets/pages/info/TldPage.tsx:93 +msgid "Registry Operator" +msgstr "" + +#: assets/pages/info/TldPage.tsx:120 +msgid "This page presents all active TLDs in the root zone database." +msgstr "" + +#: assets/pages/info/TldPage.tsx:123 +msgid "" +"IANA provides the list of currently active TLDs, regardless of their type, " +"and ICANN provides the list of gTLDs.\n" +"In most cases, the two-letter ccTLD assigned to a country is made in " +"accordance with the ISO 3166-1 standard.\n" +"This data is updated every month. Three HTTP requests are needed for the " +"complete update of TLDs in Domain Watchdog (two requests to IANA and one to " +"ICANN).\n" +"At the same time, the list of root RDAP servers is updated." +msgstr "" + +#: assets/pages/info/TldPage.tsx:134 +msgid "Sponsored Top-Level-Domains" +msgstr "" + +#: assets/pages/info/TldPage.tsx:136 +msgid "" +"Top-level domains sponsored by specific organizations that set rules for " +"registration and use, often related to particular interest groups or " +"industries." +msgstr "" + +#: assets/pages/info/TldPage.tsx:143 +msgid "Generic Top-Level-Domains" +msgstr "" + +#: assets/pages/info/TldPage.tsx:145 +msgid "" +"Generic top-level domains open to everyone, not restricted by specific " +"criteria, representing various themes or industries." +msgstr "" + +#: assets/pages/info/TldPage.tsx:152 +msgid "Brand Generic Top-Level-Domains" +msgstr "" + +#: assets/pages/info/TldPage.tsx:154 +msgid "" +"Generic top-level domains associated with specific brands, allowing " +"companies to use their own brand names as domains." +msgstr "" + +#: assets/pages/info/TldPage.tsx:161 +msgid "Country-Code Top-Level-Domains" +msgstr "" + +#: assets/pages/info/TldPage.tsx:163 +msgid "" +"Top-level domains based on country codes, identifying websites according to " +"their country of origin." +msgstr "" + +#: assets/pages/watchdog/UserPage.tsx:18 +msgid "Username" +msgstr "" + +#: assets/pages/watchdog/UserPage.tsx:21 +msgid "Roles" +msgstr "" + +#: assets/pages/tracking/ConnectorsPage.tsx:19 +msgid "Connector created !" +msgstr "" + +#: assets/pages/tracking/ConnectorsPage.tsx:38 +msgid "Create a Connector" +msgstr "" + +#: assets/pages/tracking/WatchlistPage.tsx:47 +msgid "Watchlist created !" +msgstr "" + +#: assets/pages/tracking/WatchlistPage.tsx:70 +msgid "Create a Watchlist" +msgstr "" + +#: assets/pages/NotFoundPage.tsx:10 +msgid "Sorry, the page you visited does not exist." +msgstr "" + +#: assets/pages/LoginPage.tsx:38 +msgid "Create an account" +msgstr "" + +#: assets/utils/providers/index.tsx:11 +msgid "" +"Retrieve a set of tokens from your customer account on the Provider's " +"website" +msgstr "" + +#: assets/utils/providers/index.tsx:16 +msgid "" +"Retrieve a Personal Access Token from your customer account on the " +"Provider's website" +msgstr "" + +#: assets/utils/providers/ovh.tsx:5 +msgid "Application key" +msgstr "" + +#: assets/utils/providers/ovh.tsx:6 +msgid "Application secret" +msgstr "" + +#: assets/utils/providers/ovh.tsx:7 +msgid "Consumer key" +msgstr "" + +#: assets/utils/providers/ovh.tsx:12 +msgid "European Region" +msgstr "" + +#: assets/utils/providers/ovh.tsx:19 +msgid "Europe" +msgstr "" + +#: assets/utils/providers/ovh.tsx:22 +msgid "The domain is free and at the standard price" +msgstr "" + +#: assets/utils/providers/ovh.tsx:25 +msgid "" +"The domain is free but can be premium. Its price varies from one domain to " +"another" +msgstr "" + +#: assets/utils/index.ts:19 +#, javascript-format +msgid "Please retry after ${ duration } seconds" +msgstr "" + +#: assets/utils/index.ts:23 +#: assets/utils/index.ts:26 +msgid "An error occurred" +msgstr "" + +#: assets/App.tsx:101 +msgid "TOS" +msgstr "" + +#: assets/App.tsx:102 +msgid "Privacy Policy" +msgstr "" + +#: assets/App.tsx:103 +msgid "FAQ" +msgstr "" + +#: assets/App.tsx:105 +msgid "Documentation" +msgstr "" + +#: assets/App.tsx:108 +#, javascript-format +msgid "" +"${ ProjectLink } is an open source project distributed under the ${ " +"LicenseLink } license." +msgstr "" From da671c2e7a0c5f29aefe5753eba1650496072eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 09:00:43 +0000 Subject: [PATCH 014/257] Translated using Weblate (German) Currently translated at 100.0% (128 of 128 strings) --- translations/de.po | 269 ++++++++++++++++++++++++++------------------- 1 file changed, 158 insertions(+), 111 deletions(-) diff --git a/translations/de.po b/translations/de.po index 20d2d72..503e537 100644 --- a/translations/de.po +++ b/translations/de.po @@ -1,14 +1,19 @@ msgid "" msgstr "" +"PO-Revision-Date: 2024-08-13 10:02+0000\n" +"Last-Translator: Maël Gangloff \n" +"Language-Team: German \n" "Language: de\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" #: assets/components/LoginForm.tsx:51 #: assets/components/RegisterForm.tsx:38 msgid "Email address" -msgstr "" +msgstr "E-Mail-Adresse" #: assets/components/LoginForm.tsx:53 #: assets/components/LoginForm.tsx:61 @@ -26,405 +31,421 @@ msgstr "" #: assets/components/tracking/ConnectorForm.tsx:165 #: assets/components/tracking/WatchlistForm.tsx:103 msgid "Required" -msgstr "" +msgstr "Erforderlich" #: assets/components/LoginForm.tsx:59 #: assets/components/RegisterForm.tsx:46 msgid "Password" -msgstr "" +msgstr "Passwort" #: assets/components/LoginForm.tsx:69 msgid "Submit" -msgstr "" +msgstr "Senden" #: assets/components/LoginForm.tsx:74 msgid "Log in with SSO" -msgstr "" +msgstr "Mit SSO anmelden" #: assets/components/search/EventTimeline.tsx:25 msgid "Registration" -msgstr "" +msgstr "Registrierung" #: assets/components/search/EventTimeline.tsx:26 msgid "Reregistration" -msgstr "" +msgstr "Neuregistrierung" #: assets/components/search/EventTimeline.tsx:27 msgid "Last changed" -msgstr "" +msgstr "Letzte Änderung" #: assets/components/search/EventTimeline.tsx:28 msgid "Expiration" -msgstr "" +msgstr "Ablauf" #: assets/components/search/EventTimeline.tsx:29 msgid "Deletion" -msgstr "" +msgstr "Löschung" #: assets/components/search/EventTimeline.tsx:30 msgid "Reinstantiation" -msgstr "" +msgstr "Neuinstanzierung" #: assets/components/search/EventTimeline.tsx:31 msgid "Transfer" -msgstr "" +msgstr "Übertragung" #: assets/components/search/EventTimeline.tsx:32 msgid "Locked" -msgstr "" +msgstr "Gesperrt" #: assets/components/search/EventTimeline.tsx:33 msgid "Unlocked" -msgstr "" +msgstr "Ungesperrt" #: assets/components/search/EventTimeline.tsx:34 msgid "Registrar expiration" -msgstr "" +msgstr "Ablauf des Registrars" #: assets/components/search/EventTimeline.tsx:35 msgid "ENUM validation expiration" -msgstr "" +msgstr "Ablauf der ENUM-Validierung" #: assets/components/search/DomainSearchBar.tsx:26 #: assets/components/tracking/WatchlistForm.tsx:106 msgid "This domain name does not appear to be valid" -msgstr "" +msgstr "Dieser Domainname scheint nicht gültig zu sein" #: assets/components/search/EntitiesList.tsx:10 msgid "Registrant" -msgstr "" +msgstr "Anmelder" #: assets/components/search/EntitiesList.tsx:11 msgid "Technical" -msgstr "" +msgstr "Technischer" #: assets/components/search/EntitiesList.tsx:12 msgid "Administrative" -msgstr "" +msgstr "Verwaltung" #: assets/components/search/EntitiesList.tsx:13 msgid "Abuse" -msgstr "" +msgstr "Missbrauch" #: assets/components/search/EntitiesList.tsx:14 msgid "Billing" -msgstr "" +msgstr "Rechnungsstellung" #: assets/components/search/EntitiesList.tsx:15 msgid "Registrar" -msgstr "" +msgstr "Registrierungsstelle" #: assets/components/search/EntitiesList.tsx:16 msgid "Reseller" -msgstr "" +msgstr "Wiederverkäufer" #: assets/components/search/EntitiesList.tsx:17 msgid "Sponsor" -msgstr "" +msgstr "Sponsor" #: assets/components/search/EntitiesList.tsx:18 msgid "Proxy" -msgstr "" +msgstr "Proxy" #: assets/components/search/EntitiesList.tsx:19 msgid "Notifications" -msgstr "" +msgstr "Benachrichtigungen" #: assets/components/search/EntitiesList.tsx:20 msgid "Noc" -msgstr "" +msgstr "Noc" #: assets/components/tracking/WatchlistForm.tsx:60 msgid "Name" -msgstr "" +msgstr "Name" #: assets/components/tracking/WatchlistForm.tsx:71 msgid "Watchlist Name" -msgstr "" +msgstr "Name der Watchlist" #: assets/components/tracking/WatchlistForm.tsx:72 msgid "Naming the Watchlist makes it easier to find in the list below." msgstr "" +"Durch die Benennung der Watchlist ist sie in der Liste weiter unten leichter " +"zu finden." #: assets/components/tracking/WatchlistForm.tsx:83 msgid "At least one domain name" -msgstr "" +msgstr "Mindestens ein Domänenname" #: assets/components/tracking/WatchlistForm.tsx:94 #: assets/components/tracking/WatchlistsList.tsx:21 msgid "Domain names" -msgstr "" +msgstr "Domänennamen" #: assets/components/tracking/WatchlistForm.tsx:112 msgid "Domain name" -msgstr "" +msgstr "Domänenname" #: assets/components/tracking/WatchlistForm.tsx:129 msgid "Add a Domain name" -msgstr "" +msgstr "Einen Domänennamen hinzufügen" #: assets/components/tracking/WatchlistForm.tsx:136 #: assets/components/tracking/WatchlistsList.tsx:25 msgid "Tracked events" -msgstr "" +msgstr "Verfolgte Ereignisse" #: assets/components/tracking/WatchlistForm.tsx:138 msgid "At least one trigger" -msgstr "" +msgstr "Mindestens ein Auslöser" #: assets/components/tracking/WatchlistForm.tsx:160 #: assets/components/tracking/WatchlistForm.tsx:174 msgid "Connector" -msgstr "" +msgstr "Konnektor" #: assets/components/tracking/WatchlistForm.tsx:170 msgid "" "Please make sure the connector information is valid to purchase a domain " "that may be available soon." msgstr "" +"Bitte stellen Sie sicher, dass die Connector-Informationen gültig sind, um " +"eine Domäne zu erwerben, die möglicherweise bald verfügbar ist." #: assets/components/tracking/ConnectorForm.tsx:176 #: assets/components/tracking/WatchlistForm.tsx:186 msgid "Create" -msgstr "" +msgstr "Erstellen" #: assets/components/tracking/ConnectorForm.tsx:179 #: assets/components/tracking/WatchlistForm.tsx:189 msgid "Reset" -msgstr "" +msgstr "Zurücksetzen" #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" -msgstr "" +msgstr "Anbieter" #: assets/components/tracking/ConnectorForm.tsx:47 msgid "Please select a Provider" -msgstr "" +msgstr "Bitte wählen Sie einen Anbieter" #: assets/components/tracking/ConnectorForm.tsx:75 msgid "OVH Endpoint" -msgstr "" +msgstr "OVH Endpunkt" #: assets/components/tracking/ConnectorForm.tsx:82 msgid "OVH subsidiary" -msgstr "" +msgstr "OVH-Tochter" #: assets/components/tracking/ConnectorForm.tsx:90 msgid "OVH pricing mode" -msgstr "" +msgstr "OVH Preismodell" #: assets/components/tracking/ConnectorForm.tsx:95 msgid "Confirm pricing mode" -msgstr "" +msgstr "Preismodus bestätigen" #: assets/components/tracking/ConnectorForm.tsx:96 msgid "" "Are you sure about this setting? This may result in additional charges from " "the API Provider" msgstr "" +"Sind Sie sich bei dieser Einstellung sicher? Dies kann zu zusätzlichen " +"Gebühren durch den API-Anbieter führen" #: assets/components/tracking/ConnectorForm.tsx:120 msgid "Personal Access Token (PAT)" -msgstr "" +msgstr "Persönlicher Zugriffstoken (PAT)" #: assets/components/tracking/ConnectorForm.tsx:126 msgid "Organization sharing ID" -msgstr "" +msgstr "Freigabe-ID der Organisation" #: assets/components/tracking/ConnectorForm.tsx:129 msgid "It indicates the organization that will pay for the ordered product" -msgstr "" +msgstr "Es gibt die Organisation an, die für das bestellte Produkt bezahlt" #: assets/components/tracking/ConnectorForm.tsx:140 msgid "API Terms of Service" -msgstr "" +msgstr "API-Nutzungsbedingungen" #: assets/components/tracking/ConnectorForm.tsx:148 msgid "" "I have read and accepted the conditions of use of the Provider API, " "accessible from this hyperlink" msgstr "" +"Ich habe die Nutzungsbedingungen der Provider-API gelesen und akzeptiert, " +"die über diesen Hyperlink zugänglich sind" #: assets/components/tracking/ConnectorForm.tsx:154 msgid "Legal age" -msgstr "" +msgstr "Volljährigkeit" #: assets/components/tracking/ConnectorForm.tsx:159 msgid "I am of the minimum age required to consent to these conditions" msgstr "" +"Ich habe das erforderliche Mindestalter erreicht, um diesen Bedingungen " +"zuzustimmen" #: assets/components/tracking/ConnectorForm.tsx:163 msgid "Withdrawal period" -msgstr "" +msgstr "Rücktrittsfrist" #: assets/components/tracking/ConnectorForm.tsx:168 msgid "" "I waive my right of withdrawal regarding the purchase of domain names via " "the Provider's API" msgstr "" +"Ich verzichte auf mein Widerrufsrecht beim Kauf von Domainnamen über die API " +"des Anbieters" #: assets/components/tracking/WatchlistsList.tsx:40 msgid "This Watchlist is not linked to a Connector." -msgstr "" +msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." #: assets/components/tracking/WatchlistsList.tsx:43 msgid "Watchlist" -msgstr "" +msgstr "Watchlist" #: assets/components/tracking/WatchlistsList.tsx:51 msgid "Export events to iCalendar format" -msgstr "" +msgstr "Ereignisse in das iCalendar-Format exportieren" #: assets/components/tracking/WatchlistsList.tsx:54 #: assets/components/tracking/WatchlistsList.tsx:60 msgid "Delete the Watchlist" -msgstr "" +msgstr "Löschen der Watchlist" #: assets/components/tracking/WatchlistsList.tsx:55 msgid "Are you sure to delete this Watchlist?" -msgstr "" +msgstr "Möchten Sie diese Watchlist wirklich löschen?" #: assets/components/tracking/ConnectorsList.tsx:25 #: assets/components/tracking/WatchlistsList.tsx:57 msgid "Yes" -msgstr "" +msgstr "Ja" #: assets/components/tracking/ConnectorsList.tsx:26 #: assets/components/tracking/WatchlistsList.tsx:58 msgid "No" -msgstr "" +msgstr "Nein" #: assets/components/tracking/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" -msgstr "" +msgstr "Konnektor ${ connector.provider }" #: assets/components/tracking/ConnectorsList.tsx:22 msgid "Delete the Connector" -msgstr "" +msgstr "Löschen des Connectors" #: assets/components/tracking/ConnectorsList.tsx:23 msgid "Are you sure to delete this Connector?" -msgstr "" +msgstr "Möchten Sie diesen Connector wirklich löschen?" #: assets/components/Sider.tsx:29 msgid "Home" -msgstr "" +msgstr "Startseite" #: assets/components/Sider.tsx:35 msgid "Search" -msgstr "" +msgstr "Suchen" #: assets/components/Sider.tsx:41 msgid "Domain" -msgstr "" +msgstr "Domain" #: assets/components/Sider.tsx:42 msgid "Domain Finder" -msgstr "" +msgstr "Domänenfinder" #: assets/components/Sider.tsx:49 #: assets/pages/info/TldPage.tsx:79 msgid "TLD" -msgstr "" +msgstr "TLD" #: assets/components/Sider.tsx:50 msgid "TLD list" -msgstr "" +msgstr "TLD-Liste" #: assets/components/Sider.tsx:57 msgid "Entity" -msgstr "" +msgstr "Entität" #: assets/components/Sider.tsx:58 msgid "Entity Finder" -msgstr "" +msgstr "Entitätsfinder" #: assets/components/Sider.tsx:65 msgid "Nameserver" -msgstr "" +msgstr "Nameserver" #: assets/components/Sider.tsx:66 msgid "Nameserver Finder" -msgstr "" +msgstr "Nameserver-Finder" #: assets/components/Sider.tsx:73 msgid "Tracking" -msgstr "" +msgstr "Nachverfolgung" #: assets/components/Sider.tsx:79 msgid "My Watchlists" -msgstr "" +msgstr "Meine Watchlists" #: assets/components/Sider.tsx:86 msgid "My Connectors" -msgstr "" +msgstr "Meine Konnektoren" #: assets/components/Sider.tsx:95 msgid "Statistics" -msgstr "" +msgstr "Statistiken" #: assets/components/Sider.tsx:105 #: assets/pages/watchdog/UserPage.tsx:16 msgid "My Account" -msgstr "" +msgstr "Mein Konto" #: assets/components/Sider.tsx:111 msgid "Log out" -msgstr "" +msgstr "Abmelden" #: assets/components/Sider.tsx:119 #: assets/pages/LoginPage.tsx:30 #: assets/pages/LoginPage.tsx:38 msgid "Log in" -msgstr "" +msgstr "Anmelden" #: assets/components/RegisterForm.tsx:55 #: assets/pages/LoginPage.tsx:30 msgid "Register" -msgstr "" +msgstr "Registrieren" #: assets/pages/search/DomainSearchPage.tsx:21 msgid "Found !" -msgstr "" +msgstr "Gefunden !" #: assets/pages/search/DomainSearchPage.tsx:29 msgid "Domain finder" -msgstr "" +msgstr "Domänenfinder" #: assets/pages/search/DomainSearchPage.tsx:50 msgid "EPP Status Codes" -msgstr "" +msgstr "EPP-Statuscodes" #: assets/pages/search/DomainSearchPage.tsx:60 msgid "Timeline" -msgstr "" +msgstr "Zeitleiste" #: assets/pages/search/DomainSearchPage.tsx:65 msgid "Entities" -msgstr "" +msgstr "Entitäten" #: assets/pages/search/DomainSearchPage.tsx:73 msgid "" "Although the domain exists in my database, it has been deleted from the " "WHOIS by its registrar." msgstr "" +"Obwohl die Domain in meiner Datenbank vorhanden ist, wurde sie von ihrem " +"Registrar aus dem WHOIS gelöscht." #: assets/pages/info/TldPage.tsx:85 msgid "Flag" -msgstr "" +msgstr "Landesflagge" #: assets/pages/info/TldPage.tsx:88 msgid "Country" -msgstr "" +msgstr "Land" #: assets/pages/info/TldPage.tsx:93 msgid "Registry Operator" -msgstr "" +msgstr "Registrierungsbetreiber" #: assets/pages/info/TldPage.tsx:120 msgid "This page presents all active TLDs in the root zone database." msgstr "" +"Auf dieser Seite werden alle aktiven TLDs in der Root-Zone-Datenbank " +"angezeigt." #: assets/pages/info/TldPage.tsx:123 msgid "" @@ -437,10 +458,18 @@ msgid "" "ICANN).\n" "At the same time, the list of root RDAP servers is updated." msgstr "" +"IANA stellt die Liste der derzeit aktiven TLDs unabhängig von ihrem Typ " +"bereit und ICANN stellt die Liste der gTLDs bereit.\n" +" In den meisten Fällen erfolgt die Zuweisung der zweistelligen ccTLD an ein " +"Land gemäß der Norm ISO 3166-1.\n" +" Diese Daten werden jeden Monat aktualisiert. Für die vollständige " +"Aktualisierung der TLDs in Domain Watchdog sind drei HTTP-Anfragen " +"erforderlich (zwei Anfragen an IANA und eine an ICANN).\n" +" Gleichzeitig wird die Liste der Root-RDAP-Server aktualisiert." #: assets/pages/info/TldPage.tsx:134 msgid "Sponsored Top-Level-Domains" -msgstr "" +msgstr "Gesponserte Top-Level-Domains" #: assets/pages/info/TldPage.tsx:136 msgid "" @@ -448,136 +477,152 @@ msgid "" "registration and use, often related to particular interest groups or " "industries." msgstr "" +"Top-Level-Domains werden von bestimmten Organisationen gesponsert, die " +"Regeln für die Registrierung und Nutzung festlegen und oft mit bestimmten " +"Interessengruppen oder Branchen in Zusammenhang stehen." #: assets/pages/info/TldPage.tsx:143 msgid "Generic Top-Level-Domains" -msgstr "" +msgstr "Generische Top-Level-Domains" #: assets/pages/info/TldPage.tsx:145 msgid "" "Generic top-level domains open to everyone, not restricted by specific " "criteria, representing various themes or industries." msgstr "" +"Generische Top-Level-Domains, die für jeden offen sind, nicht durch " +"bestimmte Kriterien eingeschränkt sind und verschiedene Themen oder Branchen " +"repräsentieren." #: assets/pages/info/TldPage.tsx:152 msgid "Brand Generic Top-Level-Domains" -msgstr "" +msgstr "Markengenerische Top-Level-Domains" #: assets/pages/info/TldPage.tsx:154 msgid "" "Generic top-level domains associated with specific brands, allowing " "companies to use their own brand names as domains." msgstr "" +"Generische Top-Level-Domains sind mit bestimmten Marken verknüpft und " +"ermöglichen Unternehmen die Verwendung ihrer eigenen Markennamen als Domains." #: assets/pages/info/TldPage.tsx:161 msgid "Country-Code Top-Level-Domains" -msgstr "" +msgstr "Länderspezifische Top-Level-Domains" #: assets/pages/info/TldPage.tsx:163 msgid "" "Top-level domains based on country codes, identifying websites according to " "their country of origin." msgstr "" +"Top-Level-Domains basieren auf Ländercodes und identifizieren Websites " +"entsprechend ihrem Herkunftsland." #: assets/pages/watchdog/UserPage.tsx:18 msgid "Username" -msgstr "" +msgstr "Benutzername" #: assets/pages/watchdog/UserPage.tsx:21 msgid "Roles" -msgstr "" +msgstr "Rollen" #: assets/pages/tracking/ConnectorsPage.tsx:19 msgid "Connector created !" -msgstr "" +msgstr "Connector erstellt!" #: assets/pages/tracking/ConnectorsPage.tsx:38 msgid "Create a Connector" -msgstr "" +msgstr "Erstellen eines Connectors" #: assets/pages/tracking/WatchlistPage.tsx:47 msgid "Watchlist created !" -msgstr "" +msgstr "Watchlist erstellt !" #: assets/pages/tracking/WatchlistPage.tsx:70 msgid "Create a Watchlist" -msgstr "" +msgstr "Erstellen Sie eine Watchlist" #: assets/pages/NotFoundPage.tsx:10 msgid "Sorry, the page you visited does not exist." -msgstr "" +msgstr "Es tut uns leid, die von Ihnen besuchte Seite existiert nicht." #: assets/pages/LoginPage.tsx:38 msgid "Create an account" -msgstr "" +msgstr "Ein Konto erstellen" #: assets/utils/providers/index.tsx:11 msgid "" "Retrieve a set of tokens from your customer account on the Provider's " "website" msgstr "" +"Abrufen eines Token-Satzes aus Ihrem Kundenkonto auf der Website des " +"Anbieters" #: assets/utils/providers/index.tsx:16 msgid "" "Retrieve a Personal Access Token from your customer account on the " "Provider's website" msgstr "" +"Abrufen eines persönlichen Zugriffstokens aus Ihrem Kundenkonto auf der " +"Website des Anbieters" #: assets/utils/providers/ovh.tsx:5 msgid "Application key" -msgstr "" +msgstr "Anwendungsschlüssel" #: assets/utils/providers/ovh.tsx:6 msgid "Application secret" -msgstr "" +msgstr "Geheimer Schlüssel der Anwendung" #: assets/utils/providers/ovh.tsx:7 msgid "Consumer key" -msgstr "" +msgstr "Verbraucherschlüssel" #: assets/utils/providers/ovh.tsx:12 msgid "European Region" -msgstr "" +msgstr "Europäische Region" #: assets/utils/providers/ovh.tsx:19 msgid "Europe" -msgstr "" +msgstr "Europa" #: assets/utils/providers/ovh.tsx:22 msgid "The domain is free and at the standard price" -msgstr "" +msgstr "Die Domain ist kostenlos und zum Standardpreis" #: assets/utils/providers/ovh.tsx:25 msgid "" "The domain is free but can be premium. Its price varies from one domain to " "another" msgstr "" +"Die Domain ist kostenlos, kann aber Premium sein. Der Preis variiert von " +"einer Domain zur anderen" #: assets/utils/index.ts:19 #, javascript-format msgid "Please retry after ${ duration } seconds" -msgstr "" +msgstr "Bitte versuchen Sie es nach ${ duration } Sekunden erneut" #: assets/utils/index.ts:23 #: assets/utils/index.ts:26 msgid "An error occurred" -msgstr "" +msgstr "Es ist ein Fehler aufgetreten" #: assets/App.tsx:101 msgid "TOS" -msgstr "" +msgstr "Nutzungsbedingungen" #: assets/App.tsx:102 msgid "Privacy Policy" -msgstr "" +msgstr "Datenschutzrichtlinie" #: assets/App.tsx:103 msgid "FAQ" -msgstr "" +msgstr "Häufig gestellte Fragen" #: assets/App.tsx:105 msgid "Documentation" -msgstr "" +msgstr "Dokumentation" #: assets/App.tsx:108 #, javascript-format @@ -585,3 +630,5 @@ msgid "" "${ ProjectLink } is an open source project distributed under the ${ " "LicenseLink } license." msgstr "" +"${ ProjectLink } ist ein Open-Source-Projekt, das unter der ${ LicenseLink }-" +"Lizenz vertrieben wird." From de1274bddf96ad86ac546a9f79f43335ce8f5505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 10:19:59 +0000 Subject: [PATCH 015/257] Translated using Weblate (German) Currently translated at 100.0% (128 of 128 strings) --- translations/de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/de.po b/translations/de.po index 503e537..ccd745e 100644 --- a/translations/de.po +++ b/translations/de.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-13 10:02+0000\n" +"PO-Revision-Date: 2024-08-13 10:20+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: German \n" @@ -216,7 +216,7 @@ msgstr "OVH Endpunkt" #: assets/components/tracking/ConnectorForm.tsx:82 msgid "OVH subsidiary" -msgstr "OVH-Tochter" +msgstr "OVH-Tochtergesellschaft" #: assets/components/tracking/ConnectorForm.tsx:90 msgid "OVH pricing mode" From fc1138810351b3e838c9faecf960b43dcd543085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 13:37:34 +0200 Subject: [PATCH 016/257] chore: less RUN in Dockerfile --- Dockerfile | 11 +++++++---- compose.yaml | 3 --- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 79e1791..1ef1328 100644 --- a/Dockerfile +++ b/Dockerfile @@ -97,7 +97,10 @@ RUN set -eux; \ chmod +x bin/console; \ sync -RUN php bin/console assets:install -RUN yarn install -RUN yarn run build -RUN yarn run ttag:po2json + +RUN set -eux; \ + php bin/console assets:install; \ + yarn install; \ + yarn run build; \ + yarn run ttag:po2json; \ + sync diff --git a/compose.yaml b/compose.yaml index 2fef85a..564654c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -51,6 +51,3 @@ volumes: ###> doctrine/doctrine-bundle ### database_data: ###< doctrine/doctrine-bundle ### - -networks: - dw-net: \ No newline at end of file From 701dd7970307a55aa53f29444698f1e29c16e56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 14:19:30 +0200 Subject: [PATCH 017/257] ci: add publish.yml workflow --- .github/workflows/publish.yml | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..9660e6f --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,56 @@ +name: Publish Docker image + +on: + release: + types: [ published ] + +jobs: + push_to_registries: + name: Push Docker image to multiple registries + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + attestations: write + id-token: write + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: | + maelgangloff/domain-watchdog + ghcr.io/${{ github.repository }} + + - name: Build and push Docker images + id: push + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: . + target: frankenphp_prod + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v1 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true From 3048d6499b17ab33ff3193e6722018c19041b0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 14:28:42 +0200 Subject: [PATCH 018/257] ci: fix publish.yml envvar --- .github/workflows/publish.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9660e6f..d65167b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,6 +4,10 @@ on: release: types: [ published ] +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + jobs: push_to_registries: name: Push Docker image to multiple registries From ff2b2d7fb06710f708c0c9e13edf9043030b843f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 14:36:59 +0200 Subject: [PATCH 019/257] chore: remove node_modules in the docker image --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 1ef1328..f9e21d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -103,4 +103,5 @@ RUN set -eux; \ yarn install; \ yarn run build; \ yarn run ttag:po2json; \ + rm -rf node_modules; \ sync From 34d946ba30a8992b6bff12c9b76d5171f1e4b16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Tue, 13 Aug 2024 18:29:56 +0200 Subject: [PATCH 020/257] chore: update monolog.yaml --- Dockerfile | 4 ---- config/packages/monolog.yaml | 16 ++++++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index f9e21d2..5998934 100644 --- a/Dockerfile +++ b/Dockerfile @@ -95,10 +95,6 @@ RUN set -eux; \ composer dump-env prod; \ composer run-script --no-dev post-install-cmd; \ chmod +x bin/console; \ - sync - - -RUN set -eux; \ php bin/console assets:install; \ yarn install; \ yarn run build; \ diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml index 9db7d8a..69f744a 100644 --- a/config/packages/monolog.yaml +++ b/config/packages/monolog.yaml @@ -9,7 +9,7 @@ when@dev: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" level: debug - channels: ["!event"] + channels: [ "!event" ] # uncomment to get logging in your browser # you may have to allow bigger header sizes in your Web server configuration #firephp: @@ -21,7 +21,7 @@ when@dev: console: type: console process_psr_3_messages: false - channels: ["!event", "!doctrine", "!console"] + channels: [ "!event", "!doctrine", "!console" ] when@test: monolog: @@ -30,8 +30,8 @@ when@test: type: fingers_crossed action_level: error handler: nested - excluded_http_codes: [404, 405] - channels: ["!event"] + excluded_http_codes: [ 404, 405 ] + channels: [ "!event" ] nested: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" @@ -42,9 +42,9 @@ when@prod: handlers: main: type: fingers_crossed - action_level: error + action_level: notice handler: nested - excluded_http_codes: [404, 405] + excluded_http_codes: [ 404, 405 ] buffer_size: 50 # How many messages should be saved? Prevent memory leaks nested: type: stream @@ -54,9 +54,9 @@ when@prod: console: type: console process_psr_3_messages: false - channels: ["!event", "!doctrine"] + channels: [ "!event", "!doctrine" ] deprecation: type: stream - channels: [deprecation] + channels: [ deprecation ] path: php://stderr formatter: monolog.formatter.json From 2d2d478b328aba89dda4a3a2d54b11262f29c1b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Wed, 14 Aug 2024 17:01:43 +0200 Subject: [PATCH 021/257] fix: remove patch watchlist --- README.md | 14 +++++++------- assets/utils/api/watchlist.ts | 15 --------------- src/Entity/WatchList.php | 2 ++ 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 39ba9bf..541ffbd 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,14 @@ detailed history of events (ownership changes, renewals, etc.) is not feasible w 1. Clone the repository 2. Build the Docker image locally - ```shell - docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache - ``` + ```shell + docker compose -f compose.yaml -f compose.prod.yaml build --pull --no-cache + ``` 3. Modify environment variables and add static files to customize your instance 4. Start the project in production environment - ```shell - docker compose -f compose.yaml -f compose.prod.yaml up - ``` + ```shell + docker compose -f compose.yaml -f compose.prod.yaml up + ``` ## How it works? @@ -81,7 +81,7 @@ possible to predict in advance which user will win the domain name. The choice i ## Disclaimer -> [!WARNING] +> [!IMPORTANT] > * Domain Watchdog is an opensource project distributed under *GNU Affero General Public License v3.0 or later* license > * In the internal opration, everything is done to perform the least possible RDAP requests: rate limit, intelligent caching system, etc. diff --git a/assets/utils/api/watchlist.ts b/assets/utils/api/watchlist.ts index af2a806..db97e23 100644 --- a/assets/utils/api/watchlist.ts +++ b/assets/utils/api/watchlist.ts @@ -32,18 +32,3 @@ export async function deleteWatchlist(token: string): Promise { url: 'watchlists/' + token }) } - -export async function patchWatchlist(domains: string[], triggers: Event[]) { - const response = await request({ - method: 'PATCH', - url: 'watchlists', - data: { - domains, - triggers - }, - headers: { - "Content-Type": 'application/merge-patch+json' - } - }) - return response.data -} \ No newline at end of file diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index c5c926c..48b4e60 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -58,10 +58,12 @@ use Symfony\Component\Uid\Uuid; denormalizationContext: ['groups' => 'watchlist:create'], name: 'create' ), + /* new Patch( normalizationContext: ['groups' => 'watchlist:item'], denormalizationContext: ['groups' => 'watchlist:update'] ), + */ new Delete(), ], )] From d41071a052dc6b93afcb88d872601568ece4fce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Wed, 14 Aug 2024 21:53:21 +0200 Subject: [PATCH 022/257] chore: remove unnecessary config --- frankenphp/Caddyfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/frankenphp/Caddyfile b/frankenphp/Caddyfile index 9bbff76..712c317 100644 --- a/frankenphp/Caddyfile +++ b/frankenphp/Caddyfile @@ -12,8 +12,6 @@ root * /app/public encode zstd br gzip - vulcain - {$CADDY_SERVER_EXTRA_DIRECTIVES} # Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics From 5dd27a4b7b121baf93ac2ead10f2a167404de1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Wed, 14 Aug 2024 23:23:32 +0200 Subject: [PATCH 023/257] feat: add watchlist patch with limitations --- assets/utils/api/watchlist.ts | 14 +++++- src/Controller/WatchListController.php | 63 +++++++++++++++++++------- src/Entity/WatchList.php | 33 ++++++++------ src/Entity/WatchListTrigger.php | 4 +- 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/assets/utils/api/watchlist.ts b/assets/utils/api/watchlist.ts index db97e23..d05baf3 100644 --- a/assets/utils/api/watchlist.ts +++ b/assets/utils/api/watchlist.ts @@ -1,4 +1,4 @@ -import {Event, request, Watchlist} from "./index"; +import {request, Watchlist} from "./index"; export async function getWatchlists() { const response = await request({ @@ -32,3 +32,15 @@ export async function deleteWatchlist(token: string): Promise { url: 'watchlists/' + token }) } + +export async function patchWatchlist(watchlist: Partial & { token: string }) { + const response = await request({ + method: 'PATCH', + url: 'watchlists/' + watchlist.token, + data: watchlist, + headers: { + "Content-Type": 'application/merge-patch+json' + } + }) + return response.data +} diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index dbc5237..f10e915 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -44,22 +44,8 @@ class WatchListController extends AbstractController ) { } - /** - * @throws \Exception - */ - #[Route( - path: '/api/watchlists', - name: 'watchlist_create', - defaults: [ - '_api_resource_class' => WatchList::class, - '_api_operation_name' => 'create', - ], - methods: ['POST'] - )] - public function createWatchList(Request $request): WatchList + public function verifyLimitations(WatchList $watchList) { - $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); - /** @var User $user */ $user = $this->getUser(); $watchList->setUser($user); @@ -99,8 +85,53 @@ class WatchListController extends AbstractController } } } + } - $this->logger->info('User {username} register a Watchlist ({token}).', [ + /** + * @throws \Exception + */ + #[Route( + path: '/api/watchlists', + name: 'watchlist_create', + defaults: [ + '_api_resource_class' => WatchList::class, + '_api_operation_name' => 'create', + ], + methods: ['POST'] + )] + public function createWatchList(Request $request): WatchList + { + $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); + $this->verifyLimitations($watchList); + + $user = $this->getUser(); + $this->logger->info('User {username} registers a Watchlist ({token}).', [ + 'username' => $user->getUserIdentifier(), + 'token' => $watchList->getToken(), + ]); + + $this->em->persist($watchList); + $this->em->flush(); + + return $watchList; + } + + #[Route( + path: '/api/watchlists/{token}', + name: 'watchlist_update', + defaults: [ + '_api_resource_class' => WatchList::class, + '_api_operation_name' => 'update', + ], + methods: ['PATCH'] + )] + public function patchWatchList(Request $request): WatchList + { + $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); + $this->verifyLimitations($watchList); + + $user = $this->getUser(); + $this->logger->info('User {username} updates a Watchlist ({token}).', [ 'username' => $user->getUserIdentifier(), 'token' => $watchList->getToken(), ]); diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index 48b4e60..1bd921c 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -27,7 +27,16 @@ use Symfony\Component\Uid\Uuid; name: 'get_all_mine', ), new Get( - normalizationContext: ['groups' => 'watchlist:item'], + normalizationContext: ['groups' => [ + 'watchlist:item', + 'domain:item', + 'event:list', + 'domain-entity:entity', + 'nameserver-entity:nameserver', + 'nameserver-entity:entity', + 'tld:item', + ], + ], security: 'object.user == user' ), new Get( @@ -58,26 +67,24 @@ use Symfony\Component\Uid\Uuid; denormalizationContext: ['groups' => 'watchlist:create'], name: 'create' ), - /* new Patch( + routeName: 'watchlist_update', normalizationContext: ['groups' => 'watchlist:item'], - denormalizationContext: ['groups' => 'watchlist:update'] + denormalizationContext: ['groups' => 'watchlist:create'], + name: 'update' ), - */ new Delete(), ], )] class WatchList { + #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'watchLists')] + #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] + public ?User $user = null; #[ORM\Id] #[ORM\Column(type: 'uuid')] #[Groups(['watchlist:item', 'watchlist:list'])] private string $token; - - #[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'watchLists')] - #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] - public ?User $user = null; - /** * @var Collection */ @@ -85,23 +92,23 @@ class WatchList #[ORM\JoinTable(name: 'watch_lists_domains', joinColumns: [new ORM\JoinColumn(name: 'watch_list_token', referencedColumnName: 'token', onDelete: 'CASCADE')], inverseJoinColumns: [new ORM\JoinColumn(name: 'domain_ldh_name', referencedColumnName: 'ldh_name', onDelete: 'CASCADE')])] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] private Collection $domains; /** * @var Collection */ #[ORM\OneToMany(targetEntity: WatchListTrigger::class, mappedBy: 'watchList', cascade: ['persist'], orphanRemoval: true)] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] #[SerializedName('triggers')] private Collection $watchListTriggers; #[ORM\ManyToOne(inversedBy: 'watchLists')] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] private ?Connector $connector = null; #[ORM\Column(length: 255, nullable: true)] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] private ?string $name = null; #[ORM\Column] diff --git a/src/Entity/WatchListTrigger.php b/src/Entity/WatchListTrigger.php index d40b265..ce92512 100644 --- a/src/Entity/WatchListTrigger.php +++ b/src/Entity/WatchListTrigger.php @@ -12,7 +12,7 @@ class WatchListTrigger { #[ORM\Id] #[ORM\Column(length: 255)] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] private ?string $event = null; #[ORM\Id] @@ -22,7 +22,7 @@ class WatchListTrigger #[ORM\Id] #[ORM\Column(enumType: TriggerAction::class)] - #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create', 'watchlist:update'])] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] private ?TriggerAction $action = null; public function getEvent(): ?string From 7d16d836f44a8022f8fb2612288db5fcc10cd1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 03:04:31 +0200 Subject: [PATCH 024/257] feat: update Watchlist --- assets/components/tracking/WatchlistForm.tsx | 20 +++-- assets/components/tracking/WatchlistsList.tsx | 69 +++++++++++++-- assets/pages/tracking/WatchlistPage.tsx | 52 ++++++++--- assets/utils/api/watchlist.ts | 11 +-- src/Controller/WatchListController.php | 88 ++++++++++--------- src/Entity/WatchList.php | 14 ++- src/Entity/WatchListTrigger.php | 2 +- 7 files changed, 177 insertions(+), 79 deletions(-) diff --git a/assets/components/tracking/WatchlistForm.tsx b/assets/components/tracking/WatchlistForm.tsx index 1b76c5c..689bd1d 100644 --- a/assets/components/tracking/WatchlistForm.tsx +++ b/assets/components/tracking/WatchlistForm.tsx @@ -25,19 +25,20 @@ const formItemLayoutWithOutLabel = { }, }; -export function WatchlistForm({form, connectors, onCreateWatchlist}: { +export function WatchlistForm({form, connectors, onFinish, isCreation}: { form: FormInstance, connectors: (Connector & { id: string })[] - onCreateWatchlist: (values: { domains: string[], emailTriggers: string[] }) => void + onFinish: (values: { domains: string[], emailTriggers: string[], token: string }) => void + isCreation: boolean }) { const domainEventTranslated = domainEvent() const triggerTagRenderer: TagRender = (props) => { const {value, closable, onClose} = props; const onPreventMouseDown = (event: React.MouseEvent) => { - event.preventDefault(); - event.stopPropagation(); - }; + event.preventDefault() + event.stopPropagation() + } return ( + + + } + > + { + onUpdateWatchlist(values); + onClose() + }} + connectors={connectors} + isCreation={false} + /> + + - + + + } > diff --git a/assets/pages/tracking/WatchlistPage.tsx b/assets/pages/tracking/WatchlistPage.tsx index 5fbd285..40b0762 100644 --- a/assets/pages/tracking/WatchlistPage.tsx +++ b/assets/pages/tracking/WatchlistPage.tsx @@ -1,6 +1,6 @@ import React, {useEffect, useState} from "react"; import {Card, Divider, Flex, Form, message} from "antd"; -import {EventAction, getWatchlists, postWatchlist} from "../../utils/api"; +import {EventAction, getWatchlists, putWatchlist, postWatchlist} from "../../utils/api"; import {AxiosError} from "axios"; import {t} from 'ttag' import {WatchlistForm} from "../../components/tracking/WatchlistForm"; @@ -40,7 +40,7 @@ export default function WatchlistPage() { name: values.name, domains: domainsURI, triggers: values.emailTriggers.map(t => ({event: t, action: 'email'})), - connector: values.connector !== undefined ? '/api/connectors/' + values.connector : undefined + connector: values.connector !== undefined ? ('/api/connectors/' + values.connector) : undefined }).then((w) => { form.resetFields() refreshWatchlists() @@ -50,6 +50,31 @@ export default function WatchlistPage() { }) } + const onUpdateWatchlist = (values: { + token: string + name?: string + domains: string[], + emailTriggers: string[] + connector?: string + }) => { + const domainsURI = values.domains.map(d => '/api/domains/' + d) + + console.log(values) + + putWatchlist({ + token: values.token, + name: values.name, + domains: domainsURI, + triggers: values.emailTriggers.map(t => ({event: t, action: 'email'})), + connector: values.connector !== undefined ? ('/api/connectors/' + values.connector) : undefined + }).then((w) => { + refreshWatchlists() + messageApi.success(t`Watchlist updated !`) + }).catch((e: AxiosError) => { + showErrorAPI(e, messageApi) + }) + } + const refreshWatchlists = () => getWatchlists().then(w => { setWatchlists(w['hydra:member']) }).catch((e: AxiosError) => { @@ -67,17 +92,18 @@ export default function WatchlistPage() { }, []) return - - {contextHolder} - { - connectors && - - } - - + {contextHolder} + { + connectors && + + + + } - - {watchlists && watchlists.length > 0 && - } + {connectors && watchlists && watchlists.length > 0 && + } } \ No newline at end of file diff --git a/assets/utils/api/watchlist.ts b/assets/utils/api/watchlist.ts index d05baf3..ec0d55d 100644 --- a/assets/utils/api/watchlist.ts +++ b/assets/utils/api/watchlist.ts @@ -1,4 +1,4 @@ -import {request, Watchlist} from "./index"; +import {Event, request, Watchlist} from "./index"; export async function getWatchlists() { const response = await request({ @@ -33,14 +33,11 @@ export async function deleteWatchlist(token: string): Promise { }) } -export async function patchWatchlist(watchlist: Partial & { token: string }) { +export async function putWatchlist(watchlist: Partial & { token: string }) { const response = await request({ - method: 'PATCH', + method: 'PUT', url: 'watchlists/' + watchlist.token, data: watchlist, - headers: { - "Content-Type": 'application/merge-patch+json' - } }) return response.data -} +} \ No newline at end of file diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index f10e915..5849753 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -10,6 +10,7 @@ use App\Entity\WatchList; use App\Repository\WatchListRepository; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Exception\ORMException; use Eluceo\iCal\Domain\Entity\Attendee; use Eluceo\iCal\Domain\Entity\Calendar; use Eluceo\iCal\Domain\Entity\Event; @@ -44,7 +45,36 @@ class WatchListController extends AbstractController ) { } - public function verifyLimitations(WatchList $watchList) + /** + * @throws \Exception + */ + #[Route( + path: '/api/watchlists', + name: 'watchlist_create', + defaults: [ + '_api_resource_class' => WatchList::class, + '_api_operation_name' => 'create', + ], + methods: ['POST'] + )] + public function createWatchList(Request $request): WatchList + { + $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); + $this->verifyLimitations($watchList); + + $user = $this->getUser(); + $this->logger->info('User {username} registers a Watchlist ({token}).', [ + 'username' => $user->getUserIdentifier(), + 'token' => $watchList->getToken(), + ]); + + $this->em->persist($watchList); + $this->em->flush(); + + return $watchList; + } + + public function verifyLimitations(WatchList $watchList): void { /** @var User $user */ $user = $this->getUser(); @@ -87,35 +117,26 @@ class WatchListController extends AbstractController } } - /** - * @throws \Exception - */ #[Route( path: '/api/watchlists', - name: 'watchlist_create', + name: 'watchlist_get_all_mine', defaults: [ '_api_resource_class' => WatchList::class, - '_api_operation_name' => 'create', + '_api_operation_name' => 'get_all_mine', ], - methods: ['POST'] + methods: ['GET'] )] - public function createWatchList(Request $request): WatchList + public function getWatchLists(): Collection { - $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); - $this->verifyLimitations($watchList); - + /** @var User $user */ $user = $this->getUser(); - $this->logger->info('User {username} registers a Watchlist ({token}).', [ - 'username' => $user->getUserIdentifier(), - 'token' => $watchList->getToken(), - ]); - $this->em->persist($watchList); - $this->em->flush(); - - return $watchList; + return $user->getWatchLists(); } + /** + * @throws ORMException + */ #[Route( path: '/api/watchlists/{token}', name: 'watchlist_update', @@ -123,19 +144,23 @@ class WatchListController extends AbstractController '_api_resource_class' => WatchList::class, '_api_operation_name' => 'update', ], - methods: ['PATCH'] + methods: ['PUT'] )] - public function patchWatchList(Request $request): WatchList + public function putWatchList(WatchList $watchList): WatchList { - $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); + /** @var User $user */ + $user = $this->getUser(); + $this->verifyLimitations($watchList); - $user = $this->getUser(); $this->logger->info('User {username} updates a Watchlist ({token}).', [ 'username' => $user->getUserIdentifier(), 'token' => $watchList->getToken(), ]); + $this->em->remove($this->em->getReference(WatchList::class, $watchList->getToken())); + $this->em->flush(); + $this->em->persist($watchList); $this->em->flush(); @@ -202,21 +227,4 @@ class WatchListController extends AbstractController 'Content-Type' => 'text/calendar; charset=utf-8', ]); } - - #[Route( - path: '/api/watchlists', - name: 'watchlist_get_all_mine', - defaults: [ - '_api_resource_class' => WatchList::class, - '_api_operation_name' => 'get_all_mine', - ], - methods: ['GET'] - )] - public function getWatchLists(): Collection - { - /** @var User $user */ - $user = $this->getUser(); - - return $user->getWatchLists(); - } } diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index 1bd921c..3297032 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -6,8 +6,8 @@ use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\Delete; use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\GetCollection; -use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Post; +use ApiPlatform\Metadata\Put; use App\Controller\WatchListController; use App\Repository\WatchListRepository; use Doctrine\Common\Collections\ArrayCollection; @@ -67,10 +67,11 @@ use Symfony\Component\Uid\Uuid; denormalizationContext: ['groups' => 'watchlist:create'], name: 'create' ), - new Patch( + new Put( routeName: 'watchlist_update', normalizationContext: ['groups' => 'watchlist:item'], - denormalizationContext: ['groups' => 'watchlist:create'], + denormalizationContext: ['groups' => ['watchlist:create', 'watchlist:token']], + security: 'object.user == user', name: 'update' ), new Delete(), @@ -83,7 +84,7 @@ class WatchList public ?User $user = null; #[ORM\Id] #[ORM\Column(type: 'uuid')] - #[Groups(['watchlist:item', 'watchlist:list'])] + #[Groups(['watchlist:item', 'watchlist:list', 'watchlist:token'])] private string $token; /** * @var Collection @@ -128,6 +129,11 @@ class WatchList return $this->token; } + public function setToken(string $token): void + { + $this->token = $token; + } + public function getUser(): ?User { return $this->user; diff --git a/src/Entity/WatchListTrigger.php b/src/Entity/WatchListTrigger.php index ce92512..c1601fe 100644 --- a/src/Entity/WatchListTrigger.php +++ b/src/Entity/WatchListTrigger.php @@ -16,7 +16,7 @@ class WatchListTrigger private ?string $event = null; #[ORM\Id] - #[ORM\ManyToOne(targetEntity: WatchList::class, inversedBy: 'watchListTriggers')] + #[ORM\ManyToOne(targetEntity: WatchList::class, cascade: ['persist'], inversedBy: 'watchListTriggers')] #[ORM\JoinColumn(referencedColumnName: 'token', nullable: false, onDelete: 'CASCADE')] private ?WatchList $watchList = null; From 2da8c0b2700014f894e3d7187ab46e8c17a610b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 03:11:19 +0200 Subject: [PATCH 025/257] fix: update watchlist width --- assets/components/tracking/WatchlistsList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/WatchlistsList.tsx index 3d8b359..0b42862 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/WatchlistsList.tsx @@ -82,7 +82,7 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect Date: Thu, 15 Aug 2024 03:12:09 +0200 Subject: [PATCH 026/257] chore: update translations.pot --- translations/translations.pot | 70 +++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/translations/translations.pot b/translations/translations.pot index 9ae847d..475d4b0 100644 --- a/translations/translations.pot +++ b/translations/translations.pot @@ -22,7 +22,7 @@ msgstr "" #: assets/components/tracking/ConnectorForm.tsx:142 #: assets/components/tracking/ConnectorForm.tsx:156 #: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:103 +#: assets/components/tracking/WatchlistForm.tsx:109 msgid "Required" msgstr "" @@ -84,7 +84,7 @@ msgid "ENUM validation expiration" msgstr "" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:106 +#: assets/components/tracking/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "" @@ -132,62 +132,66 @@ msgstr "" msgid "Noc" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:60 +#: assets/components/tracking/WatchlistForm.tsx:66 msgid "Name" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:71 +#: assets/components/tracking/WatchlistForm.tsx:77 msgid "Watchlist Name" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:72 +#: assets/components/tracking/WatchlistForm.tsx:78 msgid "Naming the Watchlist makes it easier to find in the list below." msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:83 +#: assets/components/tracking/WatchlistForm.tsx:89 msgid "At least one domain name" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:94 -#: assets/components/tracking/WatchlistsList.tsx:21 +#: assets/components/tracking/WatchlistForm.tsx:100 +#: assets/components/tracking/WatchlistsList.tsx:28 msgid "Domain names" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/WatchlistForm.tsx:118 msgid "Domain name" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:129 +#: assets/components/tracking/WatchlistForm.tsx:135 msgid "Add a Domain name" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:136 -#: assets/components/tracking/WatchlistsList.tsx:25 +#: assets/components/tracking/WatchlistForm.tsx:142 +#: assets/components/tracking/WatchlistsList.tsx:32 msgid "Tracked events" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:138 +#: assets/components/tracking/WatchlistForm.tsx:144 msgid "At least one trigger" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:160 -#: assets/components/tracking/WatchlistForm.tsx:174 +#: assets/components/tracking/WatchlistForm.tsx:166 +#: assets/components/tracking/WatchlistForm.tsx:180 msgid "Connector" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:170 +#: assets/components/tracking/WatchlistForm.tsx:176 msgid "" "Please make sure the connector information is valid to purchase a domain " "that may be available soon." msgstr "" #: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:186 +#: assets/components/tracking/WatchlistForm.tsx:192 msgid "Create" msgstr "" +#: assets/components/tracking/WatchlistForm.tsx:192 +msgid "Update" +msgstr "" + #: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:189 +#: assets/components/tracking/WatchlistForm.tsx:195 msgid "Reset" msgstr "" @@ -261,34 +265,42 @@ msgid "" "the Provider's API" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:40 +#: assets/components/tracking/WatchlistsList.tsx:57 msgid "This Watchlist is not linked to a Connector." msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:43 +#: assets/components/tracking/WatchlistsList.tsx:60 msgid "Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:51 +#: assets/components/tracking/WatchlistsList.tsx:68 msgid "Export events to iCalendar format" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:54 -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:71 +msgid "Edit the Watchlist" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:84 +msgid "Update a Watchlist" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:107 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "Delete the Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:55 +#: assets/components/tracking/WatchlistsList.tsx:108 msgid "Are you sure to delete this Watchlist?" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:110 msgid "Yes" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:58 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "No" msgstr "" @@ -497,7 +509,11 @@ msgstr "" msgid "Watchlist created !" msgstr "" -#: assets/pages/tracking/WatchlistPage.tsx:70 +#: assets/pages/tracking/WatchlistPage.tsx:72 +msgid "Watchlist updated !" +msgstr "" + +#: assets/pages/tracking/WatchlistPage.tsx:98 msgid "Create a Watchlist" msgstr "" From 6878be0fbaeca5d4b286b6023cbf5bbc9ab40a62 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 15 Aug 2024 01:12:41 +0000 Subject: [PATCH 027/257] Update translation files Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate. --- translations/de.po | 112 +++++++++++++++++++++++++-------------------- translations/fr.po | 76 +++++++++++++++++++----------- 2 files changed, 111 insertions(+), 77 deletions(-) diff --git a/translations/de.po b/translations/de.po index ccd745e..8ec66a7 100644 --- a/translations/de.po +++ b/translations/de.po @@ -5,20 +5,17 @@ msgstr "" "Language-Team: German \n" "Language: de\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.6.2\n" -#: assets/components/LoginForm.tsx:51 -#: assets/components/RegisterForm.tsx:38 +#: assets/components/LoginForm.tsx:51 assets/components/RegisterForm.tsx:38 msgid "Email address" msgstr "E-Mail-Adresse" -#: assets/components/LoginForm.tsx:53 -#: assets/components/LoginForm.tsx:61 -#: assets/components/RegisterForm.tsx:40 -#: assets/components/RegisterForm.tsx:48 +#: assets/components/LoginForm.tsx:53 assets/components/LoginForm.tsx:61 +#: assets/components/RegisterForm.tsx:40 assets/components/RegisterForm.tsx:48 #: assets/components/search/DomainSearchBar.tsx:23 #: assets/components/tracking/ConnectorForm.tsx:43 #: assets/components/tracking/ConnectorForm.tsx:69 @@ -29,12 +26,11 @@ msgstr "E-Mail-Adresse" #: assets/components/tracking/ConnectorForm.tsx:142 #: assets/components/tracking/ConnectorForm.tsx:156 #: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:103 +#: assets/components/tracking/WatchlistForm.tsx:109 msgid "Required" msgstr "Erforderlich" -#: assets/components/LoginForm.tsx:59 -#: assets/components/RegisterForm.tsx:46 +#: assets/components/LoginForm.tsx:59 assets/components/RegisterForm.tsx:46 msgid "Password" msgstr "Passwort" @@ -91,7 +87,7 @@ msgid "ENUM validation expiration" msgstr "Ablauf der ENUM-Validierung" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:106 +#: assets/components/tracking/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "Dieser Domainname scheint nicht gültig zu sein" @@ -139,52 +135,52 @@ msgstr "Benachrichtigungen" msgid "Noc" msgstr "Noc" -#: assets/components/tracking/WatchlistForm.tsx:60 +#: assets/components/tracking/WatchlistForm.tsx:66 msgid "Name" msgstr "Name" -#: assets/components/tracking/WatchlistForm.tsx:71 +#: assets/components/tracking/WatchlistForm.tsx:77 msgid "Watchlist Name" msgstr "Name der Watchlist" -#: assets/components/tracking/WatchlistForm.tsx:72 +#: assets/components/tracking/WatchlistForm.tsx:78 msgid "Naming the Watchlist makes it easier to find in the list below." msgstr "" "Durch die Benennung der Watchlist ist sie in der Liste weiter unten leichter " "zu finden." -#: assets/components/tracking/WatchlistForm.tsx:83 +#: assets/components/tracking/WatchlistForm.tsx:89 msgid "At least one domain name" msgstr "Mindestens ein Domänenname" -#: assets/components/tracking/WatchlistForm.tsx:94 -#: assets/components/tracking/WatchlistsList.tsx:21 +#: assets/components/tracking/WatchlistForm.tsx:100 +#: assets/components/tracking/WatchlistsList.tsx:28 msgid "Domain names" msgstr "Domänennamen" -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/WatchlistForm.tsx:118 msgid "Domain name" msgstr "Domänenname" -#: assets/components/tracking/WatchlistForm.tsx:129 +#: assets/components/tracking/WatchlistForm.tsx:135 msgid "Add a Domain name" msgstr "Einen Domänennamen hinzufügen" -#: assets/components/tracking/WatchlistForm.tsx:136 -#: assets/components/tracking/WatchlistsList.tsx:25 +#: assets/components/tracking/WatchlistForm.tsx:142 +#: assets/components/tracking/WatchlistsList.tsx:32 msgid "Tracked events" msgstr "Verfolgte Ereignisse" -#: assets/components/tracking/WatchlistForm.tsx:138 +#: assets/components/tracking/WatchlistForm.tsx:144 msgid "At least one trigger" msgstr "Mindestens ein Auslöser" -#: assets/components/tracking/WatchlistForm.tsx:160 -#: assets/components/tracking/WatchlistForm.tsx:174 +#: assets/components/tracking/WatchlistForm.tsx:166 +#: assets/components/tracking/WatchlistForm.tsx:180 msgid "Connector" msgstr "Konnektor" -#: assets/components/tracking/WatchlistForm.tsx:170 +#: assets/components/tracking/WatchlistForm.tsx:176 msgid "" "Please make sure the connector information is valid to purchase a domain " "that may be available soon." @@ -193,12 +189,16 @@ msgstr "" "eine Domäne zu erwerben, die möglicherweise bald verfügbar ist." #: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:186 +#: assets/components/tracking/WatchlistForm.tsx:192 msgid "Create" msgstr "Erstellen" +#: assets/components/tracking/WatchlistForm.tsx:192 +msgid "Update" +msgstr "" + #: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:189 +#: assets/components/tracking/WatchlistForm.tsx:195 msgid "Reset" msgstr "Zurücksetzen" @@ -280,34 +280,46 @@ msgstr "" "Ich verzichte auf mein Widerrufsrecht beim Kauf von Domainnamen über die API " "des Anbieters" -#: assets/components/tracking/WatchlistsList.tsx:40 +#: assets/components/tracking/WatchlistsList.tsx:57 msgid "This Watchlist is not linked to a Connector." msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." -#: assets/components/tracking/WatchlistsList.tsx:43 +#: assets/components/tracking/WatchlistsList.tsx:60 msgid "Watchlist" msgstr "Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:51 +#: assets/components/tracking/WatchlistsList.tsx:68 msgid "Export events to iCalendar format" msgstr "Ereignisse in das iCalendar-Format exportieren" -#: assets/components/tracking/WatchlistsList.tsx:54 -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:71 +#, fuzzy +#| msgid "Delete the Watchlist" +msgid "Edit the Watchlist" +msgstr "Löschen der Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:84 +#, fuzzy +#| msgid "Create a Watchlist" +msgid "Update a Watchlist" +msgstr "Erstellen Sie eine Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:107 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "Delete the Watchlist" msgstr "Löschen der Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:55 +#: assets/components/tracking/WatchlistsList.tsx:108 msgid "Are you sure to delete this Watchlist?" msgstr "Möchten Sie diese Watchlist wirklich löschen?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:110 msgid "Yes" msgstr "Ja" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:58 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "No" msgstr "Nein" @@ -340,8 +352,7 @@ msgstr "Domain" msgid "Domain Finder" msgstr "Domänenfinder" -#: assets/components/Sider.tsx:49 -#: assets/pages/info/TldPage.tsx:79 +#: assets/components/Sider.tsx:49 assets/pages/info/TldPage.tsx:79 msgid "TLD" msgstr "TLD" @@ -381,8 +392,7 @@ msgstr "Meine Konnektoren" msgid "Statistics" msgstr "Statistiken" -#: assets/components/Sider.tsx:105 -#: assets/pages/watchdog/UserPage.tsx:16 +#: assets/components/Sider.tsx:105 assets/pages/watchdog/UserPage.tsx:16 msgid "My Account" msgstr "Mein Konto" @@ -390,14 +400,12 @@ msgstr "Mein Konto" msgid "Log out" msgstr "Abmelden" -#: assets/components/Sider.tsx:119 -#: assets/pages/LoginPage.tsx:30 +#: assets/components/Sider.tsx:119 assets/pages/LoginPage.tsx:30 #: assets/pages/LoginPage.tsx:38 msgid "Log in" msgstr "Anmelden" -#: assets/components/RegisterForm.tsx:55 -#: assets/pages/LoginPage.tsx:30 +#: assets/components/RegisterForm.tsx:55 assets/pages/LoginPage.tsx:30 msgid "Register" msgstr "Registrieren" @@ -538,7 +546,13 @@ msgstr "Erstellen eines Connectors" msgid "Watchlist created !" msgstr "Watchlist erstellt !" -#: assets/pages/tracking/WatchlistPage.tsx:70 +#: assets/pages/tracking/WatchlistPage.tsx:72 +#, fuzzy +#| msgid "Watchlist created !" +msgid "Watchlist updated !" +msgstr "Watchlist erstellt !" + +#: assets/pages/tracking/WatchlistPage.tsx:98 msgid "Create a Watchlist" msgstr "Erstellen Sie eine Watchlist" @@ -552,8 +566,7 @@ msgstr "Ein Konto erstellen" #: assets/utils/providers/index.tsx:11 msgid "" -"Retrieve a set of tokens from your customer account on the Provider's " -"website" +"Retrieve a set of tokens from your customer account on the Provider's website" msgstr "" "Abrufen eines Token-Satzes aus Ihrem Kundenkonto auf der Website des " "Anbieters" @@ -603,8 +616,7 @@ msgstr "" msgid "Please retry after ${ duration } seconds" msgstr "Bitte versuchen Sie es nach ${ duration } Sekunden erneut" -#: assets/utils/index.ts:23 -#: assets/utils/index.ts:26 +#: assets/utils/index.ts:23 assets/utils/index.ts:26 msgid "An error occurred" msgstr "Es ist ein Fehler aufgetreten" @@ -627,8 +639,8 @@ msgstr "Dokumentation" #: assets/App.tsx:108 #, javascript-format msgid "" -"${ ProjectLink } is an open source project distributed under the ${ " -"LicenseLink } license." +"${ ProjectLink } is an open source project distributed under the " +"${ LicenseLink } license." msgstr "" "${ ProjectLink } ist ein Open-Source-Projekt, das unter der ${ LicenseLink }-" "Lizenz vertrieben wird." diff --git a/translations/fr.po b/translations/fr.po index a7794d0..e6a1c38 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -27,7 +27,7 @@ msgstr "Adresse e-mail" #: assets/components/tracking/ConnectorForm.tsx:142 #: assets/components/tracking/ConnectorForm.tsx:156 #: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:103 +#: assets/components/tracking/WatchlistForm.tsx:109 msgid "Required" msgstr "Requis" @@ -88,7 +88,7 @@ msgid "ENUM validation expiration" msgstr "Expiration de la validation ENUM" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:106 +#: assets/components/tracking/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "Ce nom de domaine ne semble pas être valide" @@ -136,52 +136,52 @@ msgstr "Notifications" msgid "Noc" msgstr "NOC" -#: assets/components/tracking/WatchlistForm.tsx:60 +#: assets/components/tracking/WatchlistForm.tsx:66 msgid "Name" msgstr "Nom" -#: assets/components/tracking/WatchlistForm.tsx:71 +#: assets/components/tracking/WatchlistForm.tsx:77 msgid "Watchlist Name" msgstr "Nom de la Watchlist" -#: assets/components/tracking/WatchlistForm.tsx:72 +#: assets/components/tracking/WatchlistForm.tsx:78 msgid "Naming the Watchlist makes it easier to find in the list below." msgstr "" "Nommer la Watchlist permet de la retrouver plus facilement dans la liste ci-" "dessous." -#: assets/components/tracking/WatchlistForm.tsx:83 +#: assets/components/tracking/WatchlistForm.tsx:89 msgid "At least one domain name" msgstr "Au moins un nom de domaine" -#: assets/components/tracking/WatchlistForm.tsx:94 -#: assets/components/tracking/WatchlistsList.tsx:21 +#: assets/components/tracking/WatchlistForm.tsx:100 +#: assets/components/tracking/WatchlistsList.tsx:28 msgid "Domain names" msgstr "Noms de domaines" -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/WatchlistForm.tsx:118 msgid "Domain name" msgstr "Nom de domaine" -#: assets/components/tracking/WatchlistForm.tsx:129 +#: assets/components/tracking/WatchlistForm.tsx:135 msgid "Add a Domain name" msgstr "Ajouter un nom de domaine" -#: assets/components/tracking/WatchlistForm.tsx:136 -#: assets/components/tracking/WatchlistsList.tsx:25 +#: assets/components/tracking/WatchlistForm.tsx:142 +#: assets/components/tracking/WatchlistsList.tsx:32 msgid "Tracked events" msgstr "Événements suivis" -#: assets/components/tracking/WatchlistForm.tsx:138 +#: assets/components/tracking/WatchlistForm.tsx:144 msgid "At least one trigger" msgstr "Au moins un déclencheur" -#: assets/components/tracking/WatchlistForm.tsx:160 -#: assets/components/tracking/WatchlistForm.tsx:174 +#: assets/components/tracking/WatchlistForm.tsx:166 +#: assets/components/tracking/WatchlistForm.tsx:180 msgid "Connector" msgstr "Connecteur" -#: assets/components/tracking/WatchlistForm.tsx:170 +#: assets/components/tracking/WatchlistForm.tsx:176 msgid "" "Please make sure the connector information is valid to purchase a domain " "that may be available soon." @@ -190,12 +190,16 @@ msgstr "" "acheter un domaine qui pourrait être disponible prochainement." #: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:186 +#: assets/components/tracking/WatchlistForm.tsx:192 msgid "Create" msgstr "Créer" +#: assets/components/tracking/WatchlistForm.tsx:192 +msgid "Update" +msgstr "" + #: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:189 +#: assets/components/tracking/WatchlistForm.tsx:195 msgid "Reset" msgstr "Réinitialiser" @@ -276,34 +280,46 @@ msgstr "" "Je renonce expressément à mon droit de rétractation concernant l'achat de " "noms de domaine via l'API du Fournisseur" -#: assets/components/tracking/WatchlistsList.tsx:40 +#: assets/components/tracking/WatchlistsList.tsx:57 msgid "This Watchlist is not linked to a Connector." msgstr "Cette Watchlist n'est pas liée à un connecteur." -#: assets/components/tracking/WatchlistsList.tsx:43 +#: assets/components/tracking/WatchlistsList.tsx:60 msgid "Watchlist" msgstr "Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:51 +#: assets/components/tracking/WatchlistsList.tsx:68 msgid "Export events to iCalendar format" msgstr "Exporter les événements au format iCalendar" -#: assets/components/tracking/WatchlistsList.tsx:54 -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:71 +#, fuzzy +#| msgid "Delete the Watchlist" +msgid "Edit the Watchlist" +msgstr "Supprimer la Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:84 +#, fuzzy +#| msgid "Create a Watchlist" +msgid "Update a Watchlist" +msgstr "Créer une Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:107 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "Delete the Watchlist" msgstr "Supprimer la Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:55 +#: assets/components/tracking/WatchlistsList.tsx:108 msgid "Are you sure to delete this Watchlist?" msgstr "Êtes-vous sûr de vouloir supprimer cette Watchlist ?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:110 msgid "Yes" msgstr "Oui" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:58 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "No" msgstr "Non" @@ -529,7 +545,13 @@ msgstr "Créer un Connecteur" msgid "Watchlist created !" msgstr "Watchlist créée !" -#: assets/pages/tracking/WatchlistPage.tsx:70 +#: assets/pages/tracking/WatchlistPage.tsx:72 +#, fuzzy +#| msgid "Watchlist created !" +msgid "Watchlist updated !" +msgstr "Watchlist créée !" + +#: assets/pages/tracking/WatchlistPage.tsx:98 msgid "Create a Watchlist" msgstr "Créer une Watchlist" From 2c27ba8508a7b763b7bd2b9d6c1c87640968c502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 01:13:02 +0000 Subject: [PATCH 028/257] Translated using Weblate (French) Currently translated at 100.0% (132 of 132 strings) --- translations/fr.po | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/translations/fr.po b/translations/fr.po index e6a1c38..94f5666 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-09 22:58+0000\n" +"PO-Revision-Date: 2024-08-15 01:17+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: French \n" @@ -196,7 +196,7 @@ msgstr "Créer" #: assets/components/tracking/WatchlistForm.tsx:192 msgid "Update" -msgstr "" +msgstr "Mise à jour" #: assets/components/tracking/ConnectorForm.tsx:179 #: assets/components/tracking/WatchlistForm.tsx:195 @@ -293,16 +293,12 @@ msgid "Export events to iCalendar format" msgstr "Exporter les événements au format iCalendar" #: assets/components/tracking/WatchlistsList.tsx:71 -#, fuzzy -#| msgid "Delete the Watchlist" msgid "Edit the Watchlist" -msgstr "Supprimer la Watchlist" +msgstr "Modifier la Watchlist" #: assets/components/tracking/WatchlistsList.tsx:84 -#, fuzzy -#| msgid "Create a Watchlist" msgid "Update a Watchlist" -msgstr "Créer une Watchlist" +msgstr "Mise à jour d'une Watchlist" #: assets/components/tracking/WatchlistsList.tsx:107 #: assets/components/tracking/WatchlistsList.tsx:114 @@ -546,10 +542,8 @@ msgid "Watchlist created !" msgstr "Watchlist créée !" #: assets/pages/tracking/WatchlistPage.tsx:72 -#, fuzzy -#| msgid "Watchlist created !" msgid "Watchlist updated !" -msgstr "Watchlist créée !" +msgstr "Watchlist mise à jour !" #: assets/pages/tracking/WatchlistPage.tsx:98 msgid "Create a Watchlist" From ca6499b55f3eb144662f16d6dfffe9adff74c295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 01:14:36 +0000 Subject: [PATCH 029/257] Translated using Weblate (German) Currently translated at 100.0% (132 of 132 strings) --- translations/de.po | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/translations/de.po b/translations/de.po index 8ec66a7..fd995c4 100644 --- a/translations/de.po +++ b/translations/de.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-13 10:20+0000\n" +"PO-Revision-Date: 2024-08-15 01:17+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: German \n" @@ -195,7 +195,7 @@ msgstr "Erstellen" #: assets/components/tracking/WatchlistForm.tsx:192 msgid "Update" -msgstr "" +msgstr "Aktualisieren" #: assets/components/tracking/ConnectorForm.tsx:179 #: assets/components/tracking/WatchlistForm.tsx:195 @@ -293,16 +293,12 @@ msgid "Export events to iCalendar format" msgstr "Ereignisse in das iCalendar-Format exportieren" #: assets/components/tracking/WatchlistsList.tsx:71 -#, fuzzy -#| msgid "Delete the Watchlist" msgid "Edit the Watchlist" -msgstr "Löschen der Watchlist" +msgstr "Bearbeiten der Watchlist" #: assets/components/tracking/WatchlistsList.tsx:84 -#, fuzzy -#| msgid "Create a Watchlist" msgid "Update a Watchlist" -msgstr "Erstellen Sie eine Watchlist" +msgstr "Aktualisieren einer Watchlist" #: assets/components/tracking/WatchlistsList.tsx:107 #: assets/components/tracking/WatchlistsList.tsx:114 @@ -547,10 +543,8 @@ msgid "Watchlist created !" msgstr "Watchlist erstellt !" #: assets/pages/tracking/WatchlistPage.tsx:72 -#, fuzzy -#| msgid "Watchlist created !" msgid "Watchlist updated !" -msgstr "Watchlist erstellt !" +msgstr "Watchlist aktualisiert !" #: assets/pages/tracking/WatchlistPage.tsx:98 msgid "Create a Watchlist" From 04aa834379d0b05f6bb7bdd9bf3e045949afab28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 03:42:41 +0200 Subject: [PATCH 030/257] fix: update watchlist limitations --- src/Controller/WatchListController.php | 54 ++++++++++++++++++-------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index 5849753..9ce9296 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -60,22 +60,7 @@ class WatchListController extends AbstractController public function createWatchList(Request $request): WatchList { $watchList = $this->serializer->deserialize($request->getContent(), WatchList::class, 'json', ['groups' => 'watchlist:create']); - $this->verifyLimitations($watchList); - $user = $this->getUser(); - $this->logger->info('User {username} registers a Watchlist ({token}).', [ - 'username' => $user->getUserIdentifier(), - 'token' => $watchList->getToken(), - ]); - - $this->em->persist($watchList); - $this->em->flush(); - - return $watchList; - } - - public function verifyLimitations(WatchList $watchList): void - { /** @var User $user */ $user = $this->getUser(); $watchList->setUser($user); @@ -115,6 +100,17 @@ class WatchListController extends AbstractController } } } + + $user = $this->getUser(); + $this->logger->info('User {username} registers a Watchlist ({token}).', [ + 'username' => $user->getUserIdentifier(), + 'token' => $watchList->getToken(), + ]); + + $this->em->persist($watchList); + $this->em->flush(); + + return $watchList; } #[Route( @@ -136,6 +132,7 @@ class WatchListController extends AbstractController /** * @throws ORMException + * @throws \Exception */ #[Route( path: '/api/watchlists/{token}', @@ -150,8 +147,33 @@ class WatchListController extends AbstractController { /** @var User $user */ $user = $this->getUser(); + $watchList->setUser($user); - $this->verifyLimitations($watchList); + if ($this->getParameter('limited_features')) { + if ($watchList->getDomains()->count() >= (int) $this->getParameter('limit_max_watchlist_domains')) { + $this->logger->notice('User {username} tried to update a Watchlist. However, the maximum number of domains has been reached for this Watchlist', [ + 'username' => $user->getUserIdentifier(), + ]); + throw new AccessDeniedHttpException('You have exceeded the maximum number of domain names allowed in this Watchlist'); + } + + $userWatchLists = $user->getWatchLists(); + + /** @var Domain[] $trackedDomains */ + $trackedDomains = $userWatchLists->reduce(fn (array $acc, WatchList $watchList) => [...$acc, ...$watchList->getDomains()->toArray()], []); + + /** @var Domain $domain */ + foreach ($watchList->getDomains()->getIterator() as $domain) { + if (in_array($domain, $trackedDomains)) { + $this->logger->notice('User {username} tried to update a watchlist with domain name {ldhName}. However, it is forbidden to register the same domain name twice with limited mode.', [ + 'username' => $user->getUserIdentifier(), + 'ldhName' => $domain->getLdhName(), + ]); + + throw new AccessDeniedHttpException('It is forbidden to register the same domain name twice in your watchlists with limited mode.'); + } + } + } $this->logger->info('User {username} updates a Watchlist ({token}).', [ 'username' => $user->getUserIdentifier(), From f3ee662ea323ebc4ddb3369eb316f7d79ee02a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 03:50:29 +0200 Subject: [PATCH 031/257] fix: update watchlist limitations --- src/Controller/WatchListController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index 9ce9296..c1d07a2 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -160,7 +160,9 @@ class WatchListController extends AbstractController $userWatchLists = $user->getWatchLists(); /** @var Domain[] $trackedDomains */ - $trackedDomains = $userWatchLists->reduce(fn (array $acc, WatchList $watchList) => [...$acc, ...$watchList->getDomains()->toArray()], []); + $trackedDomains = $userWatchLists + ->filter(fn (WatchList $wl) => $wl !== $watchList) + ->reduce(fn (array $acc, WatchList $wl) => [...$acc, ...$wl->getDomains()->toArray()], []); /** @var Domain $domain */ foreach ($watchList->getDomains()->getIterator() as $domain) { From b9d2241ed1d93240b46c52028ab95fffef8fb1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 04:06:35 +0200 Subject: [PATCH 032/257] fix: update watchlist form --- assets/components/tracking/WatchlistsList.tsx | 11 +++++++---- assets/pages/tracking/WatchlistPage.tsx | 8 +++----- assets/utils/api/watchlist.ts | 2 +- src/Controller/WatchListController.php | 8 ++++---- src/Entity/DomainEvent.php | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/WatchlistsList.tsx index 0b42862..9415d72 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/WatchlistsList.tsx @@ -15,7 +15,7 @@ const {useToken} = theme; export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connectors}: { watchlists: Watchlist[], onDelete: () => void, - onUpdateWatchlist: (values: { domains: string[], emailTriggers: string[], token: string }) => void, + onUpdateWatchlist: (values: { domains: string[], emailTriggers: string[], token: string }) => Promise, connectors: (Connector & { id: string })[] }) { const {token} = useToken() @@ -34,7 +34,8 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect } ] - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false) + const [loading, setLoading] = useState(false) const showDrawer = () => { setOpen(true) @@ -42,6 +43,7 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect const onClose = () => { setOpen(false) + setLoading(false) }; return <> @@ -85,6 +87,7 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect width='80%' onClose={onClose} open={open} + loading={loading} styles={{ body: { paddingBottom: 80, @@ -95,8 +98,8 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect { - onUpdateWatchlist(values); - onClose() + setLoading(true) + onUpdateWatchlist(values).then(onClose).catch(() => setLoading(false)) }} connectors={connectors} isCreation={false} diff --git a/assets/pages/tracking/WatchlistPage.tsx b/assets/pages/tracking/WatchlistPage.tsx index 40b0762..c260c85 100644 --- a/assets/pages/tracking/WatchlistPage.tsx +++ b/assets/pages/tracking/WatchlistPage.tsx @@ -50,7 +50,7 @@ export default function WatchlistPage() { }) } - const onUpdateWatchlist = (values: { + const onUpdateWatchlist = async (values: { token: string name?: string domains: string[], @@ -59,9 +59,7 @@ export default function WatchlistPage() { }) => { const domainsURI = values.domains.map(d => '/api/domains/' + d) - console.log(values) - - putWatchlist({ + return putWatchlist({ token: values.token, name: values.name, domains: domainsURI, @@ -71,7 +69,7 @@ export default function WatchlistPage() { refreshWatchlists() messageApi.success(t`Watchlist updated !`) }).catch((e: AxiosError) => { - showErrorAPI(e, messageApi) + throw showErrorAPI(e, messageApi) }) } diff --git a/assets/utils/api/watchlist.ts b/assets/utils/api/watchlist.ts index ec0d55d..bed3164 100644 --- a/assets/utils/api/watchlist.ts +++ b/assets/utils/api/watchlist.ts @@ -1,4 +1,4 @@ -import {Event, request, Watchlist} from "./index"; +import {request, Watchlist} from "./index"; export async function getWatchlists() { const response = await request({ diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index c1d07a2..83f0bd0 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -70,7 +70,7 @@ class WatchListController extends AbstractController * This policy guarantees the equal probability of obtaining a domain name if it is requested by several users. */ if ($this->getParameter('limited_features')) { - if ($watchList->getDomains()->count() >= (int) $this->getParameter('limit_max_watchlist_domains')) { + if ($watchList->getDomains()->count() > (int) $this->getParameter('limit_max_watchlist_domains')) { $this->logger->notice('User {username} tried to create a Watchlist. However, the maximum number of domains has been reached for this Watchlist', [ 'username' => $user->getUserIdentifier(), ]); @@ -78,7 +78,7 @@ class WatchListController extends AbstractController } $userWatchLists = $user->getWatchLists(); - if ($userWatchLists->count() >= (int) $this->getParameter('limit_max_watchlist')) { + if ($userWatchLists->count() > (int) $this->getParameter('limit_max_watchlist')) { $this->logger->notice('User {username} tried to create a Watchlist. However, the maximum number of Watchlists has been reached.', [ 'username' => $user->getUserIdentifier(), ]); @@ -150,7 +150,7 @@ class WatchListController extends AbstractController $watchList->setUser($user); if ($this->getParameter('limited_features')) { - if ($watchList->getDomains()->count() >= (int) $this->getParameter('limit_max_watchlist_domains')) { + if ($watchList->getDomains()->count() > (int) $this->getParameter('limit_max_watchlist_domains')) { $this->logger->notice('User {username} tried to update a Watchlist. However, the maximum number of domains has been reached for this Watchlist', [ 'username' => $user->getUserIdentifier(), ]); @@ -161,7 +161,7 @@ class WatchListController extends AbstractController /** @var Domain[] $trackedDomains */ $trackedDomains = $userWatchLists - ->filter(fn (WatchList $wl) => $wl !== $watchList) + ->filter(fn (WatchList $wl) => $wl->getToken() !== $watchList->getToken()) ->reduce(fn (array $acc, WatchList $wl) => [...$acc, ...$wl->getDomains()->toArray()], []); /** @var Domain $domain */ diff --git a/src/Entity/DomainEvent.php b/src/Entity/DomainEvent.php index 7dfe1f0..4648dff 100644 --- a/src/Entity/DomainEvent.php +++ b/src/Entity/DomainEvent.php @@ -8,7 +8,7 @@ use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: DomainEventRepository::class)] class DomainEvent extends Event { - #[ORM\ManyToOne(targetEntity: Domain::class, cascade: ['persist'], inversedBy: 'events')] + #[ORM\ManyToOne(targetEntity: Domain::class, inversedBy: 'events')] #[ORM\JoinColumn(referencedColumnName: 'ldh_name', nullable: false)] private ?Domain $domain = null; From 8045848d5e2bf54c7108ce3dac78ee224ce5685b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 01:57:43 +0000 Subject: [PATCH 033/257] Translated using Weblate (French) Currently translated at 100.0% (132 of 132 strings) --- translations/fr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/fr.po b/translations/fr.po index 94f5666..61b0d21 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-15 01:17+0000\n" +"PO-Revision-Date: 2024-08-15 02:07+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: French \n" @@ -196,7 +196,7 @@ msgstr "Créer" #: assets/components/tracking/WatchlistForm.tsx:192 msgid "Update" -msgstr "Mise à jour" +msgstr "Mettre à jour" #: assets/components/tracking/ConnectorForm.tsx:179 #: assets/components/tracking/WatchlistForm.tsx:195 From 52fc96d036d65326d86ec6f01f75275496974319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 04:07:33 +0200 Subject: [PATCH 034/257] chore: update translations.pot --- translations/translations.pot | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/translations/translations.pot b/translations/translations.pot index 475d4b0..a26d55d 100644 --- a/translations/translations.pot +++ b/translations/translations.pot @@ -265,42 +265,42 @@ msgid "" "the Provider's API" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:59 msgid "This Watchlist is not linked to a Connector." msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:62 msgid "Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:68 +#: assets/components/tracking/WatchlistsList.tsx:70 msgid "Export events to iCalendar format" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:71 +#: assets/components/tracking/WatchlistsList.tsx:73 msgid "Edit the Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:84 +#: assets/components/tracking/WatchlistsList.tsx:86 msgid "Update a Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:107 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:117 msgid "Delete the Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:108 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "Are you sure to delete this Watchlist?" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:113 msgid "Yes" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "No" msgstr "" @@ -509,11 +509,11 @@ msgstr "" msgid "Watchlist created !" msgstr "" -#: assets/pages/tracking/WatchlistPage.tsx:72 +#: assets/pages/tracking/WatchlistPage.tsx:70 msgid "Watchlist updated !" msgstr "" -#: assets/pages/tracking/WatchlistPage.tsx:98 +#: assets/pages/tracking/WatchlistPage.tsx:96 msgid "Create a Watchlist" msgstr "" From 64bc4ac1725b930eafe7c319a7833496ab62c48a Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 15 Aug 2024 02:07:57 +0000 Subject: [PATCH 035/257] Update translation files Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate. --- translations/de.po | 24 ++++++++++++------------ translations/fr.po | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/translations/de.po b/translations/de.po index fd995c4..c42e1c9 100644 --- a/translations/de.po +++ b/translations/de.po @@ -280,42 +280,42 @@ msgstr "" "Ich verzichte auf mein Widerrufsrecht beim Kauf von Domainnamen über die API " "des Anbieters" -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:59 msgid "This Watchlist is not linked to a Connector." msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:62 msgid "Watchlist" msgstr "Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:68 +#: assets/components/tracking/WatchlistsList.tsx:70 msgid "Export events to iCalendar format" msgstr "Ereignisse in das iCalendar-Format exportieren" -#: assets/components/tracking/WatchlistsList.tsx:71 +#: assets/components/tracking/WatchlistsList.tsx:73 msgid "Edit the Watchlist" msgstr "Bearbeiten der Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:84 +#: assets/components/tracking/WatchlistsList.tsx:86 msgid "Update a Watchlist" msgstr "Aktualisieren einer Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:107 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:117 msgid "Delete the Watchlist" msgstr "Löschen der Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:108 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "Are you sure to delete this Watchlist?" msgstr "Möchten Sie diese Watchlist wirklich löschen?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:113 msgid "Yes" msgstr "Ja" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "No" msgstr "Nein" @@ -542,11 +542,11 @@ msgstr "Erstellen eines Connectors" msgid "Watchlist created !" msgstr "Watchlist erstellt !" -#: assets/pages/tracking/WatchlistPage.tsx:72 +#: assets/pages/tracking/WatchlistPage.tsx:70 msgid "Watchlist updated !" msgstr "Watchlist aktualisiert !" -#: assets/pages/tracking/WatchlistPage.tsx:98 +#: assets/pages/tracking/WatchlistPage.tsx:96 msgid "Create a Watchlist" msgstr "Erstellen Sie eine Watchlist" diff --git a/translations/fr.po b/translations/fr.po index 61b0d21..699f25c 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -280,42 +280,42 @@ msgstr "" "Je renonce expressément à mon droit de rétractation concernant l'achat de " "noms de domaine via l'API du Fournisseur" -#: assets/components/tracking/WatchlistsList.tsx:57 +#: assets/components/tracking/WatchlistsList.tsx:59 msgid "This Watchlist is not linked to a Connector." msgstr "Cette Watchlist n'est pas liée à un connecteur." -#: assets/components/tracking/WatchlistsList.tsx:60 +#: assets/components/tracking/WatchlistsList.tsx:62 msgid "Watchlist" msgstr "Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:68 +#: assets/components/tracking/WatchlistsList.tsx:70 msgid "Export events to iCalendar format" msgstr "Exporter les événements au format iCalendar" -#: assets/components/tracking/WatchlistsList.tsx:71 +#: assets/components/tracking/WatchlistsList.tsx:73 msgid "Edit the Watchlist" msgstr "Modifier la Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:84 +#: assets/components/tracking/WatchlistsList.tsx:86 msgid "Update a Watchlist" msgstr "Mise à jour d'une Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:107 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:117 msgid "Delete the Watchlist" msgstr "Supprimer la Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:108 +#: assets/components/tracking/WatchlistsList.tsx:111 msgid "Are you sure to delete this Watchlist?" msgstr "Êtes-vous sûr de vouloir supprimer cette Watchlist ?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:110 +#: assets/components/tracking/WatchlistsList.tsx:113 msgid "Yes" msgstr "Oui" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/WatchlistsList.tsx:114 msgid "No" msgstr "Non" @@ -541,11 +541,11 @@ msgstr "Créer un Connecteur" msgid "Watchlist created !" msgstr "Watchlist créée !" -#: assets/pages/tracking/WatchlistPage.tsx:72 +#: assets/pages/tracking/WatchlistPage.tsx:70 msgid "Watchlist updated !" msgstr "Watchlist mise à jour !" -#: assets/pages/tracking/WatchlistPage.tsx:98 +#: assets/pages/tracking/WatchlistPage.tsx:96 msgid "Create a Watchlist" msgstr "Créer une Watchlist" From 34c7c9cdb4e06c3761510935f59d96a9d5cf43c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 04:12:38 +0200 Subject: [PATCH 036/257] fix: correct limitations --- src/Controller/WatchListController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index 83f0bd0..ecc2fc7 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -78,7 +78,7 @@ class WatchListController extends AbstractController } $userWatchLists = $user->getWatchLists(); - if ($userWatchLists->count() > (int) $this->getParameter('limit_max_watchlist')) { + if ($userWatchLists->count() >= (int) $this->getParameter('limit_max_watchlist')) { $this->logger->notice('User {username} tried to create a Watchlist. However, the maximum number of Watchlists has been reached.', [ 'username' => $user->getUserIdentifier(), ]); From fb43f6bdb07a609cd206d7dc24945aa76b72f7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 17:40:09 +0200 Subject: [PATCH 037/257] chore: translate Close button --- assets/components/tracking/WatchlistsList.tsx | 6 +++--- translations/translations.pot | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/WatchlistsList.tsx index 9415d72..ba32b8a 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/WatchlistsList.tsx @@ -39,12 +39,12 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect const showDrawer = () => { setOpen(true) - }; + } const onClose = () => { setOpen(false) setLoading(false) - }; + } return <> {watchlists.map(watchlist => @@ -93,7 +93,7 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect paddingBottom: 80, } }} - extra={} + extra={} > Date: Thu, 15 Aug 2024 15:40:48 +0000 Subject: [PATCH 038/257] Update translation files Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate. --- translations/de.po | 4 ++++ translations/fr.po | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/translations/de.po b/translations/de.po index c42e1c9..3c995ea 100644 --- a/translations/de.po +++ b/translations/de.po @@ -300,6 +300,10 @@ msgstr "Bearbeiten der Watchlist" msgid "Update a Watchlist" msgstr "Aktualisieren einer Watchlist" +#: assets/components/tracking/WatchlistsList.tsx:96 +msgid "Cancel" +msgstr "" + #: assets/components/tracking/WatchlistsList.tsx:110 #: assets/components/tracking/WatchlistsList.tsx:117 msgid "Delete the Watchlist" diff --git a/translations/fr.po b/translations/fr.po index 699f25c..035bcac 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -300,6 +300,10 @@ msgstr "Modifier la Watchlist" msgid "Update a Watchlist" msgstr "Mise à jour d'une Watchlist" +#: assets/components/tracking/WatchlistsList.tsx:96 +msgid "Cancel" +msgstr "" + #: assets/components/tracking/WatchlistsList.tsx:110 #: assets/components/tracking/WatchlistsList.tsx:117 msgid "Delete the Watchlist" From c989478144873705f5fbc5af64f1fd15222bf8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 17:46:32 +0200 Subject: [PATCH 039/257] docs: fix content typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maël Gangloff --- INSTALL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 888f083..ff64662 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -67,10 +67,10 @@ git clone https://github.com/maelgangloff/domain-watchdog.git ``` 4. Add and modify the following files as you wish: ~~~ - public/contents/home.md - public/contents/privacy.md - public/contents/tos.md - public/contents/faq.md + public/content/home.md + public/content/privacy.md + public/content/tos.md + public/content/faq.md public/images/icons-512.png public/images/banner.png public/favicon.ico From f34c1a5d7e808aa67b7f8cef4a9796f410cc3100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 18:14:01 +0200 Subject: [PATCH 040/257] fix: generate JWT keys on first launch --- frankenphp/docker-entrypoint.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh index 9823560..189968b 100755 --- a/frankenphp/docker-entrypoint.sh +++ b/frankenphp/docker-entrypoint.sh @@ -53,6 +53,8 @@ if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then fi fi + php bin/console lexik:jwt:generate-keypair || true + setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var fi From 95f724f5b4bf84c046290c645bfde28e4a21b079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 15:41:29 +0000 Subject: [PATCH 041/257] Translated using Weblate (French) Currently translated at 100.0% (133 of 133 strings) --- translations/fr.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/fr.po b/translations/fr.po index 035bcac..e2db367 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-15 02:07+0000\n" +"PO-Revision-Date: 2024-08-15 16:16+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: French \n" @@ -302,7 +302,7 @@ msgstr "Mise à jour d'une Watchlist" #: assets/components/tracking/WatchlistsList.tsx:96 msgid "Cancel" -msgstr "" +msgstr "Annuler" #: assets/components/tracking/WatchlistsList.tsx:110 #: assets/components/tracking/WatchlistsList.tsx:117 From 29f4a756d36c1c35a6292dbca39d5934db7f1b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 15:42:01 +0000 Subject: [PATCH 042/257] Translated using Weblate (German) Currently translated at 100.0% (133 of 133 strings) --- translations/de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/de.po b/translations/de.po index 3c995ea..9b37d10 100644 --- a/translations/de.po +++ b/translations/de.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-15 01:17+0000\n" +"PO-Revision-Date: 2024-08-15 16:16+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: German \n" @@ -302,7 +302,7 @@ msgstr "Aktualisieren einer Watchlist" #: assets/components/tracking/WatchlistsList.tsx:96 msgid "Cancel" -msgstr "" +msgstr "Abbrechen" #: assets/components/tracking/WatchlistsList.tsx:110 #: assets/components/tracking/WatchlistsList.tsx:117 From 5ab099d8751a81b5ed61df574b3f8db2ab7a3813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 18:48:47 +0200 Subject: [PATCH 043/257] fix: instantiate DB on first launch with Docker --- compose.prod.yaml | 7 +++++++ frankenphp/docker-entrypoint.sh | 1 + 2 files changed, 8 insertions(+) diff --git a/compose.prod.yaml b/compose.prod.yaml index d49a419..5220ceb 100644 --- a/compose.prod.yaml +++ b/compose.prod.yaml @@ -6,3 +6,10 @@ services: target: frankenphp_prod environment: APP_SECRET: ${APP_SECRET} + + php-worker: + build: + context: . + target: frankenphp_prod + restart: always + command: php /app/bin/console messenger:consume --all --time-limit=3600 -vvv diff --git a/frankenphp/docker-entrypoint.sh b/frankenphp/docker-entrypoint.sh index 189968b..a2931f2 100755 --- a/frankenphp/docker-entrypoint.sh +++ b/frankenphp/docker-entrypoint.sh @@ -54,6 +54,7 @@ if [ "$1" = 'frankenphp' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then fi php bin/console lexik:jwt:generate-keypair || true + php bin/console app:update-rdap-servers setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX var setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX var From 0bb41156496e9947595ecc6ae3279e4284c69317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 19:31:32 +0200 Subject: [PATCH 044/257] chore: add time to JWT tokens so they expire less often --- config/packages/lexik_jwt_authentication.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/packages/lexik_jwt_authentication.yaml b/config/packages/lexik_jwt_authentication.yaml index 6c34ca2..9cfe282 100644 --- a/config/packages/lexik_jwt_authentication.yaml +++ b/config/packages/lexik_jwt_authentication.yaml @@ -2,7 +2,7 @@ lexik_jwt_authentication: secret_key: '%env(resolve:JWT_SECRET_KEY)%' public_key: '%env(resolve:JWT_PUBLIC_KEY)%' pass_phrase: '%env(JWT_PASSPHRASE)%' - token_ttl: 7200 # in seconds, default is 3600 + token_ttl: 604800 # in seconds, default is 3600 token_extractors: authorization_header: enabled: true From 31b136ec92bcf7ac1c0b5c7dacad2950d7f2b29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 19:54:36 +0200 Subject: [PATCH 045/257] fix: unknown entity logging --- src/Service/RDAPService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service/RDAPService.php b/src/Service/RDAPService.php index 60a6126..c917ff5 100644 --- a/src/Service/RDAPService.php +++ b/src/Service/RDAPService.php @@ -364,7 +364,7 @@ readonly class RDAPService if (null === $entity) { $entity = new Entity(); - } else { + $this->logger->info('The entity {handle} was not known to this Domain Watchdog instance.', [ 'handle' => $rdapEntity['handle'], ]); From d0d13a07a953c7b6286aceb6850fde23da0b4a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Thu, 15 Aug 2024 22:58:15 +0200 Subject: [PATCH 046/257] refactor: split button components --- .../tracking/DeleteWatchlistButton.tsx | 22 +++++ .../tracking/UpdateWatchlistButton.tsx | 67 ++++++++++++++ .../tracking/ViewDiagramWatchlistButton.tsx | 40 +++++++++ assets/components/tracking/WatchlistsList.tsx | 88 +++++-------------- 4 files changed, 149 insertions(+), 68 deletions(-) create mode 100644 assets/components/tracking/DeleteWatchlistButton.tsx create mode 100644 assets/components/tracking/UpdateWatchlistButton.tsx create mode 100644 assets/components/tracking/ViewDiagramWatchlistButton.tsx diff --git a/assets/components/tracking/DeleteWatchlistButton.tsx b/assets/components/tracking/DeleteWatchlistButton.tsx new file mode 100644 index 0000000..cecac54 --- /dev/null +++ b/assets/components/tracking/DeleteWatchlistButton.tsx @@ -0,0 +1,22 @@ +import {Popconfirm, theme, Typography} from "antd"; +import {t} from "ttag"; +import {deleteWatchlist} from "../../utils/api"; +import {DeleteFilled} from "@ant-design/icons"; +import React from "react"; +import {Watchlist} from "../../pages/tracking/WatchlistPage"; + +export function DeleteWatchlistButton({watchlist, onDelete}: { watchlist: Watchlist, onDelete: () => void }) { + const {token} = theme.useToken() + + return deleteWatchlist(watchlist.token).then(onDelete)} + okText={t`Yes`} + cancelText={t`No`} + okButtonProps={{danger: true}}> + + + + +} \ No newline at end of file diff --git a/assets/components/tracking/UpdateWatchlistButton.tsx b/assets/components/tracking/UpdateWatchlistButton.tsx new file mode 100644 index 0000000..7e3686d --- /dev/null +++ b/assets/components/tracking/UpdateWatchlistButton.tsx @@ -0,0 +1,67 @@ +import {Button, Drawer, Form, Typography} from "antd"; +import {t} from "ttag"; +import {WatchlistForm} from "./WatchlistForm"; +import React, {useState} from "react"; +import {Watchlist} from "../../pages/tracking/WatchlistPage"; +import {EditOutlined} from "@ant-design/icons"; +import {Connector} from "../../utils/api/connectors"; + +export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors}: { + watchlist: Watchlist, + onUpdateWatchlist: (values: { domains: string[], emailTriggers: string[], token: string }) => Promise, + connectors: (Connector & { id: string })[] +}) { + + const [form] = Form.useForm() + const [open, setOpen] = useState(false) + const [loading, setLoading] = useState(false) + + + const showDrawer = () => { + setOpen(true) + } + + const onClose = () => { + setOpen(false) + setLoading(false) + } + + return <> + + { + showDrawer() + form.setFields([ + {name: 'token', value: watchlist.token}, + {name: 'name', value: watchlist.name}, + {name: 'connector', value: watchlist.connector?.id}, + {name: 'domains', value: watchlist.domains.map(d => d.ldhName)}, + {name: 'emailTriggers', value: watchlist.triggers?.map(t => t.event)}, + ]) + }}/> + + {t`Cancel`}} + > + { + setLoading(true) + onUpdateWatchlist(values).then(onClose).catch(() => setLoading(false)) + }} + connectors={connectors} + isCreation={false} + /> + + + +} \ No newline at end of file diff --git a/assets/components/tracking/ViewDiagramWatchlistButton.tsx b/assets/components/tracking/ViewDiagramWatchlistButton.tsx new file mode 100644 index 0000000..241f6ad --- /dev/null +++ b/assets/components/tracking/ViewDiagramWatchlistButton.tsx @@ -0,0 +1,40 @@ +import {Button, Modal, Space, Typography} from "antd" +import {t} from "ttag" +import React, {useState} from "react" +import {Watchlist} from "../../pages/tracking/WatchlistPage" +import {ApartmentOutlined} from "@ant-design/icons" + +export function ViewDiagramWatchlistButton({watchlist}: { watchlist: Watchlist }) { + const [open, setOpen] = useState(false) + + return <> + + setOpen(true)}/> + + + + + + + } + onOk={() => setOpen(false)} + onCancel={() => setOpen(false)} + width='80%' + > + + + + +} \ No newline at end of file diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/WatchlistsList.tsx index ba32b8a..1d36b04 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/WatchlistsList.tsx @@ -1,16 +1,15 @@ -import {Button, Card, Divider, Drawer, Form, Popconfirm, Space, Table, Tag, theme, Typography} from "antd"; +import {Card, Divider, Space, Table, Tag, Typography} from "antd"; import {t} from "ttag"; -import {deleteWatchlist} from "../../utils/api"; -import {CalendarFilled, DeleteFilled, DisconnectOutlined, EditOutlined, LinkOutlined} from "@ant-design/icons"; -import React, {useState} from "react"; +import {CalendarFilled, DisconnectOutlined, LinkOutlined} from "@ant-design/icons"; +import React from "react"; import useBreakpoint from "../../hooks/useBreakpoint"; import {actionToColor, domainEvent} from "../search/EventTimeline"; import {Watchlist} from "../../pages/tracking/WatchlistPage"; import punycode from "punycode/punycode"; -import {WatchlistForm} from "./WatchlistForm"; import {Connector} from "../../utils/api/connectors"; - -const {useToken} = theme; +import {UpdateWatchlistButton} from "./UpdateWatchlistButton"; +import {DeleteWatchlistButton} from "./DeleteWatchlistButton"; +import {ViewDiagramWatchlistButton} from "./ViewDiagramWatchlistButton"; export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connectors}: { watchlists: Watchlist[], @@ -18,10 +17,9 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect onUpdateWatchlist: (values: { domains: string[], emailTriggers: string[], token: string }) => Promise, connectors: (Connector & { id: string })[] }) { - const {token} = useToken() const sm = useBreakpoint('sm') const domainEventTranslated = domainEvent() - const [form] = Form.useForm() + const columns = [ { @@ -34,17 +32,6 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect } ] - const [open, setOpen] = useState(false) - const [loading, setLoading] = useState(false) - - const showDrawer = () => { - setOpen(true) - } - - const onClose = () => { - setOpen(false) - setLoading(false) - } return <> {watchlists.map(watchlist => @@ -66,57 +53,22 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect size='small' style={{width: '100%'}} extra={ - - - - - { - showDrawer() - form.setFields([ - {name: 'token', value: watchlist.token}, - {name: 'name', value: watchlist.name}, - {name: 'connector', value: watchlist.connector?.id}, - {name: 'domains', value: watchlist.domains.map(d => d.ldhName)}, - {name: 'emailTriggers', value: watchlist.triggers?.map(t => t.event)}, - ]) - }}/> + + + + + - {t`Cancel`}} - > - { - setLoading(true) - onUpdateWatchlist(values).then(onClose).catch(() => setLoading(false)) - }} - connectors={connectors} - isCreation={false} - /> - + + + - deleteWatchlist(watchlist.token).then(onDelete)} - okText={t`Yes`} - cancelText={t`No`} - okButtonProps={{danger: true}}> - - - - } > From 50b76c8438842ac0617705226f20c9b93536f091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 03:54:48 +0200 Subject: [PATCH 047/257] feat: add watchlist entity diagram --- .../tracking/ViewDiagramWatchlistButton.tsx | 138 +++- assets/components/tracking/WatchlistsList.tsx | 2 +- assets/utils/api/index.ts | 11 +- assets/utils/api/watchlist.ts | 10 +- package.json | 6 +- translations/translations.pot | 52 +- yarn.lock | 695 +++++------------- 7 files changed, 345 insertions(+), 569 deletions(-) diff --git a/assets/components/tracking/ViewDiagramWatchlistButton.tsx b/assets/components/tracking/ViewDiagramWatchlistButton.tsx index 241f6ad..5579ef2 100644 --- a/assets/components/tracking/ViewDiagramWatchlistButton.tsx +++ b/assets/components/tracking/ViewDiagramWatchlistButton.tsx @@ -1,12 +1,119 @@ -import {Button, Modal, Space, Typography} from "antd" +import {Button, Flex, Modal, Space, Typography} from "antd" import {t} from "ttag" -import React, {useState} from "react" -import {Watchlist} from "../../pages/tracking/WatchlistPage" +import React, {useEffect, useState} from "react" import {ApartmentOutlined} from "@ant-design/icons" -export function ViewDiagramWatchlistButton({watchlist}: { watchlist: Watchlist }) { +import '@xyflow/react/dist/style.css' +import {Background, Controls, MiniMap, ReactFlow, useEdgesState, useNodesState} from "@xyflow/react"; +import {getWatchlist, Watchlist} from "../../utils/api"; + +import dagre from 'dagre' +import vCard from "vcf"; + +const dagreGraph = new dagre.graphlib.Graph(); +dagreGraph.setDefaultEdgeLabel(() => ({})); + +const nodeWidth = 172; +const nodeHeight = 200; + +const getLayoutedElements = (nodes: any, edges: any, direction = 'TB') => { + const isHorizontal = direction === 'LR'; + dagreGraph.setGraph({rankdir: direction}); + + nodes.forEach((node: any) => { + dagreGraph.setNode(node.id, {width: nodeWidth, height: nodeHeight}); + }); + + edges.forEach((edge: any) => { + dagreGraph.setEdge(edge.source, edge.target); + }); + + dagre.layout(dagreGraph); + + const newNodes = nodes.map((node: any) => { + const nodeWithPosition = dagreGraph.node(node.id) + + return { + ...node, + targetPosition: isHorizontal ? 'left' : 'top', + sourcePosition: isHorizontal ? 'right' : 'bottom', + position: { + x: nodeWithPosition.x - nodeWidth / 2, + y: nodeWithPosition.y - nodeHeight / 2 + }, + }; + }); + + return {nodes: newNodes, edges}; +} + + +function watchlistToNodes(watchlist: Watchlist) { + const domains = watchlist.domains.map(d => ({ + id: d.ldhName, + data: {label: {d.ldhName}}, + style: { + width: 200 + } + })) + const entities = [...new Set(watchlist.domains + .map(d => d.entities + .filter(e => !e.roles.includes('registrar')) + .map(e => e.entity + ) + ).flat())].map(e => { + const jCard = vCard.fromJSON(e.jCard) + let label = e.handle + if (jCard.data.fn !== undefined && !Array.isArray(jCard.data.fn)) label = jCard.data.fn.valueOf() + + return { + id: e.handle, + data: {label}, + style: { + width: 200 + } + } + }) + + return [...domains, ...entities] +} + +const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' : + roles.includes('technical') ? 'orange' : 'black' + +function watchlistToEdges(watchlist: Watchlist) { + return watchlist.domains + .map(d => d.entities + .filter(e => !e.roles.includes('registrar')) + .map(e => ({ + id: `${d.ldhName}-${e.entity.handle}`, + source: e.roles.includes('technical') ? d.ldhName : e.entity.handle, + target: e.roles.includes('technical') ? e.entity.handle : d.ldhName, + style: {stroke: rolesToColor(e.roles), strokeWidth: 3}, + animated: e.roles.includes('registrant'), + })) + ).flat(2) +} + +export function ViewDiagramWatchlistButton({token}: { token: string }) { const [open, setOpen] = useState(false) + const [loading, setLoading] = useState(false) + const [nodes, setNodes, onNodesChange] = useNodesState([]); + const [edges, setEdges, onEdgesChange] = useEdgesState([]); + + useEffect(() => { + if (!open) return + setLoading(true) + getWatchlist(token).then(w => { + const e = getLayoutedElements(watchlistToNodes(w), watchlistToEdges(w)) + setNodes(e.nodes) + setEdges(e.edges) + }).catch(() => setOpen(false)).finally(() => setLoading(false)) + + }, [open]) + + return <> - - @@ -31,10 +134,21 @@ export function ViewDiagramWatchlistButton({watchlist}: { watchlist: Watchlist } } onOk={() => setOpen(false)} onCancel={() => setOpen(false)} - width='80%' + width='80vw' > - + {nodes && edges && + + + + + + } - } \ No newline at end of file diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/WatchlistsList.tsx index 1d36b04..e6b39e5 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/WatchlistsList.tsx @@ -54,7 +54,7 @@ export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connect style={{width: '100%'}} extra={ - + ({ + const response = await request({ url: 'watchlists/' + token }) return response.data } -export async function postWatchlist(watchlist: Watchlist) { +export async function postWatchlist(watchlist: WatchlistRequest) { const response = await request<{ token: string }>({ method: 'POST', url: 'watchlists', @@ -33,8 +33,8 @@ export async function deleteWatchlist(token: string): Promise { }) } -export async function putWatchlist(watchlist: Partial & { token: string }) { - const response = await request({ +export async function putWatchlist(watchlist: Partial & { token: string }) { + const response = await request({ method: 'PUT', url: 'watchlists/' + watchlist.token, data: watchlist, diff --git a/package.json b/package.json index b4d3eed..e79cb1c 100644 --- a/package.json +++ b/package.json @@ -21,15 +21,18 @@ "@fontsource/noto-color-emoji": "^5.0.27", "@symfony/webpack-encore": "^4.0.0", "@types/axios": "^0.14.0", + "@types/dagre": "^0.7.52", "@types/jsonld": "^1.5.15", "@types/punycode": "^2.1.4", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/react-responsive": "^8.0.8", "@types/vcf": "^2.0.7", + "@xyflow/react": "^12.1.0", "antd": "^5.19.3", "axios": "^1.7.2", "core-js": "^3.23.0", + "dagre": "^0.8.5", "html-loader": "^5.1.0", "jsonld": "^8.3.2", "punycode": "^2.3.1", @@ -57,8 +60,5 @@ "build": "encore production --progress", "ttag:po2json": "cd translations; for i in $(find . -name \"*.po\"); do ttag po2json $i > ../public/locales/$i.json; done; cd ..", "ttag:extract": "ttag extract $(find assets -name '*.ts' -or -name '*.tsx') -o translations/translations.pot" - }, - "dependencies": { - "remove": "^0.1.5" } } diff --git a/translations/translations.pot b/translations/translations.pot index e61fe64..2bd1eea 100644 --- a/translations/translations.pot +++ b/translations/translations.pot @@ -149,7 +149,7 @@ msgid "At least one domain name" msgstr "" #: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:28 +#: assets/components/tracking/WatchlistsList.tsx:26 msgid "Domain names" msgstr "" @@ -162,7 +162,7 @@ msgid "Add a Domain name" msgstr "" #: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:32 +#: assets/components/tracking/WatchlistsList.tsx:30 msgid "Tracked events" msgstr "" @@ -195,6 +195,14 @@ msgstr "" msgid "Reset" msgstr "" +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 +msgid "View the Watchlist Entity Diagram" +msgstr "" + +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 +msgid "Watchlist Entity Diagram" +msgstr "" + #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" msgstr "" @@ -265,49 +273,49 @@ msgid "" "the Provider's API" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:59 -msgid "This Watchlist is not linked to a Connector." -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:62 -msgid "Watchlist" -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:70 -msgid "Export events to iCalendar format" -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:73 +#: assets/components/tracking/UpdateWatchlistButton.tsx:31 msgid "Edit the Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:86 +#: assets/components/tracking/UpdateWatchlistButton.tsx:43 msgid "Update a Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:96 +#: assets/components/tracking/UpdateWatchlistButton.tsx:53 msgid "Cancel" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:110 -#: assets/components/tracking/WatchlistsList.tsx:117 +#: assets/components/tracking/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/DeleteWatchlistButton.tsx:19 msgid "Delete the Watchlist" msgstr "" -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/DeleteWatchlistButton.tsx:13 msgid "Are you sure to delete this Watchlist?" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:113 +#: assets/components/tracking/DeleteWatchlistButton.tsx:15 msgid "Yes" msgstr "" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/DeleteWatchlistButton.tsx:16 msgid "No" msgstr "" +#: assets/components/tracking/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "" + +#: assets/components/tracking/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "" + #: assets/components/tracking/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" diff --git a/yarn.lock b/yarn.lock index 7a8b554..58a60c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1738,6 +1738,50 @@ dependencies: "@types/node" "*" +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-drag@^3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02" + integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-interpolate@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-selection@*", "@types/d3-selection@^3.0.10": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe" + integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg== + +"@types/d3-transition@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f" + integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-zoom@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" + integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== + dependencies: + "@types/d3-interpolate" "*" + "@types/d3-selection" "*" + +"@types/dagre@^0.7.52": + version "0.7.52" + resolved "https://registry.yarnpkg.com/@types/dagre/-/dagre-0.7.52.tgz#edbf0bca6922cd0ad1936a7486f9d03523d7565a" + integrity sha512-XKJdy+OClLk3hketHi9Qg6gTfe1F3y+UFnHxKA2rn9Dw+oXa4Gb378Ztz9HlMgZKSxpPmn4BNVh9wgkpvrK1uw== + "@types/eslint-scope@^3.7.3": version "3.7.7" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" @@ -2116,6 +2160,28 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@xyflow/react@^12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@xyflow/react/-/react-12.1.0.tgz#71a93eb514497b0ae3835b45df21ac14ce6e0812" + integrity sha512-tlYBV8S27kTwLuKvKa3dX0yEJ6NgUup9BwXLWcdNKdZq+UvLfDr5JXHwzyRqT1XSlYFv+YgcfroGmir8krYXIg== + dependencies: + "@xyflow/system" "0.0.38" + classcat "^5.0.3" + zustand "^4.4.0" + +"@xyflow/system@0.0.38": + version "0.0.38" + resolved "https://registry.yarnpkg.com/@xyflow/system/-/system-0.0.38.tgz#4bf67fa1adfba5cd3760d182ce645841fc652c69" + integrity sha512-auJU8djbT59S5Afb9lFds1lQJvKIb0zUoHhO+il/ogDDG5BbFds6D8g5a8Q3oHdyR6dy0TaD1oZq9s7Ydhn41g== + dependencies: + "@types/d3-drag" "^3.0.7" + "@types/d3-selection" "^3.0.10" + "@types/d3-transition" "^3.0.8" + "@types/d3-zoom" "^3.0.8" + d3-drag "^3.0.0" + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -2294,14 +2360,6 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -2324,20 +2382,6 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -arraybuffer.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - assets-webpack-plugin@7.0.*: version "7.0.0" resolved "https://registry.yarnpkg.com/assets-webpack-plugin/-/assets-webpack-plugin-7.0.0.tgz#c61ed7466f35ff7a4d90d7070948736f471b8804" @@ -2352,13 +2396,6 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - axios@*, axios@^1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" @@ -2553,7 +2590,7 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: +call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -2607,13 +2644,6 @@ canonicalize@^1.0.1: resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.8.tgz#24d1f1a00ed202faafd9bf8e63352cd4450c6df1" integrity sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A== -"chainsaw@>=0.0.7 <0.1": - version "0.0.9" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.0.9.tgz#11a05102d1c4c785b6d0415d336d5a3a1612913e" - integrity sha512-nG8PYH+/4xB+8zkV4G844EtfvZ5tTiLFoX3dZ4nhF4t3OCKIb9UvaFyNmeZO2zOSmRWzBoTD+napN6hiL+EgcA== - dependencies: - traverse ">=0.3.0 <0.4" - chalk@^1.0.0, chalk@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -2667,6 +2697,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +classcat@^5.0.3: + version "5.0.5" + resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.5.tgz#8c209f359a93ac302404a10161b501eba9c09c77" + integrity sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w== + classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" @@ -3070,38 +3105,81 @@ csstype@^3.0.2, csstype@^3.1.3: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-ease@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-interpolate@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + +dagre@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee" + integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw== + dependencies: + graphlib "^2.1.8" + lodash "^4.17.15" + data-uri-to-buffer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== -data-view-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" - integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" - integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-data-view "^1.0.1" - -data-view-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" - integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-data-view "^1.0.1" - dayjs@^1.11.11: version "1.11.12" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.12.tgz#5245226cc7f40a15bf52e0b99fd2a04669ccac1d" @@ -3150,7 +3228,7 @@ default-gateway@^6.0.3: dependencies: execa "^5.0.0" -define-data-property@^1.0.1, define-data-property@^1.1.4: +define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -3164,15 +3242,6 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - del@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" @@ -3362,58 +3431,6 @@ error-stack-parser@^2.1.4: dependencies: stackframe "^1.3.4" -es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== - dependencies: - array-buffer-byte-length "^1.0.1" - arraybuffer.prototype.slice "^1.0.3" - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - data-view-buffer "^1.0.1" - data-view-byte-length "^1.0.1" - data-view-byte-offset "^1.0.0" - es-define-property "^1.0.0" - es-errors "^1.3.0" - es-object-atoms "^1.0.0" - es-set-tostringtag "^2.0.3" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.4" - get-symbol-description "^1.0.2" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - has-proto "^1.0.3" - has-symbols "^1.0.3" - hasown "^2.0.2" - internal-slot "^1.0.7" - is-array-buffer "^3.0.4" - is-callable "^1.2.7" - is-data-view "^1.0.1" - is-negative-zero "^2.0.3" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.3" - is-string "^1.0.7" - is-typed-array "^1.1.13" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" - safe-array-concat "^1.1.2" - safe-regex-test "^1.0.3" - string.prototype.trim "^1.2.9" - string.prototype.trimend "^1.0.8" - string.prototype.trimstart "^1.0.8" - typed-array-buffer "^1.0.2" - typed-array-byte-length "^1.0.1" - typed-array-byte-offset "^1.0.2" - typed-array-length "^1.0.6" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.15" - es-define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" @@ -3421,7 +3438,7 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" -es-errors@^1.2.1, es-errors@^1.3.0: +es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== @@ -3431,31 +3448,6 @@ es-module-lexer@^1.2.1: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== -es-object-atoms@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" - integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== - dependencies: - es-errors "^1.3.0" - -es-set-tostringtag@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" - integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== - dependencies: - get-intrinsic "^1.2.4" - has-tostringtag "^1.0.2" - hasown "^2.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - escalade@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" @@ -3691,13 +3683,6 @@ follow-redirects@^1.0.0, follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - foreachasync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6" @@ -3754,21 +3739,6 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -3779,7 +3749,7 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -3800,15 +3770,6 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - gettext-parser@6.0.0, gettext-parser@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gettext-parser/-/gettext-parser-6.0.0.tgz#201e61d92c1cc7edf8f6ee3a7e3d6ab1e061b44c" @@ -3848,14 +3809,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globalthis@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" - integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== - dependencies: - define-properties "^1.2.1" - gopd "^1.0.1" - globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -3879,6 +3832,13 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphlib@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" + integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== + dependencies: + lodash "^4.17.15" + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -3896,11 +3856,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3911,38 +3866,31 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1, has-proto@^1.0.3: +has-proto@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== -has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" -"hashish@>=0.0.2 <0.1": - version "0.0.4" - resolved "https://registry.yarnpkg.com/hashish/-/hashish-0.0.4.tgz#6d60bc6ffaf711b6afd60e426d077988014e6554" - integrity sha512-xyD4XgslstNAs72ENaoFvgMwtv8xhiDtC2AtzCG+8yF7W/Knxxm9BX+e2s25mm+HxMKh0rBmXVOEGF3zNImXvA== - dependencies: - traverse ">=0.2.4" - -hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -4148,15 +4096,6 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -internal-slot@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -4172,26 +4111,11 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== -is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -4199,19 +4123,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-core-module@^2.13.0: version "2.15.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" @@ -4219,20 +4130,6 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.2" -is-data-view@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" - integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== - dependencies: - is-typed-array "^1.1.13" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -4262,18 +4159,6 @@ is-glob@^4.0.1, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-negative-zero@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" - integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4310,54 +4195,11 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" - integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== - dependencies: - call-bind "^1.0.7" - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" @@ -4370,11 +4212,6 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4634,7 +4471,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4921,21 +4758,6 @@ object-inspect@^1.13.1: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -5221,11 +5043,6 @@ plural-forms@^0.5.3: resolved "https://registry.yarnpkg.com/plural-forms/-/plural-forms-0.5.5.tgz#d15ca5597aff37373c97edc039ba11659461120e" integrity sha512-rJw4xp22izsfJOVqta5Hyvep2lR3xPkFUtj7dyQtpf/FbxUiX7PQCajTn2EHDRylizH5N/Uqqodfdu22I0ju+g== -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - postcss-calc@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-9.0.1.tgz#a744fd592438a93d6de0f1434c572670361eb6c6" @@ -6052,16 +5869,6 @@ regex-parser@^2.2.11: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.3.0.tgz#4bb61461b1a19b8b913f3960364bb57887f920ee" integrity sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg== -regexp.prototype.flags@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" - integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== - dependencies: - call-bind "^1.0.6" - define-properties "^1.2.1" - es-errors "^1.3.0" - set-function-name "^2.0.1" - regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" @@ -6086,13 +5893,6 @@ relateurl@^0.2.7: resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== -remove@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/remove/-/remove-0.1.5.tgz#095ffd827d65c9f41ad97d33e416a75811079955" - integrity sha512-AJMA9oWvJzdTjwIGwSQZsjGQiRx73YTmiOWmfCp1fpLa/D4n7jKcpoA+CZiVLJqKcEKUuh1Suq80c5wF+L/qVQ== - dependencies: - seq ">= 0.3.5" - renderkid@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" @@ -6193,16 +5993,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -safe-array-concat@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" - integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== - dependencies: - call-bind "^1.0.7" - get-intrinsic "^1.2.4" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -6213,15 +6003,6 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@^5.2.1, resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -6302,14 +6083,6 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -"seq@>= 0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/seq/-/seq-0.3.5.tgz#ae02af3a424793d8ccbf212d69174e0c54dffe38" - integrity sha512-sisY2Ln1fj43KBkRtXkesnRHYNdswIkIibvNe/0UKm2GZxjMbqmccpiatoKr/k2qX5VKiLU8xm+tz/74LAho4g== - dependencies: - chainsaw ">=0.0.7 <0.1" - hashish ">=0.0.2 <0.1" - serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -6364,16 +6137,6 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-function-name@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" - integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.2" - setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -6539,34 +6302,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trim@^1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" - integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-object-atoms "^1.0.0" - -string.prototype.trimend@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" - integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - -string.prototype.trimstart@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" - integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-object-atoms "^1.0.0" - string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -6749,20 +6484,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -traverse@>=0.2.4: - version "0.6.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.9.tgz#76cfdbacf06382d460b76f8b735a44a6209d8b81" - integrity sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg== - dependencies: - gopd "^1.0.1" - typedarray.prototype.slice "^1.0.3" - which-typed-array "^1.1.15" - -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== - ts-loader@^9.5.1: version "9.5.1" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" @@ -6843,77 +6564,11 @@ type-is@^1.6.14, type-is@^1.6.16, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typed-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" - integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" - integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-byte-offset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" - integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - -typed-array-length@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" - integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== - dependencies: - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-proto "^1.0.3" - is-typed-array "^1.1.13" - possible-typed-array-names "^1.0.0" - -typedarray.prototype.slice@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz#bce2f685d3279f543239e4d595e0d021731d2d1a" - integrity sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A== - dependencies: - call-bind "^1.0.7" - define-properties "^1.2.1" - es-abstract "^1.23.0" - es-errors "^1.3.0" - typed-array-buffer "^1.0.2" - typed-array-byte-offset "^1.0.2" - typescript@^5.5.3: version "5.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -6969,6 +6624,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-sync-external-store@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -7180,33 +6840,11 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - which-module@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -7309,3 +6947,10 @@ yocto-queue@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== + +zustand@^4.4.0: + version "4.5.5" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.5.tgz#f8c713041543715ec81a2adda0610e1dc82d4ad1" + integrity sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q== + dependencies: + use-sync-external-store "1.2.2" From f7bf49c49af66cd514751de04e9ea060c7370201 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 16 Aug 2024 01:56:36 +0000 Subject: [PATCH 048/257] Update translation files Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate. --- translations/de.po | 54 +++++++++++++++++++++++++++------------------- translations/fr.po | 54 +++++++++++++++++++++++++++------------------- 2 files changed, 64 insertions(+), 44 deletions(-) diff --git a/translations/de.po b/translations/de.po index 9b37d10..25f9f31 100644 --- a/translations/de.po +++ b/translations/de.po @@ -154,7 +154,7 @@ msgid "At least one domain name" msgstr "Mindestens ein Domänenname" #: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:28 +#: assets/components/tracking/WatchlistsList.tsx:26 msgid "Domain names" msgstr "Domänennamen" @@ -167,7 +167,7 @@ msgid "Add a Domain name" msgstr "Einen Domänennamen hinzufügen" #: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:32 +#: assets/components/tracking/WatchlistsList.tsx:30 msgid "Tracked events" msgstr "Verfolgte Ereignisse" @@ -202,6 +202,16 @@ msgstr "Aktualisieren" msgid "Reset" msgstr "Zurücksetzen" +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 +msgid "View the Watchlist Entity Diagram" +msgstr "" + +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 +#, fuzzy +#| msgid "Watchlist Name" +msgid "Watchlist Entity Diagram" +msgstr "Name der Watchlist" + #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" msgstr "Anbieter" @@ -280,49 +290,49 @@ msgstr "" "Ich verzichte auf mein Widerrufsrecht beim Kauf von Domainnamen über die API " "des Anbieters" -#: assets/components/tracking/WatchlistsList.tsx:59 -msgid "This Watchlist is not linked to a Connector." -msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." - -#: assets/components/tracking/WatchlistsList.tsx:62 -msgid "Watchlist" -msgstr "Watchlist" - -#: assets/components/tracking/WatchlistsList.tsx:70 -msgid "Export events to iCalendar format" -msgstr "Ereignisse in das iCalendar-Format exportieren" - -#: assets/components/tracking/WatchlistsList.tsx:73 +#: assets/components/tracking/UpdateWatchlistButton.tsx:31 msgid "Edit the Watchlist" msgstr "Bearbeiten der Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:86 +#: assets/components/tracking/UpdateWatchlistButton.tsx:43 msgid "Update a Watchlist" msgstr "Aktualisieren einer Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:96 +#: assets/components/tracking/UpdateWatchlistButton.tsx:53 msgid "Cancel" msgstr "Abbrechen" -#: assets/components/tracking/WatchlistsList.tsx:110 -#: assets/components/tracking/WatchlistsList.tsx:117 +#: assets/components/tracking/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/DeleteWatchlistButton.tsx:19 msgid "Delete the Watchlist" msgstr "Löschen der Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/DeleteWatchlistButton.tsx:13 msgid "Are you sure to delete this Watchlist?" msgstr "Möchten Sie diese Watchlist wirklich löschen?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:113 +#: assets/components/tracking/DeleteWatchlistButton.tsx:15 msgid "Yes" msgstr "Ja" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/DeleteWatchlistButton.tsx:16 msgid "No" msgstr "Nein" +#: assets/components/tracking/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." + +#: assets/components/tracking/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "Ereignisse in das iCalendar-Format exportieren" + #: assets/components/tracking/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" diff --git a/translations/fr.po b/translations/fr.po index e2db367..692a882 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -155,7 +155,7 @@ msgid "At least one domain name" msgstr "Au moins un nom de domaine" #: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:28 +#: assets/components/tracking/WatchlistsList.tsx:26 msgid "Domain names" msgstr "Noms de domaines" @@ -168,7 +168,7 @@ msgid "Add a Domain name" msgstr "Ajouter un nom de domaine" #: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:32 +#: assets/components/tracking/WatchlistsList.tsx:30 msgid "Tracked events" msgstr "Événements suivis" @@ -203,6 +203,16 @@ msgstr "Mettre à jour" msgid "Reset" msgstr "Réinitialiser" +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 +msgid "View the Watchlist Entity Diagram" +msgstr "" + +#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 +#, fuzzy +#| msgid "Watchlist Name" +msgid "Watchlist Entity Diagram" +msgstr "Nom de la Watchlist" + #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" msgstr "Fournisseur" @@ -280,49 +290,49 @@ msgstr "" "Je renonce expressément à mon droit de rétractation concernant l'achat de " "noms de domaine via l'API du Fournisseur" -#: assets/components/tracking/WatchlistsList.tsx:59 -msgid "This Watchlist is not linked to a Connector." -msgstr "Cette Watchlist n'est pas liée à un connecteur." - -#: assets/components/tracking/WatchlistsList.tsx:62 -msgid "Watchlist" -msgstr "Watchlist" - -#: assets/components/tracking/WatchlistsList.tsx:70 -msgid "Export events to iCalendar format" -msgstr "Exporter les événements au format iCalendar" - -#: assets/components/tracking/WatchlistsList.tsx:73 +#: assets/components/tracking/UpdateWatchlistButton.tsx:31 msgid "Edit the Watchlist" msgstr "Modifier la Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:86 +#: assets/components/tracking/UpdateWatchlistButton.tsx:43 msgid "Update a Watchlist" msgstr "Mise à jour d'une Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:96 +#: assets/components/tracking/UpdateWatchlistButton.tsx:53 msgid "Cancel" msgstr "Annuler" -#: assets/components/tracking/WatchlistsList.tsx:110 -#: assets/components/tracking/WatchlistsList.tsx:117 +#: assets/components/tracking/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/DeleteWatchlistButton.tsx:19 msgid "Delete the Watchlist" msgstr "Supprimer la Watchlist" -#: assets/components/tracking/WatchlistsList.tsx:111 +#: assets/components/tracking/DeleteWatchlistButton.tsx:13 msgid "Are you sure to delete this Watchlist?" msgstr "Êtes-vous sûr de vouloir supprimer cette Watchlist ?" #: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/WatchlistsList.tsx:113 +#: assets/components/tracking/DeleteWatchlistButton.tsx:15 msgid "Yes" msgstr "Oui" #: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/WatchlistsList.tsx:114 +#: assets/components/tracking/DeleteWatchlistButton.tsx:16 msgid "No" msgstr "Non" +#: assets/components/tracking/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "Cette Watchlist n'est pas liée à un connecteur." + +#: assets/components/tracking/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "Watchlist" + +#: assets/components/tracking/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "Exporter les événements au format iCalendar" + #: assets/components/tracking/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" From d3d370593d74ad7c38c53322de4197a3477eccc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 01:57:45 +0000 Subject: [PATCH 049/257] Translated using Weblate (French) Currently translated at 100.0% (135 of 135 strings) --- translations/fr.po | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/translations/fr.po b/translations/fr.po index 692a882..d02880b 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-15 16:16+0000\n" +"PO-Revision-Date: 2024-08-16 01:59+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: French \n" @@ -205,13 +205,11 @@ msgstr "Réinitialiser" #: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 msgid "View the Watchlist Entity Diagram" -msgstr "" +msgstr "Afficher le diagramme d'entités de la Watchlist" #: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 -#, fuzzy -#| msgid "Watchlist Name" msgid "Watchlist Entity Diagram" -msgstr "Nom de la Watchlist" +msgstr "Diagramme d'entités de la Watchlist" #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" From e21df5a137dc256aae8cfe193a3c39c8a112afdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 01:58:34 +0000 Subject: [PATCH 050/257] Translated using Weblate (German) Currently translated at 100.0% (135 of 135 strings) --- translations/de.po | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/translations/de.po b/translations/de.po index 25f9f31..2d64d41 100644 --- a/translations/de.po +++ b/translations/de.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2024-08-15 16:16+0000\n" +"PO-Revision-Date: 2024-08-16 01:59+0000\n" "Last-Translator: Maël Gangloff \n" "Language-Team: German \n" @@ -204,13 +204,11 @@ msgstr "Zurücksetzen" #: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 msgid "View the Watchlist Entity Diagram" -msgstr "" +msgstr "Sehen Sie sich das Watchlist-Entitätsdiagramm an" #: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 -#, fuzzy -#| msgid "Watchlist Name" msgid "Watchlist Entity Diagram" -msgstr "Name der Watchlist" +msgstr "Watchlist-Entitäten Diagramm" #: assets/components/tracking/ConnectorForm.tsx:40 msgid "Provider" From d82aac451c2d0ee5a8e122f2fcc8da5d59b2b941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 13:56:52 +0200 Subject: [PATCH 051/257] feat: udpate watchlist entity diagram --- assets/components/search/EntitiesList.tsx | 8 +- .../{ => connector}/ConnectorForm.tsx | 6 +- .../{ => connector}/ConnectorsList.tsx | 2 +- .../ViewDiagramWatchlistButton.tsx | 55 +--- .../tracking/diagram/getLayoutedElements.tsx | 39 +++ .../{ => watchlist}/DeleteWatchlistButton.tsx | 4 +- .../{ => watchlist}/UpdateWatchlistButton.tsx | 4 +- .../{ => watchlist}/WatchlistForm.tsx | 4 +- .../{ => watchlist}/WatchlistsList.tsx | 10 +- assets/pages/tracking/ConnectorsPage.tsx | 4 +- assets/pages/tracking/WatchlistPage.tsx | 4 +- package.json | 1 + translations/translations.pot | 280 +++++++++--------- yarn.lock | 5 + 14 files changed, 223 insertions(+), 203 deletions(-) rename assets/components/tracking/{ => connector}/ConnectorForm.tsx (97%) rename assets/components/tracking/{ => connector}/ConnectorsList.tsx (95%) rename assets/components/tracking/{ => diagram}/ViewDiagramWatchlistButton.tsx (76%) create mode 100644 assets/components/tracking/diagram/getLayoutedElements.tsx rename assets/components/tracking/{ => watchlist}/DeleteWatchlistButton.tsx (86%) rename assets/components/tracking/{ => watchlist}/UpdateWatchlistButton.tsx (94%) rename assets/components/tracking/{ => watchlist}/WatchlistForm.tsx (98%) rename assets/components/tracking/{ => watchlist}/WatchlistsList.tsx (91%) diff --git a/assets/components/search/EntitiesList.tsx b/assets/components/search/EntitiesList.tsx index c0ee08d..c9c885c 100644 --- a/assets/components/search/EntitiesList.tsx +++ b/assets/components/search/EntitiesList.tsx @@ -5,8 +5,8 @@ import React from "react"; import {Domain} from "../../utils/api"; import {t} from "ttag"; -export function EntitiesList({domain}: { domain: Domain }) { - const domainRole = { +export function translateRoles() { + return { registrant: t`Registrant`, technical: t`Technical`, administrative: t`Administrative`, @@ -19,6 +19,10 @@ export function EntitiesList({domain}: { domain: Domain }) { notifications: t`Notifications`, noc: t`Noc` } +} + +export function EntitiesList({domain}: { domain: Domain }) { + const domainRole = translateRoles() return ({})); - -const nodeWidth = 172; -const nodeHeight = 200; - -const getLayoutedElements = (nodes: any, edges: any, direction = 'TB') => { - const isHorizontal = direction === 'LR'; - dagreGraph.setGraph({rankdir: direction}); - - nodes.forEach((node: any) => { - dagreGraph.setNode(node.id, {width: nodeWidth, height: nodeHeight}); - }); - - edges.forEach((edge: any) => { - dagreGraph.setEdge(edge.source, edge.target); - }); - - dagre.layout(dagreGraph); - - const newNodes = nodes.map((node: any) => { - const nodeWithPosition = dagreGraph.node(node.id) - - return { - ...node, - targetPosition: isHorizontal ? 'left' : 'top', - sourcePosition: isHorizontal ? 'right' : 'bottom', - position: { - x: nodeWithPosition.x - nodeWidth / 2, - y: nodeWithPosition.y - nodeHeight / 2 - }, - }; - }); - - return {nodes: newNodes, edges}; -} +import {getWatchlist, Watchlist} from "../../../utils/api"; +import {translateRoles} from "../../search/EntitiesList"; +import {getLayoutedElements} from "./getLayoutedElements"; function watchlistToNodes(watchlist: Watchlist) { @@ -79,9 +42,12 @@ function watchlistToNodes(watchlist: Watchlist) { } const rolesToColor = (roles: string[]) => roles.includes('registrant') ? 'green' : - roles.includes('technical') ? 'orange' : 'black' + roles.includes('administrative') ? 'blue' : + roles.includes('technical') ? 'orange' : 'violet' function watchlistToEdges(watchlist: Watchlist) { + const domainRole = translateRoles() + return watchlist.domains .map(d => d.entities .filter(e => !e.roles.includes('registrar')) @@ -90,6 +56,7 @@ function watchlistToEdges(watchlist: Watchlist) { source: e.roles.includes('technical') ? d.ldhName : e.entity.handle, target: e.roles.includes('technical') ? e.entity.handle : d.ldhName, style: {stroke: rolesToColor(e.roles), strokeWidth: 3}, + label: e.roles.map(r => Object.keys(domainRole).includes(r) ? domainRole[r as keyof typeof domainRole] : r).join(', '), animated: e.roles.includes('registrant'), })) ).flat(2) @@ -138,6 +105,10 @@ export function ViewDiagramWatchlistButton({token}: { token: string }) { > {nodes && edges && ({})); + +const nodeWidth = 172; +const nodeHeight = 200; + +export const getLayoutedElements = (nodes: any, edges: any, direction = 'TB') => { + const isHorizontal = direction === 'LR'; + dagreGraph.setGraph({rankdir: direction}); + + nodes.forEach((node: any) => { + dagreGraph.setNode(node.id, {width: nodeWidth, height: nodeHeight}); + }); + + edges.forEach((edge: any) => { + dagreGraph.setEdge(edge.source, edge.target); + }); + + dagre.layout(dagreGraph); + + const newNodes = nodes.map((node: any) => { + const nodeWithPosition = dagreGraph.node(node.id) + + return { + ...node, + targetPosition: isHorizontal ? 'left' : 'top', + sourcePosition: isHorizontal ? 'right' : 'bottom', + position: { + x: nodeWithPosition.x - nodeWidth / 2, + y: nodeWithPosition.y - nodeHeight / 2 + }, + }; + }); + + return {nodes: newNodes, edges}; +} \ No newline at end of file diff --git a/assets/components/tracking/DeleteWatchlistButton.tsx b/assets/components/tracking/watchlist/DeleteWatchlistButton.tsx similarity index 86% rename from assets/components/tracking/DeleteWatchlistButton.tsx rename to assets/components/tracking/watchlist/DeleteWatchlistButton.tsx index cecac54..f8ba3bb 100644 --- a/assets/components/tracking/DeleteWatchlistButton.tsx +++ b/assets/components/tracking/watchlist/DeleteWatchlistButton.tsx @@ -1,9 +1,9 @@ import {Popconfirm, theme, Typography} from "antd"; import {t} from "ttag"; -import {deleteWatchlist} from "../../utils/api"; +import {deleteWatchlist} from "../../../utils/api"; import {DeleteFilled} from "@ant-design/icons"; import React from "react"; -import {Watchlist} from "../../pages/tracking/WatchlistPage"; +import {Watchlist} from "../../../pages/tracking/WatchlistPage"; export function DeleteWatchlistButton({watchlist, onDelete}: { watchlist: Watchlist, onDelete: () => void }) { const {token} = theme.useToken() diff --git a/assets/components/tracking/UpdateWatchlistButton.tsx b/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx similarity index 94% rename from assets/components/tracking/UpdateWatchlistButton.tsx rename to assets/components/tracking/watchlist/UpdateWatchlistButton.tsx index 7e3686d..22206b2 100644 --- a/assets/components/tracking/UpdateWatchlistButton.tsx +++ b/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx @@ -2,9 +2,9 @@ import {Button, Drawer, Form, Typography} from "antd"; import {t} from "ttag"; import {WatchlistForm} from "./WatchlistForm"; import React, {useState} from "react"; -import {Watchlist} from "../../pages/tracking/WatchlistPage"; +import {Watchlist} from "../../../pages/tracking/WatchlistPage"; import {EditOutlined} from "@ant-design/icons"; -import {Connector} from "../../utils/api/connectors"; +import {Connector} from "../../../utils/api/connectors"; export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors}: { watchlist: Watchlist, diff --git a/assets/components/tracking/WatchlistForm.tsx b/assets/components/tracking/watchlist/WatchlistForm.tsx similarity index 98% rename from assets/components/tracking/WatchlistForm.tsx rename to assets/components/tracking/watchlist/WatchlistForm.tsx index 689bd1d..15d3e9d 100644 --- a/assets/components/tracking/WatchlistForm.tsx +++ b/assets/components/tracking/watchlist/WatchlistForm.tsx @@ -2,8 +2,8 @@ import {Button, Form, FormInstance, Input, Select, SelectProps, Space, Tag} from import {t} from "ttag"; import {ApiOutlined, MinusCircleOutlined, PlusOutlined} from "@ant-design/icons"; import React from "react"; -import {Connector} from "../../utils/api/connectors"; -import {actionToColor, domainEvent} from "../search/EventTimeline"; +import {Connector} from "../../../utils/api/connectors"; +import {actionToColor, domainEvent} from "../../search/EventTimeline"; type TagRender = SelectProps['tagRender']; diff --git a/assets/components/tracking/WatchlistsList.tsx b/assets/components/tracking/watchlist/WatchlistsList.tsx similarity index 91% rename from assets/components/tracking/WatchlistsList.tsx rename to assets/components/tracking/watchlist/WatchlistsList.tsx index e6b39e5..d3a17b7 100644 --- a/assets/components/tracking/WatchlistsList.tsx +++ b/assets/components/tracking/watchlist/WatchlistsList.tsx @@ -2,14 +2,14 @@ import {Card, Divider, Space, Table, Tag, Typography} from "antd"; import {t} from "ttag"; import {CalendarFilled, DisconnectOutlined, LinkOutlined} from "@ant-design/icons"; import React from "react"; -import useBreakpoint from "../../hooks/useBreakpoint"; -import {actionToColor, domainEvent} from "../search/EventTimeline"; -import {Watchlist} from "../../pages/tracking/WatchlistPage"; +import useBreakpoint from "../../../hooks/useBreakpoint"; +import {actionToColor, domainEvent} from "../../search/EventTimeline"; +import {Watchlist} from "../../../pages/tracking/WatchlistPage"; import punycode from "punycode/punycode"; -import {Connector} from "../../utils/api/connectors"; +import {Connector} from "../../../utils/api/connectors"; import {UpdateWatchlistButton} from "./UpdateWatchlistButton"; import {DeleteWatchlistButton} from "./DeleteWatchlistButton"; -import {ViewDiagramWatchlistButton} from "./ViewDiagramWatchlistButton"; +import {ViewDiagramWatchlistButton} from "../diagram/ViewDiagramWatchlistButton"; export function WatchlistsList({watchlists, onDelete, onUpdateWatchlist, connectors}: { watchlists: Watchlist[], diff --git a/assets/pages/tracking/ConnectorsPage.tsx b/assets/pages/tracking/ConnectorsPage.tsx index b4ebb13..85675b8 100644 --- a/assets/pages/tracking/ConnectorsPage.tsx +++ b/assets/pages/tracking/ConnectorsPage.tsx @@ -2,9 +2,9 @@ import React, {useEffect, useState} from "react"; import {Card, Flex, Form, message, Skeleton} from "antd"; import {t} from "ttag"; import {Connector, getConnectors, postConnector} from "../../utils/api/connectors"; -import {ConnectorForm} from "../../components/tracking/ConnectorForm"; +import {ConnectorForm} from "../../components/tracking/connector/ConnectorForm"; import {AxiosError} from "axios"; -import {ConnectorElement, ConnectorsList} from "../../components/tracking/ConnectorsList"; +import {ConnectorElement, ConnectorsList} from "../../components/tracking/connector/ConnectorsList"; import {showErrorAPI} from "../../utils"; export default function ConnectorsPage() { diff --git a/assets/pages/tracking/WatchlistPage.tsx b/assets/pages/tracking/WatchlistPage.tsx index c260c85..79c716b 100644 --- a/assets/pages/tracking/WatchlistPage.tsx +++ b/assets/pages/tracking/WatchlistPage.tsx @@ -3,8 +3,8 @@ import {Card, Divider, Flex, Form, message} from "antd"; import {EventAction, getWatchlists, putWatchlist, postWatchlist} from "../../utils/api"; import {AxiosError} from "axios"; import {t} from 'ttag' -import {WatchlistForm} from "../../components/tracking/WatchlistForm"; -import {WatchlistsList} from "../../components/tracking/WatchlistsList"; +import {WatchlistForm} from "../../components/tracking/watchlist/WatchlistForm"; +import {WatchlistsList} from "../../components/tracking/watchlist/WatchlistsList"; import {Connector, getConnectors} from "../../utils/api/connectors"; import {showErrorAPI} from "../../utils"; diff --git a/package.json b/package.json index e79cb1c..acae3d1 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "core-js": "^3.23.0", "dagre": "^0.8.5", "html-loader": "^5.1.0", + "html-to-image": "^1.11.11", "jsonld": "^8.3.2", "punycode": "^2.3.1", "react": "^18.3.1", diff --git a/translations/translations.pot b/translations/translations.pot index 2bd1eea..448db88 100644 --- a/translations/translations.pot +++ b/translations/translations.pot @@ -13,16 +13,16 @@ msgstr "" #: assets/components/RegisterForm.tsx:40 #: assets/components/RegisterForm.tsx:48 #: assets/components/search/DomainSearchBar.tsx:23 -#: assets/components/tracking/ConnectorForm.tsx:43 -#: assets/components/tracking/ConnectorForm.tsx:69 -#: assets/components/tracking/ConnectorForm.tsx:77 -#: assets/components/tracking/ConnectorForm.tsx:84 -#: assets/components/tracking/ConnectorForm.tsx:92 -#: assets/components/tracking/ConnectorForm.tsx:122 -#: assets/components/tracking/ConnectorForm.tsx:142 -#: assets/components/tracking/ConnectorForm.tsx:156 -#: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:109 +#: assets/components/tracking/connector/ConnectorForm.tsx:43 +#: assets/components/tracking/connector/ConnectorForm.tsx:69 +#: assets/components/tracking/connector/ConnectorForm.tsx:77 +#: assets/components/tracking/connector/ConnectorForm.tsx:84 +#: assets/components/tracking/connector/ConnectorForm.tsx:92 +#: assets/components/tracking/connector/ConnectorForm.tsx:122 +#: assets/components/tracking/connector/ConnectorForm.tsx:142 +#: assets/components/tracking/connector/ConnectorForm.tsx:156 +#: assets/components/tracking/connector/ConnectorForm.tsx:165 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:109 msgid "Required" msgstr "" @@ -84,7 +84,7 @@ msgid "ENUM validation expiration" msgstr "" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "" @@ -132,203 +132,203 @@ msgstr "" msgid "Noc" msgstr "" -#: assets/components/tracking/WatchlistForm.tsx:66 -msgid "Name" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:77 -msgid "Watchlist Name" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:78 -msgid "Naming the Watchlist makes it easier to find in the list below." -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:89 -msgid "At least one domain name" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:26 -msgid "Domain names" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:118 -msgid "Domain name" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:135 -msgid "Add a Domain name" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:30 -msgid "Tracked events" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:144 -msgid "At least one trigger" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:166 -#: assets/components/tracking/WatchlistForm.tsx:180 -msgid "Connector" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:176 -msgid "" -"Please make sure the connector information is valid to purchase a domain " -"that may be available soon." -msgstr "" - -#: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Create" -msgstr "" - -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Update" -msgstr "" - -#: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:195 -msgid "Reset" -msgstr "" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 -msgid "View the Watchlist Entity Diagram" -msgstr "" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 -msgid "Watchlist Entity Diagram" -msgstr "" - -#: assets/components/tracking/ConnectorForm.tsx:40 +#: assets/components/tracking/connector/ConnectorForm.tsx:40 msgid "Provider" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:47 +#: assets/components/tracking/connector/ConnectorForm.tsx:47 msgid "Please select a Provider" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:75 +#: assets/components/tracking/connector/ConnectorForm.tsx:75 msgid "OVH Endpoint" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:82 +#: assets/components/tracking/connector/ConnectorForm.tsx:82 msgid "OVH subsidiary" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:90 +#: assets/components/tracking/connector/ConnectorForm.tsx:90 msgid "OVH pricing mode" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:95 +#: assets/components/tracking/connector/ConnectorForm.tsx:95 msgid "Confirm pricing mode" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:96 +#: assets/components/tracking/connector/ConnectorForm.tsx:96 msgid "" "Are you sure about this setting? This may result in additional charges from " "the API Provider" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:120 +#: assets/components/tracking/connector/ConnectorForm.tsx:120 msgid "Personal Access Token (PAT)" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:126 +#: assets/components/tracking/connector/ConnectorForm.tsx:126 msgid "Organization sharing ID" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:129 +#: assets/components/tracking/connector/ConnectorForm.tsx:129 msgid "It indicates the organization that will pay for the ordered product" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:140 +#: assets/components/tracking/connector/ConnectorForm.tsx:140 msgid "API Terms of Service" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:148 +#: assets/components/tracking/connector/ConnectorForm.tsx:148 msgid "" "I have read and accepted the conditions of use of the Provider API, " "accessible from this hyperlink" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:154 +#: assets/components/tracking/connector/ConnectorForm.tsx:154 msgid "Legal age" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:159 +#: assets/components/tracking/connector/ConnectorForm.tsx:159 msgid "I am of the minimum age required to consent to these conditions" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:163 +#: assets/components/tracking/connector/ConnectorForm.tsx:163 msgid "Withdrawal period" msgstr "" -#: assets/components/tracking/ConnectorForm.tsx:168 +#: assets/components/tracking/connector/ConnectorForm.tsx:168 msgid "" "I waive my right of withdrawal regarding the purchase of domain names via " "the Provider's API" msgstr "" -#: assets/components/tracking/UpdateWatchlistButton.tsx:31 -msgid "Edit the Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:176 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Create" msgstr "" -#: assets/components/tracking/UpdateWatchlistButton.tsx:43 -msgid "Update a Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:179 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:195 +msgid "Reset" msgstr "" -#: assets/components/tracking/UpdateWatchlistButton.tsx:53 -msgid "Cancel" -msgstr "" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:12 -#: assets/components/tracking/DeleteWatchlistButton.tsx:19 -msgid "Delete the Watchlist" -msgstr "" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:13 -msgid "Are you sure to delete this Watchlist?" -msgstr "" - -#: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/DeleteWatchlistButton.tsx:15 -msgid "Yes" -msgstr "" - -#: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/DeleteWatchlistButton.tsx:16 -msgid "No" -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:46 -msgid "This Watchlist is not linked to a Connector." -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:49 -msgid "Watchlist" -msgstr "" - -#: assets/components/tracking/WatchlistsList.tsx:60 -msgid "Export events to iCalendar format" -msgstr "" - -#: assets/components/tracking/ConnectorsList.tsx:19 +#: assets/components/tracking/connector/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" msgstr "" -#: assets/components/tracking/ConnectorsList.tsx:22 +#: assets/components/tracking/connector/ConnectorsList.tsx:22 msgid "Delete the Connector" msgstr "" -#: assets/components/tracking/ConnectorsList.tsx:23 +#: assets/components/tracking/connector/ConnectorsList.tsx:23 msgid "Are you sure to delete this Connector?" msgstr "" +#: assets/components/tracking/connector/ConnectorsList.tsx:25 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:15 +msgid "Yes" +msgstr "" + +#: assets/components/tracking/connector/ConnectorsList.tsx:26 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:16 +msgid "No" +msgstr "" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86 +msgid "View the Watchlist Entity Diagram" +msgstr "" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91 +msgid "Watchlist Entity Diagram" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:66 +msgid "Name" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:77 +msgid "Watchlist Name" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:78 +msgid "Naming the Watchlist makes it easier to find in the list below." +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:89 +msgid "At least one domain name" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:100 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:26 +msgid "Domain names" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:118 +msgid "Domain name" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:135 +msgid "Add a Domain name" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:142 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:30 +msgid "Tracked events" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:144 +msgid "At least one trigger" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:166 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:180 +msgid "Connector" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:176 +msgid "" +"Please make sure the connector information is valid to purchase a domain " +"that may be available soon." +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Update" +msgstr "" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:31 +msgid "Edit the Watchlist" +msgstr "" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:43 +msgid "Update a Watchlist" +msgstr "" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:53 +msgid "Cancel" +msgstr "" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:19 +msgid "Delete the Watchlist" +msgstr "" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:13 +msgid "Are you sure to delete this Watchlist?" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "" + #: assets/components/Sider.tsx:29 msgid "Home" msgstr "" diff --git a/yarn.lock b/yarn.lock index 58a60c7..5a203cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3933,6 +3933,11 @@ html-minifier-terser@^7.2.0: relateurl "^0.2.7" terser "^5.15.1" +html-to-image@^1.11.11: + version "1.11.11" + resolved "https://registry.yarnpkg.com/html-to-image/-/html-to-image-1.11.11.tgz#c0f8a34dc9e4b97b93ff7ea286eb8562642ebbea" + integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA== + htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" From 43d7d6ff0de8d61608ee7cac4e8950ed2471ddd0 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 16 Aug 2024 11:57:27 +0000 Subject: [PATCH 052/257] Update translation files Updated by "Update PO files to match POT (msgmerge)" add-on in Weblate. --- translations/de.po | 292 ++++++++++++++++++++++----------------------- translations/fr.po | 292 ++++++++++++++++++++++----------------------- 2 files changed, 292 insertions(+), 292 deletions(-) diff --git a/translations/de.po b/translations/de.po index 2d64d41..858fb9a 100644 --- a/translations/de.po +++ b/translations/de.po @@ -17,16 +17,16 @@ msgstr "E-Mail-Adresse" #: assets/components/LoginForm.tsx:53 assets/components/LoginForm.tsx:61 #: assets/components/RegisterForm.tsx:40 assets/components/RegisterForm.tsx:48 #: assets/components/search/DomainSearchBar.tsx:23 -#: assets/components/tracking/ConnectorForm.tsx:43 -#: assets/components/tracking/ConnectorForm.tsx:69 -#: assets/components/tracking/ConnectorForm.tsx:77 -#: assets/components/tracking/ConnectorForm.tsx:84 -#: assets/components/tracking/ConnectorForm.tsx:92 -#: assets/components/tracking/ConnectorForm.tsx:122 -#: assets/components/tracking/ConnectorForm.tsx:142 -#: assets/components/tracking/ConnectorForm.tsx:156 -#: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:109 +#: assets/components/tracking/connector/ConnectorForm.tsx:43 +#: assets/components/tracking/connector/ConnectorForm.tsx:69 +#: assets/components/tracking/connector/ConnectorForm.tsx:77 +#: assets/components/tracking/connector/ConnectorForm.tsx:84 +#: assets/components/tracking/connector/ConnectorForm.tsx:92 +#: assets/components/tracking/connector/ConnectorForm.tsx:122 +#: assets/components/tracking/connector/ConnectorForm.tsx:142 +#: assets/components/tracking/connector/ConnectorForm.tsx:156 +#: assets/components/tracking/connector/ConnectorForm.tsx:165 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:109 msgid "Required" msgstr "Erforderlich" @@ -87,7 +87,7 @@ msgid "ENUM validation expiration" msgstr "Ablauf der ENUM-Validierung" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "Dieser Domainname scheint nicht gültig zu sein" @@ -135,106 +135,31 @@ msgstr "Benachrichtigungen" msgid "Noc" msgstr "Noc" -#: assets/components/tracking/WatchlistForm.tsx:66 -msgid "Name" -msgstr "Name" - -#: assets/components/tracking/WatchlistForm.tsx:77 -msgid "Watchlist Name" -msgstr "Name der Watchlist" - -#: assets/components/tracking/WatchlistForm.tsx:78 -msgid "Naming the Watchlist makes it easier to find in the list below." -msgstr "" -"Durch die Benennung der Watchlist ist sie in der Liste weiter unten leichter " -"zu finden." - -#: assets/components/tracking/WatchlistForm.tsx:89 -msgid "At least one domain name" -msgstr "Mindestens ein Domänenname" - -#: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:26 -msgid "Domain names" -msgstr "Domänennamen" - -#: assets/components/tracking/WatchlistForm.tsx:118 -msgid "Domain name" -msgstr "Domänenname" - -#: assets/components/tracking/WatchlistForm.tsx:135 -msgid "Add a Domain name" -msgstr "Einen Domänennamen hinzufügen" - -#: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:30 -msgid "Tracked events" -msgstr "Verfolgte Ereignisse" - -#: assets/components/tracking/WatchlistForm.tsx:144 -msgid "At least one trigger" -msgstr "Mindestens ein Auslöser" - -#: assets/components/tracking/WatchlistForm.tsx:166 -#: assets/components/tracking/WatchlistForm.tsx:180 -msgid "Connector" -msgstr "Konnektor" - -#: assets/components/tracking/WatchlistForm.tsx:176 -msgid "" -"Please make sure the connector information is valid to purchase a domain " -"that may be available soon." -msgstr "" -"Bitte stellen Sie sicher, dass die Connector-Informationen gültig sind, um " -"eine Domäne zu erwerben, die möglicherweise bald verfügbar ist." - -#: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Create" -msgstr "Erstellen" - -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Update" -msgstr "Aktualisieren" - -#: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:195 -msgid "Reset" -msgstr "Zurücksetzen" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 -msgid "View the Watchlist Entity Diagram" -msgstr "Sehen Sie sich das Watchlist-Entitätsdiagramm an" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 -msgid "Watchlist Entity Diagram" -msgstr "Watchlist-Entitäten Diagramm" - -#: assets/components/tracking/ConnectorForm.tsx:40 +#: assets/components/tracking/connector/ConnectorForm.tsx:40 msgid "Provider" msgstr "Anbieter" -#: assets/components/tracking/ConnectorForm.tsx:47 +#: assets/components/tracking/connector/ConnectorForm.tsx:47 msgid "Please select a Provider" msgstr "Bitte wählen Sie einen Anbieter" -#: assets/components/tracking/ConnectorForm.tsx:75 +#: assets/components/tracking/connector/ConnectorForm.tsx:75 msgid "OVH Endpoint" msgstr "OVH Endpunkt" -#: assets/components/tracking/ConnectorForm.tsx:82 +#: assets/components/tracking/connector/ConnectorForm.tsx:82 msgid "OVH subsidiary" msgstr "OVH-Tochtergesellschaft" -#: assets/components/tracking/ConnectorForm.tsx:90 +#: assets/components/tracking/connector/ConnectorForm.tsx:90 msgid "OVH pricing mode" msgstr "OVH Preismodell" -#: assets/components/tracking/ConnectorForm.tsx:95 +#: assets/components/tracking/connector/ConnectorForm.tsx:95 msgid "Confirm pricing mode" msgstr "Preismodus bestätigen" -#: assets/components/tracking/ConnectorForm.tsx:96 +#: assets/components/tracking/connector/ConnectorForm.tsx:96 msgid "" "Are you sure about this setting? This may result in additional charges from " "the API Provider" @@ -242,23 +167,23 @@ msgstr "" "Sind Sie sich bei dieser Einstellung sicher? Dies kann zu zusätzlichen " "Gebühren durch den API-Anbieter führen" -#: assets/components/tracking/ConnectorForm.tsx:120 +#: assets/components/tracking/connector/ConnectorForm.tsx:120 msgid "Personal Access Token (PAT)" msgstr "Persönlicher Zugriffstoken (PAT)" -#: assets/components/tracking/ConnectorForm.tsx:126 +#: assets/components/tracking/connector/ConnectorForm.tsx:126 msgid "Organization sharing ID" msgstr "Freigabe-ID der Organisation" -#: assets/components/tracking/ConnectorForm.tsx:129 +#: assets/components/tracking/connector/ConnectorForm.tsx:129 msgid "It indicates the organization that will pay for the ordered product" msgstr "Es gibt die Organisation an, die für das bestellte Produkt bezahlt" -#: assets/components/tracking/ConnectorForm.tsx:140 +#: assets/components/tracking/connector/ConnectorForm.tsx:140 msgid "API Terms of Service" msgstr "API-Nutzungsbedingungen" -#: assets/components/tracking/ConnectorForm.tsx:148 +#: assets/components/tracking/connector/ConnectorForm.tsx:148 msgid "" "I have read and accepted the conditions of use of the Provider API, " "accessible from this hyperlink" @@ -266,21 +191,21 @@ msgstr "" "Ich habe die Nutzungsbedingungen der Provider-API gelesen und akzeptiert, " "die über diesen Hyperlink zugänglich sind" -#: assets/components/tracking/ConnectorForm.tsx:154 +#: assets/components/tracking/connector/ConnectorForm.tsx:154 msgid "Legal age" msgstr "Volljährigkeit" -#: assets/components/tracking/ConnectorForm.tsx:159 +#: assets/components/tracking/connector/ConnectorForm.tsx:159 msgid "I am of the minimum age required to consent to these conditions" msgstr "" "Ich habe das erforderliche Mindestalter erreicht, um diesen Bedingungen " "zuzustimmen" -#: assets/components/tracking/ConnectorForm.tsx:163 +#: assets/components/tracking/connector/ConnectorForm.tsx:163 msgid "Withdrawal period" msgstr "Rücktrittsfrist" -#: assets/components/tracking/ConnectorForm.tsx:168 +#: assets/components/tracking/connector/ConnectorForm.tsx:168 msgid "" "I waive my right of withdrawal regarding the purchase of domain names via " "the Provider's API" @@ -288,62 +213,137 @@ msgstr "" "Ich verzichte auf mein Widerrufsrecht beim Kauf von Domainnamen über die API " "des Anbieters" -#: assets/components/tracking/UpdateWatchlistButton.tsx:31 -msgid "Edit the Watchlist" -msgstr "Bearbeiten der Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:176 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Create" +msgstr "Erstellen" -#: assets/components/tracking/UpdateWatchlistButton.tsx:43 -msgid "Update a Watchlist" -msgstr "Aktualisieren einer Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:179 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:195 +msgid "Reset" +msgstr "Zurücksetzen" -#: assets/components/tracking/UpdateWatchlistButton.tsx:53 -msgid "Cancel" -msgstr "Abbrechen" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:12 -#: assets/components/tracking/DeleteWatchlistButton.tsx:19 -msgid "Delete the Watchlist" -msgstr "Löschen der Watchlist" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:13 -msgid "Are you sure to delete this Watchlist?" -msgstr "Möchten Sie diese Watchlist wirklich löschen?" - -#: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/DeleteWatchlistButton.tsx:15 -msgid "Yes" -msgstr "Ja" - -#: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/DeleteWatchlistButton.tsx:16 -msgid "No" -msgstr "Nein" - -#: assets/components/tracking/WatchlistsList.tsx:46 -msgid "This Watchlist is not linked to a Connector." -msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." - -#: assets/components/tracking/WatchlistsList.tsx:49 -msgid "Watchlist" -msgstr "Watchlist" - -#: assets/components/tracking/WatchlistsList.tsx:60 -msgid "Export events to iCalendar format" -msgstr "Ereignisse in das iCalendar-Format exportieren" - -#: assets/components/tracking/ConnectorsList.tsx:19 +#: assets/components/tracking/connector/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" msgstr "Konnektor ${ connector.provider }" -#: assets/components/tracking/ConnectorsList.tsx:22 +#: assets/components/tracking/connector/ConnectorsList.tsx:22 msgid "Delete the Connector" msgstr "Löschen des Connectors" -#: assets/components/tracking/ConnectorsList.tsx:23 +#: assets/components/tracking/connector/ConnectorsList.tsx:23 msgid "Are you sure to delete this Connector?" msgstr "Möchten Sie diesen Connector wirklich löschen?" +#: assets/components/tracking/connector/ConnectorsList.tsx:25 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:15 +msgid "Yes" +msgstr "Ja" + +#: assets/components/tracking/connector/ConnectorsList.tsx:26 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:16 +msgid "No" +msgstr "Nein" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86 +msgid "View the Watchlist Entity Diagram" +msgstr "Sehen Sie sich das Watchlist-Entitätsdiagramm an" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91 +msgid "Watchlist Entity Diagram" +msgstr "Watchlist-Entitäten Diagramm" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:66 +msgid "Name" +msgstr "Name" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:77 +msgid "Watchlist Name" +msgstr "Name der Watchlist" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:78 +msgid "Naming the Watchlist makes it easier to find in the list below." +msgstr "" +"Durch die Benennung der Watchlist ist sie in der Liste weiter unten leichter " +"zu finden." + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:89 +msgid "At least one domain name" +msgstr "Mindestens ein Domänenname" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:100 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:26 +msgid "Domain names" +msgstr "Domänennamen" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:118 +msgid "Domain name" +msgstr "Domänenname" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:135 +msgid "Add a Domain name" +msgstr "Einen Domänennamen hinzufügen" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:142 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:30 +msgid "Tracked events" +msgstr "Verfolgte Ereignisse" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:144 +msgid "At least one trigger" +msgstr "Mindestens ein Auslöser" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:166 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:180 +msgid "Connector" +msgstr "Konnektor" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:176 +msgid "" +"Please make sure the connector information is valid to purchase a domain " +"that may be available soon." +msgstr "" +"Bitte stellen Sie sicher, dass die Connector-Informationen gültig sind, um " +"eine Domäne zu erwerben, die möglicherweise bald verfügbar ist." + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Update" +msgstr "Aktualisieren" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:31 +msgid "Edit the Watchlist" +msgstr "Bearbeiten der Watchlist" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:43 +msgid "Update a Watchlist" +msgstr "Aktualisieren einer Watchlist" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:53 +msgid "Cancel" +msgstr "Abbrechen" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:19 +msgid "Delete the Watchlist" +msgstr "Löschen der Watchlist" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:13 +msgid "Are you sure to delete this Watchlist?" +msgstr "Möchten Sie diese Watchlist wirklich löschen?" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "Diese Beobachtungsliste ist nicht mit einem Connector verknüpft." + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "Watchlist" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "Ereignisse in das iCalendar-Format exportieren" + #: assets/components/Sider.tsx:29 msgid "Home" msgstr "Startseite" diff --git a/translations/fr.po b/translations/fr.po index d02880b..8db7cd0 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -18,16 +18,16 @@ msgstr "Adresse e-mail" #: assets/components/LoginForm.tsx:53 assets/components/LoginForm.tsx:61 #: assets/components/RegisterForm.tsx:40 assets/components/RegisterForm.tsx:48 #: assets/components/search/DomainSearchBar.tsx:23 -#: assets/components/tracking/ConnectorForm.tsx:43 -#: assets/components/tracking/ConnectorForm.tsx:69 -#: assets/components/tracking/ConnectorForm.tsx:77 -#: assets/components/tracking/ConnectorForm.tsx:84 -#: assets/components/tracking/ConnectorForm.tsx:92 -#: assets/components/tracking/ConnectorForm.tsx:122 -#: assets/components/tracking/ConnectorForm.tsx:142 -#: assets/components/tracking/ConnectorForm.tsx:156 -#: assets/components/tracking/ConnectorForm.tsx:165 -#: assets/components/tracking/WatchlistForm.tsx:109 +#: assets/components/tracking/connector/ConnectorForm.tsx:43 +#: assets/components/tracking/connector/ConnectorForm.tsx:69 +#: assets/components/tracking/connector/ConnectorForm.tsx:77 +#: assets/components/tracking/connector/ConnectorForm.tsx:84 +#: assets/components/tracking/connector/ConnectorForm.tsx:92 +#: assets/components/tracking/connector/ConnectorForm.tsx:122 +#: assets/components/tracking/connector/ConnectorForm.tsx:142 +#: assets/components/tracking/connector/ConnectorForm.tsx:156 +#: assets/components/tracking/connector/ConnectorForm.tsx:165 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:109 msgid "Required" msgstr "Requis" @@ -88,7 +88,7 @@ msgid "ENUM validation expiration" msgstr "Expiration de la validation ENUM" #: assets/components/search/DomainSearchBar.tsx:26 -#: assets/components/tracking/WatchlistForm.tsx:112 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:112 msgid "This domain name does not appear to be valid" msgstr "Ce nom de domaine ne semble pas être valide" @@ -136,106 +136,31 @@ msgstr "Notifications" msgid "Noc" msgstr "NOC" -#: assets/components/tracking/WatchlistForm.tsx:66 -msgid "Name" -msgstr "Nom" - -#: assets/components/tracking/WatchlistForm.tsx:77 -msgid "Watchlist Name" -msgstr "Nom de la Watchlist" - -#: assets/components/tracking/WatchlistForm.tsx:78 -msgid "Naming the Watchlist makes it easier to find in the list below." -msgstr "" -"Nommer la Watchlist permet de la retrouver plus facilement dans la liste ci-" -"dessous." - -#: assets/components/tracking/WatchlistForm.tsx:89 -msgid "At least one domain name" -msgstr "Au moins un nom de domaine" - -#: assets/components/tracking/WatchlistForm.tsx:100 -#: assets/components/tracking/WatchlistsList.tsx:26 -msgid "Domain names" -msgstr "Noms de domaines" - -#: assets/components/tracking/WatchlistForm.tsx:118 -msgid "Domain name" -msgstr "Nom de domaine" - -#: assets/components/tracking/WatchlistForm.tsx:135 -msgid "Add a Domain name" -msgstr "Ajouter un nom de domaine" - -#: assets/components/tracking/WatchlistForm.tsx:142 -#: assets/components/tracking/WatchlistsList.tsx:30 -msgid "Tracked events" -msgstr "Événements suivis" - -#: assets/components/tracking/WatchlistForm.tsx:144 -msgid "At least one trigger" -msgstr "Au moins un déclencheur" - -#: assets/components/tracking/WatchlistForm.tsx:166 -#: assets/components/tracking/WatchlistForm.tsx:180 -msgid "Connector" -msgstr "Connecteur" - -#: assets/components/tracking/WatchlistForm.tsx:176 -msgid "" -"Please make sure the connector information is valid to purchase a domain " -"that may be available soon." -msgstr "" -"Merci de vous assurer que les informations du connecteur sont valides pour " -"acheter un domaine qui pourrait être disponible prochainement." - -#: assets/components/tracking/ConnectorForm.tsx:176 -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Create" -msgstr "Créer" - -#: assets/components/tracking/WatchlistForm.tsx:192 -msgid "Update" -msgstr "Mettre à jour" - -#: assets/components/tracking/ConnectorForm.tsx:179 -#: assets/components/tracking/WatchlistForm.tsx:195 -msgid "Reset" -msgstr "Réinitialiser" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:119 -msgid "View the Watchlist Entity Diagram" -msgstr "Afficher le diagramme d'entités de la Watchlist" - -#: assets/components/tracking/ViewDiagramWatchlistButton.tsx:124 -msgid "Watchlist Entity Diagram" -msgstr "Diagramme d'entités de la Watchlist" - -#: assets/components/tracking/ConnectorForm.tsx:40 +#: assets/components/tracking/connector/ConnectorForm.tsx:40 msgid "Provider" msgstr "Fournisseur" -#: assets/components/tracking/ConnectorForm.tsx:47 +#: assets/components/tracking/connector/ConnectorForm.tsx:47 msgid "Please select a Provider" msgstr "Veuillez sélectionner un fournisseur" -#: assets/components/tracking/ConnectorForm.tsx:75 +#: assets/components/tracking/connector/ConnectorForm.tsx:75 msgid "OVH Endpoint" msgstr "Endpoint OVH" -#: assets/components/tracking/ConnectorForm.tsx:82 +#: assets/components/tracking/connector/ConnectorForm.tsx:82 msgid "OVH subsidiary" msgstr "Filiale OVH" -#: assets/components/tracking/ConnectorForm.tsx:90 +#: assets/components/tracking/connector/ConnectorForm.tsx:90 msgid "OVH pricing mode" msgstr "Mode de tarification OVH" -#: assets/components/tracking/ConnectorForm.tsx:95 +#: assets/components/tracking/connector/ConnectorForm.tsx:95 msgid "Confirm pricing mode" msgstr "Confirmer le mode de tarification" -#: assets/components/tracking/ConnectorForm.tsx:96 +#: assets/components/tracking/connector/ConnectorForm.tsx:96 msgid "" "Are you sure about this setting? This may result in additional charges from " "the API Provider" @@ -243,23 +168,23 @@ msgstr "" "Êtes-vous sûr de ce paramètre ? Cela peut entraîner des frais " "supplémentaires de la part du fournisseur d'API" -#: assets/components/tracking/ConnectorForm.tsx:120 +#: assets/components/tracking/connector/ConnectorForm.tsx:120 msgid "Personal Access Token (PAT)" msgstr "Jeton d'accès personnel (PAT)" -#: assets/components/tracking/ConnectorForm.tsx:126 +#: assets/components/tracking/connector/ConnectorForm.tsx:126 msgid "Organization sharing ID" msgstr "ID de partage d'organisation" -#: assets/components/tracking/ConnectorForm.tsx:129 +#: assets/components/tracking/connector/ConnectorForm.tsx:129 msgid "It indicates the organization that will pay for the ordered product" msgstr "Il indique l'organisation qui paiera le produit commandé" -#: assets/components/tracking/ConnectorForm.tsx:140 +#: assets/components/tracking/connector/ConnectorForm.tsx:140 msgid "API Terms of Service" msgstr "Conditions d'utilisation de l'API" -#: assets/components/tracking/ConnectorForm.tsx:148 +#: assets/components/tracking/connector/ConnectorForm.tsx:148 msgid "" "I have read and accepted the conditions of use of the Provider API, " "accessible from this hyperlink" @@ -267,20 +192,20 @@ msgstr "" "J'ai lu et j'accepte les conditions d'utilisation de l'API du Fournisseur, " "accessibles à partir de ce lien hypertexte" -#: assets/components/tracking/ConnectorForm.tsx:154 +#: assets/components/tracking/connector/ConnectorForm.tsx:154 msgid "Legal age" msgstr "Âge minimum légal" -#: assets/components/tracking/ConnectorForm.tsx:159 +#: assets/components/tracking/connector/ConnectorForm.tsx:159 msgid "I am of the minimum age required to consent to these conditions" msgstr "" "Je certifie que j'ai l'âge minimum requis pour consentir à ces conditions" -#: assets/components/tracking/ConnectorForm.tsx:163 +#: assets/components/tracking/connector/ConnectorForm.tsx:163 msgid "Withdrawal period" msgstr "Délai de rétractation" -#: assets/components/tracking/ConnectorForm.tsx:168 +#: assets/components/tracking/connector/ConnectorForm.tsx:168 msgid "" "I waive my right of withdrawal regarding the purchase of domain names via " "the Provider's API" @@ -288,62 +213,137 @@ msgstr "" "Je renonce expressément à mon droit de rétractation concernant l'achat de " "noms de domaine via l'API du Fournisseur" -#: assets/components/tracking/UpdateWatchlistButton.tsx:31 -msgid "Edit the Watchlist" -msgstr "Modifier la Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:176 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Create" +msgstr "Créer" -#: assets/components/tracking/UpdateWatchlistButton.tsx:43 -msgid "Update a Watchlist" -msgstr "Mise à jour d'une Watchlist" +#: assets/components/tracking/connector/ConnectorForm.tsx:179 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:195 +msgid "Reset" +msgstr "Réinitialiser" -#: assets/components/tracking/UpdateWatchlistButton.tsx:53 -msgid "Cancel" -msgstr "Annuler" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:12 -#: assets/components/tracking/DeleteWatchlistButton.tsx:19 -msgid "Delete the Watchlist" -msgstr "Supprimer la Watchlist" - -#: assets/components/tracking/DeleteWatchlistButton.tsx:13 -msgid "Are you sure to delete this Watchlist?" -msgstr "Êtes-vous sûr de vouloir supprimer cette Watchlist ?" - -#: assets/components/tracking/ConnectorsList.tsx:25 -#: assets/components/tracking/DeleteWatchlistButton.tsx:15 -msgid "Yes" -msgstr "Oui" - -#: assets/components/tracking/ConnectorsList.tsx:26 -#: assets/components/tracking/DeleteWatchlistButton.tsx:16 -msgid "No" -msgstr "Non" - -#: assets/components/tracking/WatchlistsList.tsx:46 -msgid "This Watchlist is not linked to a Connector." -msgstr "Cette Watchlist n'est pas liée à un connecteur." - -#: assets/components/tracking/WatchlistsList.tsx:49 -msgid "Watchlist" -msgstr "Watchlist" - -#: assets/components/tracking/WatchlistsList.tsx:60 -msgid "Export events to iCalendar format" -msgstr "Exporter les événements au format iCalendar" - -#: assets/components/tracking/ConnectorsList.tsx:19 +#: assets/components/tracking/connector/ConnectorsList.tsx:19 #, javascript-format msgid "Connector ${ connector.provider }" msgstr "Connecteur ${ connector.provider }" -#: assets/components/tracking/ConnectorsList.tsx:22 +#: assets/components/tracking/connector/ConnectorsList.tsx:22 msgid "Delete the Connector" msgstr "Supprimer le Connecteur" -#: assets/components/tracking/ConnectorsList.tsx:23 +#: assets/components/tracking/connector/ConnectorsList.tsx:23 msgid "Are you sure to delete this Connector?" msgstr "Êtes-vous sûr de vouloir supprimer ce Connecteur ?" +#: assets/components/tracking/connector/ConnectorsList.tsx:25 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:15 +msgid "Yes" +msgstr "Oui" + +#: assets/components/tracking/connector/ConnectorsList.tsx:26 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:16 +msgid "No" +msgstr "Non" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:86 +msgid "View the Watchlist Entity Diagram" +msgstr "Afficher le diagramme d'entités de la Watchlist" + +#: assets/components/tracking/diagram/ViewDiagramWatchlistButton.tsx:91 +msgid "Watchlist Entity Diagram" +msgstr "Diagramme d'entités de la Watchlist" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:66 +msgid "Name" +msgstr "Nom" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:77 +msgid "Watchlist Name" +msgstr "Nom de la Watchlist" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:78 +msgid "Naming the Watchlist makes it easier to find in the list below." +msgstr "" +"Nommer la Watchlist permet de la retrouver plus facilement dans la liste ci-" +"dessous." + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:89 +msgid "At least one domain name" +msgstr "Au moins un nom de domaine" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:100 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:26 +msgid "Domain names" +msgstr "Noms de domaines" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:118 +msgid "Domain name" +msgstr "Nom de domaine" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:135 +msgid "Add a Domain name" +msgstr "Ajouter un nom de domaine" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:142 +#: assets/components/tracking/watchlist/WatchlistsList.tsx:30 +msgid "Tracked events" +msgstr "Événements suivis" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:144 +msgid "At least one trigger" +msgstr "Au moins un déclencheur" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:166 +#: assets/components/tracking/watchlist/WatchlistForm.tsx:180 +msgid "Connector" +msgstr "Connecteur" + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:176 +msgid "" +"Please make sure the connector information is valid to purchase a domain " +"that may be available soon." +msgstr "" +"Merci de vous assurer que les informations du connecteur sont valides pour " +"acheter un domaine qui pourrait être disponible prochainement." + +#: assets/components/tracking/watchlist/WatchlistForm.tsx:192 +msgid "Update" +msgstr "Mettre à jour" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:31 +msgid "Edit the Watchlist" +msgstr "Modifier la Watchlist" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:43 +msgid "Update a Watchlist" +msgstr "Mise à jour d'une Watchlist" + +#: assets/components/tracking/watchlist/UpdateWatchlistButton.tsx:53 +msgid "Cancel" +msgstr "Annuler" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:12 +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:19 +msgid "Delete the Watchlist" +msgstr "Supprimer la Watchlist" + +#: assets/components/tracking/watchlist/DeleteWatchlistButton.tsx:13 +msgid "Are you sure to delete this Watchlist?" +msgstr "Êtes-vous sûr de vouloir supprimer cette Watchlist ?" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:46 +msgid "This Watchlist is not linked to a Connector." +msgstr "Cette Watchlist n'est pas liée à un connecteur." + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:49 +msgid "Watchlist" +msgstr "Watchlist" + +#: assets/components/tracking/watchlist/WatchlistsList.tsx:60 +msgid "Export events to iCalendar format" +msgstr "Exporter les événements au format iCalendar" + #: assets/components/Sider.tsx:29 msgid "Home" msgstr "Accueil" From 8b47d6068c5cf3ebdd305b6c35110a39187e34ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 14:19:59 +0200 Subject: [PATCH 053/257] chore: explicit error message --- src/Controller/WatchListController.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index ecc2fc7..da869c4 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -71,7 +71,7 @@ class WatchListController extends AbstractController */ if ($this->getParameter('limited_features')) { if ($watchList->getDomains()->count() > (int) $this->getParameter('limit_max_watchlist_domains')) { - $this->logger->notice('User {username} tried to create a Watchlist. However, the maximum number of domains has been reached for this Watchlist', [ + $this->logger->notice('User {username} tried to create a Watchlist. The maximum number of domains has been reached for this Watchlist', [ 'username' => $user->getUserIdentifier(), ]); throw new AccessDeniedHttpException('You have exceeded the maximum number of domain names allowed in this Watchlist'); @@ -79,7 +79,7 @@ class WatchListController extends AbstractController $userWatchLists = $user->getWatchLists(); if ($userWatchLists->count() >= (int) $this->getParameter('limit_max_watchlist')) { - $this->logger->notice('User {username} tried to create a Watchlist. However, the maximum number of Watchlists has been reached.', [ + $this->logger->notice('User {username} tried to create a Watchlist. The maximum number of Watchlists has been reached', [ 'username' => $user->getUserIdentifier(), ]); throw new AccessDeniedHttpException('You have exceeded the maximum number of Watchlists allowed'); @@ -91,12 +91,14 @@ class WatchListController extends AbstractController /** @var Domain $domain */ foreach ($watchList->getDomains()->getIterator() as $domain) { if (in_array($domain, $trackedDomains)) { - $this->logger->notice('User {username} tried to create a watchlist with domain name {ldhName}. However, it is forbidden to register the same domain name twice with limited mode.', [ + $ldhName = $domain->getLdhName(); + + $this->logger->notice('User {username} tried to create a watchlist with domain name {ldhName}. It is forbidden to register the same domain name twice with limited mode', [ 'username' => $user->getUserIdentifier(), - 'ldhName' => $domain->getLdhName(), + 'ldhName' => $ldhName, ]); - throw new AccessDeniedHttpException('It is forbidden to register the same domain name twice in your watchlists with limited mode.'); + throw new AccessDeniedHttpException("It is forbidden to register the same domain name twice in your watchlists with limited mode ($ldhName)"); } } } @@ -151,7 +153,7 @@ class WatchListController extends AbstractController if ($this->getParameter('limited_features')) { if ($watchList->getDomains()->count() > (int) $this->getParameter('limit_max_watchlist_domains')) { - $this->logger->notice('User {username} tried to update a Watchlist. However, the maximum number of domains has been reached for this Watchlist', [ + $this->logger->notice('User {username} tried to update a Watchlist. The maximum number of domains has been reached for this Watchlist', [ 'username' => $user->getUserIdentifier(), ]); throw new AccessDeniedHttpException('You have exceeded the maximum number of domain names allowed in this Watchlist'); @@ -167,12 +169,13 @@ class WatchListController extends AbstractController /** @var Domain $domain */ foreach ($watchList->getDomains()->getIterator() as $domain) { if (in_array($domain, $trackedDomains)) { - $this->logger->notice('User {username} tried to update a watchlist with domain name {ldhName}. However, it is forbidden to register the same domain name twice with limited mode.', [ + $ldhName = $domain->getLdhName(); + $this->logger->notice('User {username} tried to update a watchlist with domain name {ldhName}. It is forbidden to register the same domain name twice with limited mode', [ 'username' => $user->getUserIdentifier(), - 'ldhName' => $domain->getLdhName(), + 'ldhName' => $ldhName, ]); - throw new AccessDeniedHttpException('It is forbidden to register the same domain name twice in your watchlists with limited mode.'); + throw new AccessDeniedHttpException("It is forbidden to register the same domain name twice in your watchlists with limited mode ($ldhName)"); } } } From 1c1821838fdf96f9a4d7973470d8ab330f13da4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 17:10:59 +0200 Subject: [PATCH 054/257] feat: improve security when delete --- src/Entity/Connector.php | 4 +++- src/Entity/WatchList.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Entity/Connector.php b/src/Entity/Connector.php index d622327..4143526 100644 --- a/src/Entity/Connector.php +++ b/src/Entity/Connector.php @@ -32,7 +32,9 @@ use Symfony\Component\Uid\Uuid; normalizationContext: ['groups' => ['connector:create', 'connector:list']], denormalizationContext: ['groups' => 'connector:create'], name: 'create' ), - new Delete(), + new Delete( + security: 'object.user == user' + ), ] )] #[ORM\Entity(repositoryClass: ConnectorRepository::class)] diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index 3297032..1e129db 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -74,7 +74,9 @@ use Symfony\Component\Uid\Uuid; security: 'object.user == user', name: 'update' ), - new Delete(), + new Delete( + security: 'object.user == user' + ), ], )] class WatchList From 8667644da577b4bf3d344c4994c8bac9beb57e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 23:23:51 +0200 Subject: [PATCH 055/257] feat: start webhook support --- composer.json | 8 + composer.lock | 547 +++++++++++++++++- config/packages/notifier.yaml | 8 + config/services.yaml | 2 + migrations/Version20240816185909.php | 32 + package.json | 4 + src/Config/TriggerAction.php | 1 + src/Config/WebhookScheme.php | 38 ++ src/Controller/WatchListController.php | 32 + src/Entity/WatchList.php | 18 + .../ProcessDomainTriggerHandler.php | 109 ++-- .../ProcessWatchListTriggerHandler.php | 33 +- src/Notifier/DomainOrderErrorNotification.php | 44 ++ src/Notifier/DomainOrderNotification.php | 49 ++ .../DomainUpdateErrorNotification.php | 44 ++ src/Notifier/DomainUpdateNotification.php | 46 ++ src/Notifier/TestChatNotification.php | 19 + symfony.lock | 72 +++ yarn.lock | 38 +- 19 files changed, 1050 insertions(+), 94 deletions(-) create mode 100644 migrations/Version20240816185909.php create mode 100644 src/Config/WebhookScheme.php create mode 100644 src/Notifier/DomainOrderErrorNotification.php create mode 100644 src/Notifier/DomainOrderNotification.php create mode 100644 src/Notifier/DomainUpdateErrorNotification.php create mode 100644 src/Notifier/DomainUpdateNotification.php create mode 100644 src/Notifier/TestChatNotification.php diff --git a/composer.json b/composer.json index 930771c..e3b4491 100644 --- a/composer.json +++ b/composer.json @@ -41,16 +41,20 @@ "symfony/asset": "7.1.*", "symfony/asset-mapper": "7.1.*", "symfony/console": "7.1.*", + "symfony/discord-notifier": "7.1.*", "symfony/doctrine-messenger": "7.1.*", "symfony/dotenv": "7.1.*", "symfony/expression-language": "7.1.*", "symfony/flex": "^2", "symfony/form": "7.1.*", "symfony/framework-bundle": "7.1.*", + "symfony/google-chat-notifier": "7.1.*", "symfony/http-client": "7.1.*", "symfony/intl": "7.1.*", "symfony/lock": "7.1.*", "symfony/mailer": "7.1.*", + "symfony/mattermost-notifier": "7.1.*", + "symfony/microsoft-teams-notifier": "7.1.*", "symfony/mime": "7.1.*", "symfony/monolog-bundle": "^3.0", "symfony/notifier": "7.1.*", @@ -58,12 +62,15 @@ "symfony/property-access": "7.1.*", "symfony/property-info": "7.1.*", "symfony/rate-limiter": "7.1.*", + "symfony/rocket-chat-notifier": "7.1.*", "symfony/runtime": "7.1.*", "symfony/scheduler": "7.1.*", "symfony/security-bundle": "7.1.*", "symfony/serializer": "7.1.*", + "symfony/slack-notifier": "7.1.*", "symfony/stimulus-bundle": "^2.18", "symfony/string": "7.1.*", + "symfony/telegram-notifier": "7.1.*", "symfony/translation": "7.1.*", "symfony/twig-bundle": "7.1.*", "symfony/uid": "7.1.*", @@ -72,6 +79,7 @@ "symfony/web-link": "7.1.*", "symfony/webpack-encore-bundle": "^2.1", "symfony/yaml": "7.1.*", + "symfony/zulip-notifier": "7.1.*", "symfonycasts/verify-email-bundle": "*", "twig/extra-bundle": "^2.12|^3.0", "twig/twig": "^2.12|^3.0" diff --git a/composer.lock b/composer.lock index 46447c6..657297b 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "bab584811b8175e404608e6738549f52", + "content-hash": "f64fa606b60efd34dccdee3abcdad8b2", "packages": [ { "name": "api-platform/core", @@ -4325,6 +4325,74 @@ ], "time": "2024-04-18T09:32:20+00:00" }, + { + "name": "symfony/discord-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/discord-notifier.git", + "reference": "f3d8368ca5ff80c1268a851f925e1f0c07997a8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/discord-notifier/zipball/f3d8368ca5ff80c1268a851f925e1f0c07997a8e", + "reference": "f3d8368ca5ff80c1268a851f925e1f0c07997a8e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\Discord\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Discord Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "discord", + "notifier" + ], + "support": { + "source": "https://github.com/symfony/discord-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/doctrine-bridge", "version": "v7.1.2", @@ -5313,6 +5381,75 @@ ], "time": "2024-06-28T08:00:31+00:00" }, + { + "name": "symfony/google-chat-notifier", + "version": "v7.1.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/google-chat-notifier.git", + "reference": "1e92b6c89b2182ba26554861dc261c530c98000f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/google-chat-notifier/zipball/1e92b6c89b2182ba26554861dc261c530c98000f", + "reference": "1e92b6c89b2182ba26554861dc261c530c98000f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\GoogleChat\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Google Chat Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "Google-Chat", + "chat", + "google", + "notifier" + ], + "support": { + "source": "https://github.com/symfony/google-chat-notifier/tree/v7.1.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-25T19:55:06+00:00" + }, { "name": "symfony/http-client", "version": "v7.1.2", @@ -5920,6 +6057,73 @@ ], "time": "2024-06-28T08:00:31+00:00" }, + { + "name": "symfony/mattermost-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/mattermost-notifier.git", + "reference": "c5ff6774682ab3504a77bbe01f8c1275b4bf48e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mattermost-notifier/zipball/c5ff6774682ab3504a77bbe01f8c1275b4bf48e9", + "reference": "c5ff6774682ab3504a77bbe01f8c1275b4bf48e9", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\Mattermost\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuele Panzeri", + "email": "thepanz@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Mattermost Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "Mattermost", + "notifier" + ], + "support": { + "source": "https://github.com/symfony/mattermost-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/messenger", "version": "v7.1.2", @@ -6006,6 +6210,78 @@ ], "time": "2024-06-28T08:00:31+00:00" }, + { + "name": "symfony/microsoft-teams-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/microsoft-teams-notifier.git", + "reference": "546b0368928b5849d08728b7daf5d22a07a052b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/microsoft-teams-notifier/zipball/546b0368928b5849d08728b7daf5d22a07a052b3", + "reference": "546b0368928b5849d08728b7daf5d22a07a052b3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\MicrosoftTeams\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Edouard Lescot", + "email": "edouard.lescot@gmail.com" + }, + { + "name": "Oskar Stark", + "email": "oskarstark@googlemail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Microsoft Teams Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "chat", + "microsoft-teams", + "notifier" + ], + "support": { + "source": "https://github.com/symfony/microsoft-teams-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/mime", "version": "v7.1.2", @@ -7319,6 +7595,73 @@ ], "time": "2024-05-31T14:57:53+00:00" }, + { + "name": "symfony/rocket-chat-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/rocket-chat-notifier.git", + "reference": "b17bff59107b51753e3e347c5194dc304019daf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/rocket-chat-notifier/zipball/b17bff59107b51753e3e347c5194dc304019daf7", + "reference": "b17bff59107b51753e3e347c5194dc304019daf7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\RocketChat\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeroen Spee", + "homepage": "https://github.com/Jeroeny" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony RocketChat Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "notifier", + "rocketchat" + ], + "support": { + "source": "https://github.com/symfony/rocket-chat-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/routing", "version": "v7.1.1", @@ -8087,6 +8430,73 @@ ], "time": "2024-04-18T09:32:20+00:00" }, + { + "name": "symfony/slack-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/slack-notifier.git", + "reference": "452a17e3935192e6a9a5b16f0443911d67e456af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/slack-notifier/zipball/452a17e3935192e6a9a5b16f0443911d67e456af", + "reference": "452a17e3935192e6a9a5b16f0443911d67e456af", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\Slack\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Slack Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "notifier", + "slack" + ], + "support": { + "source": "https://github.com/symfony/slack-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/stimulus-bundle", "version": "v2.18.1", @@ -8305,6 +8715,74 @@ ], "time": "2024-06-28T09:27:18+00:00" }, + { + "name": "symfony/telegram-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/telegram-notifier.git", + "reference": "521e77470d5b07306c1001c2d1d1bc88474a8035" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/telegram-notifier/zipball/521e77470d5b07306c1001c2d1d1bc88474a8035", + "reference": "521e77470d5b07306c1001c2d1d1bc88474a8035", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\Telegram\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Telegram Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "notifier", + "telegram" + ], + "support": { + "source": "https://github.com/symfony/telegram-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfony/translation", "version": "v7.1.1", @@ -9404,6 +9882,73 @@ ], "time": "2024-05-31T14:57:53+00:00" }, + { + "name": "symfony/zulip-notifier", + "version": "v7.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/zulip-notifier.git", + "reference": "48b3e1ac791d8eac7ee268108865b36de3be5ed2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/zulip-notifier/zipball/48b3e1ac791d8eac7ee268108865b36de3be5ed2", + "reference": "48b3e1ac791d8eac7ee268108865b36de3be5ed2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/http-client": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0" + }, + "type": "symfony-notifier-bridge", + "autoload": { + "psr-4": { + "Symfony\\Component\\Notifier\\Bridge\\Zulip\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mohammad Emran Hasan", + "email": "phpfour@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Zulip Notifier Bridge", + "homepage": "https://symfony.com", + "keywords": [ + "notifier", + "zulip" + ], + "support": { + "source": "https://github.com/symfony/zulip-notifier/tree/v7.1.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T14:57:53+00:00" + }, { "name": "symfonycasts/verify-email-bundle", "version": "v1.17.0", diff --git a/config/packages/notifier.yaml b/config/packages/notifier.yaml index d02f986..ee4dc19 100644 --- a/config/packages/notifier.yaml +++ b/config/packages/notifier.yaml @@ -1,6 +1,14 @@ framework: notifier: chatter_transports: + zulip: '%env(ZULIP_DSN)%' + telegram: '%env(TELEGRAM_DSN)%' + slack: '%env(SLACK_DSN)%' + rocketchat: '%env(ROCKETCHAT_DSN)%' + microsoftteams: '%env(MICROSOFT_TEAMS_DSN)%' + mattermost: '%env(MATTERMOST_DSN)%' + googlechat: '%env(GOOGLE_CHAT_DSN)%' + discord: '%env(DISCORD_DSN)%' texter_transports: channel_policy: # use chat/slack, chat/telegram, sms/twilio or sms/nexmo diff --git a/config/services.yaml b/config/services.yaml index bc8ea08..b69bfc5 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -14,6 +14,8 @@ parameters: limit_max_watchlist_domains: '%env(int:LIMIT_MAX_WATCHLIST_DOMAINS)%' services: + Symfony\Component\Messenger\Transport\TransportFactoryInterface: '@messenger.transport_factory' + # default configuration for services in *this* file _defaults: autowire: true # Automatically injects dependencies in your services. diff --git a/migrations/Version20240816185909.php b/migrations/Version20240816185909.php new file mode 100644 index 0000000..aa873a0 --- /dev/null +++ b/migrations/Version20240816185909.php @@ -0,0 +1,32 @@ +addSql('ALTER TABLE watch_list ADD webhook_dsn TEXT DEFAULT NULL'); + $this->addSql('COMMENT ON COLUMN watch_list.webhook_dsn IS \'(DC2Type:simple_array)\''); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE watch_list DROP webhook_dsn'); + } +} diff --git a/package.json b/package.json index acae3d1..7af1b8c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,10 @@ "@babel/preset-env": "^7.16.0", "@babel/preset-react": "^7.24.7", "@fontsource/noto-color-emoji": "^5.0.27", + "@hotwired/stimulus": "^3.0.0", + "@hotwired/turbo": "^7.1.1 || ^8.0", + "@symfony/stimulus-bridge": "^3.2.0", + "@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets", "@symfony/webpack-encore": "^4.0.0", "@types/axios": "^0.14.0", "@types/dagre": "^0.7.52", diff --git a/src/Config/TriggerAction.php b/src/Config/TriggerAction.php index a3271c3..af582d5 100644 --- a/src/Config/TriggerAction.php +++ b/src/Config/TriggerAction.php @@ -5,4 +5,5 @@ namespace App\Config; enum TriggerAction: string { case SendEmail = 'email'; + case SendChat = 'chat'; } diff --git a/src/Config/WebhookScheme.php b/src/Config/WebhookScheme.php new file mode 100644 index 0000000..16c54a9 --- /dev/null +++ b/src/Config/WebhookScheme.php @@ -0,0 +1,38 @@ + DiscordTransportFactory::class, + WebhookScheme::GOOGLE_CHAT => GoogleChatTransportFactory::class, + WebhookScheme::MATTERMOST => MattermostTransportFactory::class, + WebhookScheme::MICROSOFT_TEAMS => MicrosoftTeamsTransportFactory::class, + WebhookScheme::ROCKET_CHAT => RocketChatTransportFactory::class, + WebhookScheme::SLACK => SlackTransportFactory::class, + WebhookScheme::TELEGRAM => TelegramTransportFactory::class, + WebhookScheme::ZULIP => ZulipTransportFactory::class + }; + } +} diff --git a/src/Controller/WatchListController.php b/src/Controller/WatchListController.php index da869c4..add187d 100644 --- a/src/Controller/WatchListController.php +++ b/src/Controller/WatchListController.php @@ -2,11 +2,13 @@ namespace App\Controller; +use App\Config\WebhookScheme; use App\Entity\Domain; use App\Entity\DomainEntity; use App\Entity\DomainEvent; use App\Entity\User; use App\Entity\WatchList; +use App\Notifier\TestChatNotification; use App\Repository\WatchListRepository; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; @@ -32,6 +34,9 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Serializer\SerializerInterface; @@ -65,6 +70,23 @@ class WatchListController extends AbstractController $user = $this->getUser(); $watchList->setUser($user); + if (null !== $watchList->getWebhookDsn()) { + foreach ($watchList->getWebhookDsn() as $dsnString) { + $dsn = new Dsn($dsnString); + + $scheme = $dsn->getScheme(); + $webhookScheme = WebhookScheme::tryFrom($scheme); + + if (null === $webhookScheme) { + throw new BadRequestHttpException("The DSN scheme ($scheme) is not supported"); + } + $transportFactoryClass = $webhookScheme->getChatTransportFactory(); + /** @var AbstractTransportFactory $transportFactory */ + $transportFactory = new $transportFactoryClass(); + $transportFactory->create($dsn)->send((new TestChatNotification())->asChatMessage()); + } + } + /* * In the limited version, we do not want a user to be able to register the same domain more than once in their watchlists. * This policy guarantees the equal probability of obtaining a domain name if it is requested by several users. @@ -151,6 +173,16 @@ class WatchListController extends AbstractController $user = $this->getUser(); $watchList->setUser($user); + if (null !== $watchList->getWebhookDsn()) { + foreach ($watchList->getWebhookDsn() as $dsnString) { + $scheme = (new Dsn($dsnString))->getScheme(); + + if (null === WebhookScheme::tryFrom($scheme)) { + throw new BadRequestHttpException("The DSN scheme ($scheme) is not supported"); + } + } + } + if ($this->getParameter('limited_features')) { if ($watchList->getDomains()->count() > (int) $this->getParameter('limit_max_watchlist_domains')) { $this->logger->notice('User {username} tried to update a Watchlist. The maximum number of domains has been reached for this Watchlist', [ diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index 1e129db..c08fa5b 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -12,6 +12,7 @@ use App\Controller\WatchListController; use App\Repository\WatchListRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\SerializedName; @@ -118,6 +119,11 @@ class WatchList #[Groups(['watchlist:list', 'watchlist:item'])] private ?\DateTimeImmutable $createdAt = null; + #[SerializedName('dsn')] + #[ORM\Column(type: Types::SIMPLE_ARRAY, nullable: true)] + #[Groups(['watchlist:list', 'watchlist:item', 'watchlist:create'])] + private ?array $webhookDsn = null; + public function __construct() { $this->token = Uuid::v4(); @@ -237,4 +243,16 @@ class WatchList return $this; } + + public function getWebhookDsn(): ?array + { + return $this->webhookDsn; + } + + public function setWebhookDsn(?array $webhookDsn): static + { + $this->webhookDsn = $webhookDsn; + + return $this; + } } diff --git a/src/MessageHandler/ProcessDomainTriggerHandler.php b/src/MessageHandler/ProcessDomainTriggerHandler.php index 6c85a31..069c04b 100644 --- a/src/MessageHandler/ProcessDomainTriggerHandler.php +++ b/src/MessageHandler/ProcessDomainTriggerHandler.php @@ -4,43 +4,50 @@ namespace App\MessageHandler; use App\Config\Connector\ConnectorInterface; use App\Config\TriggerAction; -use App\Entity\Connector; +use App\Config\WebhookScheme; use App\Entity\Domain; use App\Entity\DomainEvent; -use App\Entity\User; use App\Entity\WatchList; use App\Entity\WatchListTrigger; use App\Message\ProcessDomainTrigger; +use App\Notifier\DomainOrderErrorNotification; +use App\Notifier\DomainOrderNotification; +use App\Notifier\DomainUpdateNotification; use App\Repository\DomainRepository; use App\Repository\WatchListRepository; use Psr\Log\LoggerInterface; -use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; +use Symfony\Component\Messenger\Exception\ExceptionInterface; use Symfony\Component\Mime\Address; -use Symfony\Component\Mime\Email; +use Symfony\Component\Notifier\Recipient\Recipient; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Contracts\HttpClient\HttpClientInterface; #[AsMessageHandler] final readonly class ProcessDomainTriggerHandler { + private Address $sender; + public function __construct( - private string $mailerSenderEmail, - private string $mailerSenderName, - private MailerInterface $mailer, + string $mailerSenderEmail, + string $mailerSenderName, private WatchListRepository $watchListRepository, private DomainRepository $domainRepository, private KernelInterface $kernel, private LoggerInterface $logger, - private HttpClientInterface $client + private HttpClientInterface $client, + private MailerInterface $mailer ) { + $this->sender = new Address($mailerSenderEmail, $mailerSenderName); } /** * @throws TransportExceptionInterface * @throws \Exception + * @throws ExceptionInterface */ public function __invoke(ProcessDomainTrigger $message): void { @@ -70,12 +77,16 @@ final readonly class ProcessDomainTriggerHandler $connectorProvider->orderDomain($domain, $this->kernel->isDebug()); - $this->sendEmailDomainOrdered($domain, $connector, $watchList->getUser()); + $email = (new DomainOrderNotification($this->sender, $domain, $connector)) + ->asEmailMessage(new Recipient($watchList->getUser()->getEmail())); + $this->mailer->send($email->getMessage()); } catch (\Throwable) { $this->logger->warning('Unable to complete purchase. An error message is sent to user {username}.', [ 'username' => $watchList->getUser()->getUserIdentifier(), ]); - $this->sendEmailDomainOrderError($domain, $watchList->getUser()); + $email = (new DomainOrderErrorNotification($this->sender, $domain)) + ->asEmailMessage(new Recipient($watchList->getUser()->getEmail())); + $this->mailer->send($email->getMessage()); } } @@ -91,67 +102,29 @@ final readonly class ProcessDomainTriggerHandler 'ldhName' => $message->ldhName, 'username' => $watchList->getUser()->getUserIdentifier(), ]); + + $recipient = new Recipient($watchList->getUser()->getEmail()); + $notification = new DomainUpdateNotification($this->sender, $event); + if (TriggerAction::SendEmail == $watchListTrigger->getAction()) { - $this->sendEmailDomainUpdated($event, $watchList->getUser()); + $this->mailer->send($notification->asEmailMessage($recipient)->getMessage()); + } elseif (TriggerAction::SendChat == $watchListTrigger->getAction()) { + if (null !== $watchList->getWebhookDsn()) { + foreach ($watchList->getWebhookDsn() as $dsnString) { + $dsn = new \Symfony\Component\Notifier\Transport\Dsn($dsnString); + + $scheme = $dsn->getScheme(); + $webhookScheme = WebhookScheme::tryFrom($scheme); + if (null !== $webhookScheme) { + $transportFactoryClass = $webhookScheme->getChatTransportFactory(); + /** @var AbstractTransportFactory $transportFactory */ + $transportFactory = new $transportFactoryClass(); + $transportFactory->create($dsn)->send($notification->asChatMessage()); + } + } + } } } } } - - /** - * @throws TransportExceptionInterface - */ - private function sendEmailDomainOrdered(Domain $domain, Connector $connector, User $user): void - { - $email = (new TemplatedEmail()) - ->from(new Address($this->mailerSenderEmail, $this->mailerSenderName)) - ->to($user->getEmail()) - ->priority(Email::PRIORITY_HIGHEST) - ->subject('A domain name has been ordered') - ->htmlTemplate('emails/success/domain_ordered.html.twig') - ->locale('en') - ->context([ - 'domain' => $domain, - 'provider' => $connector->getProvider()->value, - ]); - - $this->mailer->send($email); - } - - /** - * @throws TransportExceptionInterface - */ - private function sendEmailDomainOrderError(Domain $domain, User $user): void - { - $email = (new TemplatedEmail()) - ->from(new Address($this->mailerSenderEmail, $this->mailerSenderName)) - ->to($user->getEmail()) - ->subject('An error occurred while ordering a domain name') - ->htmlTemplate('emails/errors/domain_order.html.twig') - ->locale('en') - ->context([ - 'domain' => $domain, - ]); - - $this->mailer->send($email); - } - - /** - * @throws TransportExceptionInterface - */ - private function sendEmailDomainUpdated(DomainEvent $domainEvent, User $user): void - { - $email = (new TemplatedEmail()) - ->from(new Address($this->mailerSenderEmail, $this->mailerSenderName)) - ->to($user->getEmail()) - ->priority(Email::PRIORITY_HIGHEST) - ->subject('A domain name has been changed') - ->htmlTemplate('emails/success/domain_updated.html.twig') - ->locale('en') - ->context([ - 'event' => $domainEvent, - ]); - - $this->mailer->send($email); - } } diff --git a/src/MessageHandler/ProcessWatchListTriggerHandler.php b/src/MessageHandler/ProcessWatchListTriggerHandler.php index c43d9c5..c5c77fb 100644 --- a/src/MessageHandler/ProcessWatchListTriggerHandler.php +++ b/src/MessageHandler/ProcessWatchListTriggerHandler.php @@ -3,33 +3,36 @@ namespace App\MessageHandler; use App\Entity\Domain; -use App\Entity\User; use App\Entity\WatchList; use App\Message\ProcessDomainTrigger; use App\Message\ProcessWatchListTrigger; +use App\Notifier\DomainUpdateErrorNotification; use App\Repository\WatchListRepository; use App\Service\RDAPService; use Psr\Log\LoggerInterface; -use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Exception\ExceptionInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Mime\Address; +use Symfony\Component\Notifier\Recipient\Recipient; #[AsMessageHandler] final readonly class ProcessWatchListTriggerHandler { + private Address $sender; + public function __construct( private RDAPService $RDAPService, private MailerInterface $mailer, - private string $mailerSenderEmail, - private string $mailerSenderName, + string $mailerSenderEmail, + string $mailerSenderName, private MessageBusInterface $bus, private WatchListRepository $watchListRepository, private LoggerInterface $logger ) { + $this->sender = new Address($mailerSenderEmail, $mailerSenderName); } /** @@ -63,28 +66,12 @@ final readonly class ProcessWatchListTriggerHandler 'username' => $watchList->getUser()->getUserIdentifier(), 'error' => $e, ]); - $this->sendEmailDomainUpdateError($domain, $watchList->getUser()); + $email = (new DomainUpdateErrorNotification($this->sender, $domain)) + ->asEmailMessage(new Recipient($watchList->getUser()->getEmail())); + $this->mailer->send($email->getMessage()); } $this->bus->dispatch(new ProcessDomainTrigger($watchList->getToken(), $domain->getLdhName(), $updatedAt)); } } - - /** - * @throws TransportExceptionInterface - */ - private function sendEmailDomainUpdateError(Domain $domain, User $user): void - { - $email = (new TemplatedEmail()) - ->from(new Address($this->mailerSenderEmail, $this->mailerSenderName)) - ->to($user->getEmail()) - ->subject('An error occurred while updating a domain name') - ->htmlTemplate('emails/errors/domain_update.html.twig') - ->locale('en') - ->context([ - 'domain' => $domain, - ]); - - $this->mailer->send($email); - } } diff --git a/src/Notifier/DomainOrderErrorNotification.php b/src/Notifier/DomainOrderErrorNotification.php new file mode 100644 index 0000000..8174486 --- /dev/null +++ b/src/Notifier/DomainOrderErrorNotification.php @@ -0,0 +1,44 @@ +subject('Error: Domain Order'); + + return ChatMessage::fromNotification($this); + } + + public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): EmailMessage + { + return new EmailMessage((new TemplatedEmail()) + ->from($this->sender) + ->to($recipient->getEmail()) + ->subject('An error occurred while ordering a domain name') + ->htmlTemplate('emails/errors/domain_order.html.twig') + ->locale('en') + ->context([ + 'domain' => $this->domain, + ])); + } +} diff --git a/src/Notifier/DomainOrderNotification.php b/src/Notifier/DomainOrderNotification.php new file mode 100644 index 0000000..9131dc4 --- /dev/null +++ b/src/Notifier/DomainOrderNotification.php @@ -0,0 +1,49 @@ +subject('Domain Ordered'); + + return ChatMessage::fromNotification($this); + } + + public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): EmailMessage + { + return new EmailMessage((new TemplatedEmail()) + ->from($this->sender) + ->to($recipient->getEmail()) + ->priority(Email::PRIORITY_HIGHEST) + ->subject('A domain name has been ordered') + ->htmlTemplate('emails/success/domain_ordered.html.twig') + ->locale('en') + ->context([ + 'domain' => $this->domain, + 'provider' => $this->connector->getProvider()->value, + ])); + } +} diff --git a/src/Notifier/DomainUpdateErrorNotification.php b/src/Notifier/DomainUpdateErrorNotification.php new file mode 100644 index 0000000..063a27d --- /dev/null +++ b/src/Notifier/DomainUpdateErrorNotification.php @@ -0,0 +1,44 @@ +subject('Error: Domain Update'); + + return ChatMessage::fromNotification($this); + } + + public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): EmailMessage + { + return new EmailMessage((new TemplatedEmail()) + ->from($this->sender) + ->to($recipient->getEmail()) + ->subject('An error occurred while updating a domain name') + ->htmlTemplate('emails/errors/domain_update.html.twig') + ->locale('en') + ->context([ + 'domain' => $this->domain, + ])); + } +} diff --git a/src/Notifier/DomainUpdateNotification.php b/src/Notifier/DomainUpdateNotification.php new file mode 100644 index 0000000..49cfe36 --- /dev/null +++ b/src/Notifier/DomainUpdateNotification.php @@ -0,0 +1,46 @@ +subject('Domain Updated'); + + return ChatMessage::fromNotification($this); + } + + public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): EmailMessage + { + return new EmailMessage((new TemplatedEmail()) + ->from($this->sender) + ->to($recipient->getEmail()) + ->priority(Email::PRIORITY_HIGHEST) + ->subject('A domain name has been changed') + ->htmlTemplate('emails/success/domain_updated.html.twig') + ->locale('en') + ->context([ + 'event' => $this->domainEvent, + ])); + } +} diff --git a/src/Notifier/TestChatNotification.php b/src/Notifier/TestChatNotification.php new file mode 100644 index 0000000..ca3f434 --- /dev/null +++ b/src/Notifier/TestChatNotification.php @@ -0,0 +1,19 @@ +subject('Test notification'); + $this->content('This is a test message. If you can read me, this Webhook is configured correctly'); + + return ChatMessage::fromNotification($this); + } +} diff --git a/symfony.lock b/symfony.lock index e266829..83aa0f0 100644 --- a/symfony.lock +++ b/symfony.lock @@ -153,6 +153,15 @@ "config/packages/debug.yaml" ] }, + "symfony/discord-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.2", + "ref": "b97655f9a2fb8fc04d9f4081e0b5599d897b7f6e" + } + }, "symfony/flex": { "version": "2.4", "recipe": { @@ -184,6 +193,15 @@ "src/Kernel.php" ] }, + "symfony/google-chat-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "5954a3403bf1cdc557e2b71d3854cc81ba7d37cb" + } + }, "symfony/lock": { "version": "7.1", "recipe": { @@ -217,6 +235,15 @@ "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" } }, + "symfony/mattermost-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.1", + "ref": "60df16a0ff39e942f6579e624d5630fc6b4e0cc1" + } + }, "symfony/messenger": { "version": "7.1", "recipe": { @@ -229,6 +256,15 @@ "config/packages/messenger.yaml" ] }, + "symfony/microsoft-teams-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "e4e1704f0b11573aaededc00640492c915de0bbe" + } + }, "symfony/monolog-bundle": { "version": "3.10", "recipe": { @@ -268,6 +304,15 @@ "tests/bootstrap.php" ] }, + "symfony/rocket-chat-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.1", + "ref": "5c91d24b503de5cc0d0eb880fc95afa1bef8b6f4" + } + }, "symfony/routing": { "version": "7.1", "recipe": { @@ -294,6 +339,15 @@ "config/routes/security.yaml" ] }, + "symfony/slack-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.2", + "ref": "8fb9603326990013efbe6d71c2dd78ada316808a" + } + }, "symfony/stimulus-bundle": { "version": "2.18", "recipe": { @@ -308,6 +362,15 @@ "assets/controllers/hello_controller.js" ] }, + "symfony/telegram-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.0", + "ref": "6cecb59a0e96c9e1cee469f2b82fa920101a68e8" + } + }, "symfony/translation": { "version": "7.1", "recipe": { @@ -387,6 +450,15 @@ "webpack.config.js" ] }, + "symfony/zulip-notifier": { + "version": "7.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.2", + "ref": "f420901c554baf7cde79a2a0bbf9b37ab1a650aa" + } + }, "symfonycasts/verify-email-bundle": { "version": "v1.17.0" }, diff --git a/yarn.lock b/yarn.lock index 5a203cf..597413d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1504,6 +1504,21 @@ resolved "https://registry.yarnpkg.com/@fontsource/noto-color-emoji/-/noto-color-emoji-5.0.27.tgz#61e40657bea980553bde8fd2d566104bd2859ad6" integrity sha512-gsIMN5o8qoRLrA+XyDNKKnMNpTbwpNbINisJqirLOLXl83arOV2sHRnNOkVht2gzUcImUxEUBGektp56G3Vj9w== +"@hotwired/stimulus-webpack-helpers@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd" + integrity sha512-wa/zupVG0eWxRYJjC1IiPBdt3Lruv0RqGN+/DTMmUWUyMAEB27KXmVY6a8YpUVTM7QwVuaLNGW4EqDgrS2upXQ== + +"@hotwired/stimulus@^3.0.0": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608" + integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A== + +"@hotwired/turbo@^7.1.1 || ^8.0": + version "8.0.5" + resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-8.0.5.tgz#abae6dad018a891e4286e87fa0959217e3866d5a" + integrity sha512-TdZDA7fxVQ2ZycygvpnzjGPmFq4sO/E2QVg+2em/sJ3YTSsIWVEis8HmWlumz+c9DjWcUkcCuB+muF08TInpAQ== + "@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" @@ -1670,6 +1685,20 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@symfony/stimulus-bridge@^3.2.0": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@symfony/stimulus-bridge/-/stimulus-bridge-3.2.2.tgz#afc1918f82d78cb2b6e299285c54094aa7f53696" + integrity sha512-kIaUEGPXW7g14zsHkIvQWw8cmfCdXSqsEQx18fuHPBb+R0h8nYPyY+e9uVtTuHlE2wHwAjrJoc6YBBK4a7CpKA== + dependencies: + "@hotwired/stimulus-webpack-helpers" "^1.0.1" + "@types/webpack-env" "^1.16.4" + acorn "^8.0.5" + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +"@symfony/ux-turbo@file:vendor/symfony/ux-turbo/assets": + version "0.1.0" + "@symfony/webpack-encore@^4.0.0": version "4.6.1" resolved "https://registry.yarnpkg.com/@symfony/webpack-encore/-/webpack-encore-4.6.1.tgz#a3ced0baf1b02feb6d1a564906aff0e479b07259" @@ -1993,6 +2022,11 @@ dependencies: "@types/node" "*" +"@types/webpack-env@^1.16.4": + version "1.18.5" + resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.5.tgz#eccda0b04fe024bed505881e2e532f9c119169bf" + integrity sha512-wz7kjjRRj8/Lty4B+Kr0LN6Ypc/3SymeCCGSbaXp2leH0ZVg/PriNiOwNj4bD4uphI7A8NXS4b6Gl373sfO5mA== + "@types/ws@^8.5.5": version "8.5.11" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.11.tgz#90ad17b3df7719ce3e6bc32f83ff954d38656508" @@ -2202,7 +2236,7 @@ acorn-import-attributes@^1.9.5: resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== -acorn@^8.7.1, acorn@^8.8.2: +acorn@^8.0.5, acorn@^8.7.1, acorn@^8.8.2: version "8.12.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== @@ -6020,7 +6054,7 @@ scheduler@^0.23.2: dependencies: loose-envify "^1.1.0" -schema-utils@^3.1.1, schema-utils@^3.2.0: +schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== From 64aba20a93ad195ecb111b1ed0cbc172877b4c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Fri, 16 Aug 2024 23:57:52 +0200 Subject: [PATCH 056/257] feat: add Webhook support on frontend --- .../watchlist/UpdateWatchlistButton.tsx | 5 +- .../tracking/watchlist/WatchlistForm.tsx | 53 +++++++++++++++++-- .../tracking/watchlist/WatchlistsList.tsx | 2 +- assets/pages/tracking/WatchlistPage.tsx | 24 ++++++--- assets/utils/api/index.ts | 2 + 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx b/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx index 22206b2..6286a1b 100644 --- a/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx +++ b/assets/components/tracking/watchlist/UpdateWatchlistButton.tsx @@ -8,7 +8,7 @@ import {Connector} from "../../../utils/api/connectors"; export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors}: { watchlist: Watchlist, - onUpdateWatchlist: (values: { domains: string[], emailTriggers: string[], token: string }) => Promise, + onUpdateWatchlist: (values: { domains: string[], triggers: string[], token: string }) => Promise, connectors: (Connector & { id: string })[] }) { @@ -35,7 +35,8 @@ export function UpdateWatchlistButton({watchlist, onUpdateWatchlist, connectors} {name: 'name', value: watchlist.name}, {name: 'connector', value: watchlist.connector?.id}, {name: 'domains', value: watchlist.domains.map(d => d.ldhName)}, - {name: 'emailTriggers', value: watchlist.triggers?.map(t => t.event)}, + {name: 'triggers', value: watchlist.triggers?.map(t => t.event)}, + {name: 'dsn', value: watchlist.dsn} ]) }}/> diff --git a/assets/components/tracking/watchlist/WatchlistForm.tsx b/assets/components/tracking/watchlist/WatchlistForm.tsx index 15d3e9d..36b4159 100644 --- a/assets/components/tracking/watchlist/WatchlistForm.tsx +++ b/assets/components/tracking/watchlist/WatchlistForm.tsx @@ -28,7 +28,7 @@ const formItemLayoutWithOutLabel = { export function WatchlistForm({form, connectors, onFinish, isCreation}: { form: FormInstance, connectors: (Connector & { id: string })[] - onFinish: (values: { domains: string[], emailTriggers: string[], token: string }) => void + onFinish: (values: { domains: string[], triggers: string[], token: string }) => void isCreation: boolean }) { const domainEventTranslated = domainEvent() @@ -56,7 +56,7 @@ export function WatchlistForm({form, connectors, onFinish, isCreation}: { {...formItemLayoutWithOutLabel} form={form} onFinish={onFinish} - initialValues={{emailTriggers: ['last changed', 'transfer', 'expiration', 'deletion']}} + initialValues={{triggers: ['last changed', 'transfer', 'expiration', 'deletion']}} >