WIP
This commit is contained in:
@@ -0,0 +1,258 @@
|
|||||||
|
name: myep-team
|
||||||
|
type: php
|
||||||
|
docroot: public
|
||||||
|
php_version: "8.1"
|
||||||
|
webserver_type: apache-fpm
|
||||||
|
router_http_port: "80"
|
||||||
|
router_https_port: "443"
|
||||||
|
xdebug_enabled: false
|
||||||
|
additional_hostnames: []
|
||||||
|
additional_fqdns: []
|
||||||
|
database:
|
||||||
|
type: mariadb
|
||||||
|
version: "10.4"
|
||||||
|
nfs_mount_enabled: false
|
||||||
|
mutagen_enabled: false
|
||||||
|
use_dns_when_possible: true
|
||||||
|
composer_version: "2"
|
||||||
|
web_environment: []
|
||||||
|
nodejs_version: "16"
|
||||||
|
omit_containers: [dba]
|
||||||
|
|
||||||
|
# Key features of ddev's config.yaml:
|
||||||
|
|
||||||
|
# name: <projectname> # Name of the project, automatically provides
|
||||||
|
# http://projectname.ddev.site and https://projectname.ddev.site
|
||||||
|
|
||||||
|
# type: <projecttype> # drupal6/7/8, backdrop, typo3, wordpress, php
|
||||||
|
|
||||||
|
# docroot: <relative_path> # Relative path to the directory containing index.php.
|
||||||
|
|
||||||
|
# php_version: "7.4" # PHP version to use, "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2"
|
||||||
|
|
||||||
|
# You can explicitly specify the webimage but this
|
||||||
|
# is not recommended, as the images are often closely tied to ddev's' behavior,
|
||||||
|
# so this can break upgrades.
|
||||||
|
|
||||||
|
# webimage: <docker_image> # nginx/php docker image.
|
||||||
|
|
||||||
|
# database:
|
||||||
|
# type: <dbtype> # mysql, mariadb
|
||||||
|
# version: <version> # database version, like "10.3" or "8.0"
|
||||||
|
# Note that mariadb_version or mysql_version from v1.18 and earlier
|
||||||
|
# will automatically be converted to this notation with just a "ddev config --auto"
|
||||||
|
|
||||||
|
# router_http_port: <port> # Port to be used for http (defaults to port 80)
|
||||||
|
# router_https_port: <port> # Port for https (defaults to 443)
|
||||||
|
|
||||||
|
# xdebug_enabled: false # Set to true to enable xdebug and "ddev start" or "ddev restart"
|
||||||
|
# Note that for most people the commands
|
||||||
|
# "ddev xdebug" to enable xdebug and "ddev xdebug off" to disable it work better,
|
||||||
|
# as leaving xdebug enabled all the time is a big performance hit.
|
||||||
|
|
||||||
|
# xhprof_enabled: false # Set to true to enable xhprof and "ddev start" or "ddev restart"
|
||||||
|
# Note that for most people the commands
|
||||||
|
# "ddev xhprof" to enable xhprof and "ddev xhprof off" to disable it work better,
|
||||||
|
# as leaving xhprof enabled all the time is a big performance hit.
|
||||||
|
|
||||||
|
# webserver_type: nginx-fpm # or apache-fpm
|
||||||
|
|
||||||
|
# timezone: Europe/Berlin
|
||||||
|
# This is the timezone used in the containers and by PHP;
|
||||||
|
# it can be set to any valid timezone,
|
||||||
|
# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
|
# For example Europe/Dublin or MST7MDT
|
||||||
|
|
||||||
|
# composer_root: <relative_path>
|
||||||
|
# Relative path to the composer root directory from the project root. This is
|
||||||
|
# the directory which contains the composer.json and where all Composer related
|
||||||
|
# commands are executed.
|
||||||
|
|
||||||
|
# composer_version: "2"
|
||||||
|
# You can set it to "" or "2" (default) for Composer v2 or "1" for Composer v1
|
||||||
|
# to use the latest major version available at the time your container is built.
|
||||||
|
# It is also possible to use each other Composer version channel. This includes:
|
||||||
|
# - 2.2 (latest Composer LTS version)
|
||||||
|
# - stable
|
||||||
|
# - preview
|
||||||
|
# - snapshot
|
||||||
|
# Alternatively, an explicit Composer version may be specified, for example "2.2.18".
|
||||||
|
# To reinstall Composer after the image was built, run "ddev debug refresh".
|
||||||
|
|
||||||
|
# nodejs_version: "16"
|
||||||
|
# change from the default system Node.js version to another supported version, like 12, 14, 17, 18.
|
||||||
|
# Note that you can use 'ddev nvm' or nvm inside the web container to provide nearly any
|
||||||
|
# Node.js version, including v6, etc.
|
||||||
|
|
||||||
|
# additional_hostnames:
|
||||||
|
# - somename
|
||||||
|
# - someothername
|
||||||
|
# would provide http and https URLs for "somename.ddev.site"
|
||||||
|
# and "someothername.ddev.site".
|
||||||
|
|
||||||
|
# additional_fqdns:
|
||||||
|
# - example.com
|
||||||
|
# - sub1.example.com
|
||||||
|
# would provide http and https URLs for "example.com" and "sub1.example.com"
|
||||||
|
# Please take care with this because it can cause great confusion.
|
||||||
|
|
||||||
|
# upload_dir: custom/upload/dir
|
||||||
|
# would set the destination path for ddev import-files to <docroot>/custom/upload/dir
|
||||||
|
# When mutagen is enabled this path is bind-mounted so that all the files
|
||||||
|
# in the upload_dir don't have to be synced into mutagen
|
||||||
|
|
||||||
|
# working_dir:
|
||||||
|
# web: /var/www/html
|
||||||
|
# db: /home
|
||||||
|
# would set the default working directory for the web and db services.
|
||||||
|
# These values specify the destination directory for ddev ssh and the
|
||||||
|
# directory in which commands passed into ddev exec are run.
|
||||||
|
|
||||||
|
# omit_containers: [db, dba, ddev-ssh-agent]
|
||||||
|
# Currently only these containers are supported. Some containers can also be
|
||||||
|
# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit
|
||||||
|
# the "db" container, several standard features of ddev that access the
|
||||||
|
# database container will be unusable. In the global configuration it is also
|
||||||
|
# possible to omit ddev-router, but not here.
|
||||||
|
|
||||||
|
# nfs_mount_enabled: false
|
||||||
|
# Great performance improvement but requires host configuration first.
|
||||||
|
# See https://ddev.readthedocs.io/en/latest/users/install/performance/#nfs
|
||||||
|
|
||||||
|
# mutagen_enabled: false
|
||||||
|
# Performance improvement using mutagen asynchronous updates.
|
||||||
|
# See https://ddev.readthedocs.io/en/latest/users/install/performance/#mutagen
|
||||||
|
|
||||||
|
# fail_on_hook_fail: False
|
||||||
|
# Decide whether 'ddev start' should be interrupted by a failing hook
|
||||||
|
|
||||||
|
# host_https_port: "59002"
|
||||||
|
# The host port binding for https can be explicitly specified. It is
|
||||||
|
# dynamic unless otherwise specified.
|
||||||
|
# This is not used by most people, most people use the *router* instead
|
||||||
|
# of the localhost port.
|
||||||
|
|
||||||
|
# host_webserver_port: "59001"
|
||||||
|
# The host port binding for the ddev-webserver can be explicitly specified. It is
|
||||||
|
# dynamic unless otherwise specified.
|
||||||
|
# This is not used by most people, most people use the *router* instead
|
||||||
|
# of the localhost port.
|
||||||
|
|
||||||
|
# host_db_port: "59002"
|
||||||
|
# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic
|
||||||
|
# unless explicitly specified.
|
||||||
|
|
||||||
|
# phpmyadmin_port: "8036"
|
||||||
|
# phpmyadmin_https_port: "8037"
|
||||||
|
# The PHPMyAdmin ports can be changed from the default 8036 and 8037
|
||||||
|
|
||||||
|
# host_phpmyadmin_port: "8036"
|
||||||
|
# The phpmyadmin (dba) port is not normally bound on the host at all, instead being routed
|
||||||
|
# through ddev-router, but it can be specified and bound.
|
||||||
|
|
||||||
|
# mailhog_port: "8025"
|
||||||
|
# mailhog_https_port: "8026"
|
||||||
|
# The MailHog ports can be changed from the default 8025 and 8026
|
||||||
|
|
||||||
|
# host_mailhog_port: "8025"
|
||||||
|
# The mailhog port is not normally bound on the host at all, instead being routed
|
||||||
|
# through ddev-router, but it can be bound directly to localhost if specified here.
|
||||||
|
|
||||||
|
# webimage_extra_packages: [php7.4-tidy, php-bcmath]
|
||||||
|
# Extra Debian packages that are needed in the webimage can be added here
|
||||||
|
|
||||||
|
# dbimage_extra_packages: [telnet,netcat]
|
||||||
|
# Extra Debian packages that are needed in the dbimage can be added here
|
||||||
|
|
||||||
|
# use_dns_when_possible: true
|
||||||
|
# If the host has internet access and the domain configured can
|
||||||
|
# successfully be looked up, DNS will be used for hostname resolution
|
||||||
|
# instead of editing /etc/hosts
|
||||||
|
# Defaults to true
|
||||||
|
|
||||||
|
# project_tld: ddev.site
|
||||||
|
# The top-level domain used for project URLs
|
||||||
|
# The default "ddev.site" allows DNS lookup via a wildcard
|
||||||
|
# If you prefer you can change this to "ddev.local" to preserve
|
||||||
|
# pre-v1.9 behavior.
|
||||||
|
|
||||||
|
# ngrok_args: --basic-auth username:pass1234
|
||||||
|
# Provide extra flags to the "ngrok http" command, see
|
||||||
|
# https://ngrok.com/docs#http or run "ngrok http -h"
|
||||||
|
|
||||||
|
# disable_settings_management: false
|
||||||
|
# If true, ddev will not create CMS-specific settings files like
|
||||||
|
# Drupal's settings.php/settings.ddev.php or TYPO3's AdditionalConfiguration.php
|
||||||
|
# In this case the user must provide all such settings.
|
||||||
|
|
||||||
|
# You can inject environment variables into the web container with:
|
||||||
|
# web_environment:
|
||||||
|
# - SOMEENV=somevalue
|
||||||
|
# - SOMEOTHERENV=someothervalue
|
||||||
|
|
||||||
|
# no_project_mount: false
|
||||||
|
# (Experimental) If true, ddev will not mount the project into the web container;
|
||||||
|
# the user is responsible for mounting it manually or via a script.
|
||||||
|
# This is to enable experimentation with alternate file mounting strategies.
|
||||||
|
# For advanced users only!
|
||||||
|
|
||||||
|
# bind_all_interfaces: false
|
||||||
|
# If true, host ports will be bound on all network interfaces,
|
||||||
|
# not just the localhost interface. This means that ports
|
||||||
|
# will be available on the local network if the host firewall
|
||||||
|
# allows it.
|
||||||
|
|
||||||
|
# default_container_timeout: 120
|
||||||
|
# The default time that ddev waits for all containers to become ready can be increased from
|
||||||
|
# the default 120. This helps in importing huge databases, for example.
|
||||||
|
|
||||||
|
#web_extra_exposed_ports:
|
||||||
|
#- name: nodejs
|
||||||
|
# container_port: 3000
|
||||||
|
# http_port: 2999
|
||||||
|
# https_port: 3000
|
||||||
|
#- name: something
|
||||||
|
# container_port: 4000
|
||||||
|
# https_port: 4000
|
||||||
|
# http_port: 3999
|
||||||
|
# Allows a set of extra ports to be exposed via ddev-router
|
||||||
|
# The port behavior on the ddev-webserver must be arranged separately, for example
|
||||||
|
# using web_extra_daemons.
|
||||||
|
# For example, with a web app on port 3000 inside the container, this config would
|
||||||
|
# expose that web app on https://<project>.ddev.site:9999 and http://<project>.ddev.site:9998
|
||||||
|
# web_extra_exposed_ports:
|
||||||
|
# - container_port: 3000
|
||||||
|
# http_port: 9998
|
||||||
|
# https_port: 9999
|
||||||
|
|
||||||
|
#web_extra_daemons:
|
||||||
|
#- name: "http-1"
|
||||||
|
# command: "/var/www/html/node_modules/.bin/http-server -p 3000"
|
||||||
|
# directory: /var/www/html
|
||||||
|
#- name: "http-2"
|
||||||
|
# command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000"
|
||||||
|
# directory: /var/www/html
|
||||||
|
|
||||||
|
# override_config: false
|
||||||
|
# By default, config.*.yaml files are *merged* into the configuration
|
||||||
|
# But this means that some things can't be overridden
|
||||||
|
# For example, if you have 'nfs_mount_enabled: true'' you can't override it with a merge
|
||||||
|
# and you can't erase existing hooks or all environment variables.
|
||||||
|
# However, with "override_config: true" in a particular config.*.yaml file,
|
||||||
|
# 'nfs_mount_enabled: false' can override the existing values, and
|
||||||
|
# hooks:
|
||||||
|
# post-start: []
|
||||||
|
# or
|
||||||
|
# web_environment: []
|
||||||
|
# or
|
||||||
|
# additional_hostnames: []
|
||||||
|
# can have their intended affect. 'override_config' affects only behavior of the
|
||||||
|
# config.*.yaml file it exists in.
|
||||||
|
|
||||||
|
# Many ddev commands can be extended to run tasks before or after the
|
||||||
|
# ddev command is executed, for example "post-start", "post-import-db",
|
||||||
|
# "pre-composer", "post-composer"
|
||||||
|
# See https://ddev.readthedocs.io/en/stable/users/extend/custom-commands/ for more
|
||||||
|
# information on the commands that can be extended and the tasks you can define
|
||||||
|
# for them. Example:
|
||||||
|
#hooks:
|
||||||
@@ -39,3 +39,7 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
|||||||
###> symfony/mailer ###
|
###> symfony/mailer ###
|
||||||
# MAILER_DSN=null://null
|
# MAILER_DSN=null://null
|
||||||
###< symfony/mailer ###
|
###< symfony/mailer ###
|
||||||
|
|
||||||
|
APP_BPN_USER=
|
||||||
|
APP_BPN_PASSWORD=
|
||||||
|
APP_BPN_ENDPOINT=
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
https://www.ep-reisen.de/buchung/xmlanfrage.php?
|
||||||
|
operation=<?xml version="1.0" encoding="utf-8"?><anfrage><user>Kuschick</user><key>1a1c8a7235369a0ea2313444c84c5375</key><satz typ="KUNDENKONTO"/><art>Adressdaten</art><email>[email protected]</email><passwort>ed0ac03a0f0f1eeb11249cc9edbab6cb</passwort></anfrage>
|
||||||
+2
-1
@@ -12,6 +12,7 @@
|
|||||||
"doctrine/orm": "^2.15",
|
"doctrine/orm": "^2.15",
|
||||||
"phpdocumentor/reflection-docblock": "^5.3",
|
"phpdocumentor/reflection-docblock": "^5.3",
|
||||||
"phpstan/phpdoc-parser": "^1.22",
|
"phpstan/phpdoc-parser": "^1.22",
|
||||||
|
"symfony/apache-pack": "^1.0",
|
||||||
"symfony/asset": "6.3.*",
|
"symfony/asset": "6.3.*",
|
||||||
"symfony/console": "6.3.*",
|
"symfony/console": "6.3.*",
|
||||||
"symfony/doctrine-messenger": "6.3.*",
|
"symfony/doctrine-messenger": "6.3.*",
|
||||||
@@ -85,7 +86,7 @@
|
|||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"symfony": {
|
"symfony": {
|
||||||
"allow-contrib": false,
|
"allow-contrib": true,
|
||||||
"require": "6.3.*"
|
"require": "6.3.*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+27
-1
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5625360c4bf0ca4c404a3a47e7b43354",
|
"content-hash": "321e741fbc0979c63e04752cd30aba64",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "doctrine/cache",
|
"name": "doctrine/cache",
|
||||||
@@ -2008,6 +2008,32 @@
|
|||||||
},
|
},
|
||||||
"time": "2021-07-14T16:46:02+00:00"
|
"time": "2021-07-14T16:46:02+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/apache-pack",
|
||||||
|
"version": "v1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/apache-pack.git",
|
||||||
|
"reference": "3aa5818d73ad2551281fc58a75afd9ca82622e6c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/apache-pack/zipball/3aa5818d73ad2551281fc58a75afd9ca82622e6c",
|
||||||
|
"reference": "3aa5818d73ad2551281fc58a75afd9ca82622e6c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"type": "symfony-pack",
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "A pack for Apache support in Symfony",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/symfony/apache-pack/issues",
|
||||||
|
"source": "https://github.com/symfony/apache-pack/tree/master"
|
||||||
|
},
|
||||||
|
"time": "2017-12-12T01:46:35+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/asset",
|
"name": "symfony/asset",
|
||||||
"version": "v6.3.0",
|
"version": "v6.3.0",
|
||||||
|
|||||||
@@ -1,37 +1,28 @@
|
|||||||
security:
|
security:
|
||||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
|
||||||
password_hashers:
|
password_hashers:
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
|
||||||
providers:
|
providers:
|
||||||
users_in_memory: { memory: null }
|
bpn_user_provider:
|
||||||
|
entity:
|
||||||
|
class: App\Entity\User
|
||||||
|
property: email
|
||||||
|
|
||||||
firewalls:
|
firewalls:
|
||||||
dev:
|
dev:
|
||||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||||
security: false
|
security: false
|
||||||
main:
|
main:
|
||||||
lazy: true
|
lazy: true
|
||||||
provider: users_in_memory
|
provider: bpn_user_provider
|
||||||
|
custom_authenticators:
|
||||||
# activate different ways to authenticate
|
- App\Security\BpnAuthenticator
|
||||||
# https://symfony.com/doc/current/security.html#the-firewall
|
|
||||||
|
|
||||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
|
||||||
# switch_user: true
|
|
||||||
|
|
||||||
# Easy way to control access for large sections of your site
|
|
||||||
# Note: Only the *first* access control that matches will be used
|
|
||||||
access_control:
|
access_control:
|
||||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
- { path: ^/profile, roles: ROLE_USER }
|
||||||
# - { path: ^/profile, roles: ROLE_USER }
|
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
security:
|
security:
|
||||||
password_hashers:
|
password_hashers:
|
||||||
# By default, password hashers are resource intensive and take time. This is
|
|
||||||
# important to generate secure password hashes. In tests however, secure hashes
|
|
||||||
# are not important, waste resources and increase test times. The following
|
|
||||||
# reduces the work factor to the lowest possible values.
|
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||||
algorithm: auto
|
algorithm: auto
|
||||||
cost: 4 # Lowest possible value for bcrypt
|
cost: 4 # Lowest possible value for bcrypt
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# This file is the entry point to configure your own services.
|
|
||||||
# Files in the packages/ subdirectory configure your dependencies.
|
|
||||||
|
|
||||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
|
||||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
|
||||||
parameters:
|
parameters:
|
||||||
|
bpn_url: '%env(APP_BPN_ENDPOINT)%'
|
||||||
|
bpn_username: '%env(APP_BPN_USER)%'
|
||||||
|
bpn_password: '%env(APP_BPN_PASSWORD)%'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# default configuration for services in *this* file
|
# default configuration for services in *this* file
|
||||||
@@ -20,5 +18,6 @@ services:
|
|||||||
- '../src/Entity/'
|
- '../src/Entity/'
|
||||||
- '../src/Kernel.php'
|
- '../src/Kernel.php'
|
||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
App\BusProNet\ApiClient:
|
||||||
# please note that last definitions always *replace* previous ones
|
arguments:
|
||||||
|
$options: { 'bpn_username': '%bpn_username%', 'bpn_password': '%bpn_password%', 'bpn_url': '%bpn_url%' }
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database:
|
|
||||||
ports:
|
|
||||||
- "5432"
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
|
|
||||||
###> symfony/mailer ###
|
|
||||||
mailer:
|
|
||||||
image: schickling/mailcatcher
|
|
||||||
ports: ["1025", "1080"]
|
|
||||||
###< symfony/mailer ###
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database:
|
|
||||||
image: postgres:${POSTGRES_VERSION:-15}-alpine
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-app}
|
|
||||||
# You should definitely change the password in production
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-app}
|
|
||||||
volumes:
|
|
||||||
- database_data:/var/lib/postgresql/data:rw
|
|
||||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
|
|
||||||
# - ./docker/db/data:/var/lib/postgresql/data:rw
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database_data:
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230707115553 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, bus_pro_address_id INT NOT NULL, email VARCHAR(255) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, role VARCHAR(255) NOT NULL, last_login_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', available_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivered_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP TABLE user');
|
||||||
|
$this->addSql('DROP TABLE messenger_messages');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230707135208 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE user ADD bus_pro_person_id INT NOT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('ALTER TABLE user DROP bus_pro_person_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# Use the front controller as index file. It serves as a fallback solution when
|
||||||
|
# every other rewrite/redirect fails (e.g. in an aliased environment without
|
||||||
|
# mod_rewrite). Additionally, this reduces the matching process for the
|
||||||
|
# start page (path "/") because otherwise Apache will apply the rewriting rules
|
||||||
|
# to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
|
||||||
|
DirectoryIndex index.php
|
||||||
|
|
||||||
|
# By default, Apache does not evaluate symbolic links if you did not enable this
|
||||||
|
# feature in your server configuration. Uncomment the following line if you
|
||||||
|
# install assets as symlinks or if you experience problems related to symlinks
|
||||||
|
# when compiling LESS/Sass/CoffeScript assets.
|
||||||
|
# Options +FollowSymlinks
|
||||||
|
|
||||||
|
# Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve
|
||||||
|
# to the front controller "/index.php" but be rewritten to "/index.php/index".
|
||||||
|
<IfModule mod_negotiation.c>
|
||||||
|
Options -MultiViews
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
# This Option needs to be enabled for RewriteRule, otherwise it will show an error like
|
||||||
|
# 'Options FollowSymLinks or SymLinksIfOwnerMatch is off which implies that RewriteRule directive is forbidden'
|
||||||
|
Options +FollowSymlinks
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
|
||||||
|
# Determine the RewriteBase automatically and set it as environment variable.
|
||||||
|
# If you are using Apache aliases to do mass virtual hosting or installed the
|
||||||
|
# project in a subdirectory, the base path will be prepended to allow proper
|
||||||
|
# resolution of the index.php file and to redirect to the correct URI. It will
|
||||||
|
# work in environments without path prefix as well, providing a safe, one-size
|
||||||
|
# fits all solution. But as you do not need it in this case, you can comment
|
||||||
|
# the following 2 lines to eliminate the overhead.
|
||||||
|
RewriteCond %{REQUEST_URI}::$0 ^(/.+)/(.*)::\2$
|
||||||
|
RewriteRule .* - [E=BASE:%1]
|
||||||
|
|
||||||
|
# Sets the HTTP_AUTHORIZATION header removed by Apache
|
||||||
|
RewriteCond %{HTTP:Authorization} .+
|
||||||
|
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0]
|
||||||
|
|
||||||
|
# Redirect to URI without front controller to prevent duplicate content
|
||||||
|
# (with and without `/index.php`). Only do this redirect on the initial
|
||||||
|
# rewrite by Apache and not on subsequent cycles. Otherwise we would get an
|
||||||
|
# endless redirect loop (request -> rewrite to front controller ->
|
||||||
|
# redirect -> request -> ...).
|
||||||
|
# So in case you get a "too many redirects" error or you always get redirected
|
||||||
|
# to the start page because your Apache does not expose the REDIRECT_STATUS
|
||||||
|
# environment variable, you have 2 choices:
|
||||||
|
# - disable this feature by commenting the following 2 lines or
|
||||||
|
# - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
|
||||||
|
# following RewriteCond (best solution)
|
||||||
|
RewriteCond %{ENV:REDIRECT_STATUS} =""
|
||||||
|
RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
|
||||||
|
|
||||||
|
# If the requested filename exists, simply serve it.
|
||||||
|
# We only want to let Apache serve files and not directories.
|
||||||
|
# Rewrite all other queries to the front controller.
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule ^ %{ENV:BASE}/index.php [L]
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
<IfModule mod_alias.c>
|
||||||
|
# When mod_rewrite is not available, we instruct a temporary redirect of
|
||||||
|
# the start page to the front controller explicitly so that the website
|
||||||
|
# and the generated links can still be used.
|
||||||
|
RedirectMatch 307 ^/$ /index.php/
|
||||||
|
# RedirectTemp cannot be used instead
|
||||||
|
</IfModule>
|
||||||
|
</IfModule>
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\CrmAttributeSelection;
|
||||||
|
use App\BusProNet\Model\Profile;
|
||||||
|
use App\BusProNet\Model\ErrorResponse;
|
||||||
|
use App\BusProNet\Model\Result;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||||
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
|
class ApiClient
|
||||||
|
{
|
||||||
|
private array $config;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly HttpClientInterface $httpClient,
|
||||||
|
private readonly SerializerInterface $serializer,
|
||||||
|
array $options
|
||||||
|
) {
|
||||||
|
$this->config = $this->resolveOptions($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ApiClientException
|
||||||
|
*/
|
||||||
|
public function getProfile(string $email, string $password): mixed
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'anfrage' => [
|
||||||
|
'user' => $this->config['bpn_username'],
|
||||||
|
'key' => $this->createKey($this->config['bpn_username'], $this->config['bpn_password'], 'KUNDENKONTO'),
|
||||||
|
'satz' => ['@typ' => 'KUNDENKONTO'],
|
||||||
|
'art' => 'Adressdaten',
|
||||||
|
'email' => $email,
|
||||||
|
'passwort' => md5($password),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$body = $this
|
||||||
|
->serializer
|
||||||
|
->serialize($data, 'xml')
|
||||||
|
;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->httpClient->request('GET', $this->config['bpn_url'], [
|
||||||
|
'query' => [
|
||||||
|
'operation' => $body,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$xml = $response->getContent();
|
||||||
|
|
||||||
|
if (str_contains($xml, 'HINWEIS')) {
|
||||||
|
return $this->serializer->deserialize($xml, ErrorResponse::class, 'xml');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->serializer->deserialize($xml, Profile::class, 'xml');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApiClientException($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateProfile(): void
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ApiClientException
|
||||||
|
*/
|
||||||
|
public function getCrmSelection(string $email, string $password): mixed
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'anfrage' => [
|
||||||
|
'user' => $this->config['bpn_username'],
|
||||||
|
'key' => $this->createKey($this->config['bpn_username'], $this->config['bpn_password'], 'KUNDENKONTO'),
|
||||||
|
'satz' => ['@typ' => 'KUNDENKONTO'],
|
||||||
|
'art' => 'SelektionCRM',
|
||||||
|
'email' => $email,
|
||||||
|
'passwort' => md5($password),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$body = $this
|
||||||
|
->serializer
|
||||||
|
->serialize($data, 'xml')
|
||||||
|
;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->httpClient->request('GET', $this->config['bpn_url'], [
|
||||||
|
'query' => [
|
||||||
|
'operation' => $body,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$xml = $response->getContent();
|
||||||
|
|
||||||
|
if (str_contains($xml, 'HINWEIS')) {
|
||||||
|
return $this->serializer->deserialize($xml, ErrorResponse::class, 'xml');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->serializer->deserialize($xml, CrmAttributeSelection::class, 'xml');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApiClientException($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Creates key for BusPro API access according to documentation
|
||||||
|
*/
|
||||||
|
private function createKey(string $username, string $password, string $type): string
|
||||||
|
{
|
||||||
|
$date = (new \DateTimeImmutable())->format('Ymd');
|
||||||
|
|
||||||
|
return md5($username.$password.$date.$type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveOptions(array $options): array
|
||||||
|
{
|
||||||
|
$optionsResolver = new OptionsResolver();
|
||||||
|
$optionsResolver->setRequired(['bpn_url', 'bpn_username', 'bpn_password']);
|
||||||
|
|
||||||
|
return $optionsResolver->resolve($options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet;
|
||||||
|
|
||||||
|
class ApiClientException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||||
|
|
||||||
|
class Address
|
||||||
|
{
|
||||||
|
#[SerializedName('strasse')]
|
||||||
|
private ?string $street = null;
|
||||||
|
|
||||||
|
#[SerializedName('plz')]
|
||||||
|
private ?string $postCode = null;
|
||||||
|
|
||||||
|
#[SerializedName('ort')]
|
||||||
|
private ?string $city = null;
|
||||||
|
|
||||||
|
#[SerializedName('land')]
|
||||||
|
private ?string $country = null;
|
||||||
|
|
||||||
|
public function getStreet(): ?string
|
||||||
|
{
|
||||||
|
return $this->street;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStreet(?string $street): static
|
||||||
|
{
|
||||||
|
$this->street = $street;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPostCode(): ?string
|
||||||
|
{
|
||||||
|
return $this->postCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPostCode(?string $postCode): static
|
||||||
|
{
|
||||||
|
$this->postCode = $postCode;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCity(): ?string
|
||||||
|
{
|
||||||
|
return $this->city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCity(?string $city): static
|
||||||
|
{
|
||||||
|
$this->city = $city;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCountry(): ?string
|
||||||
|
{
|
||||||
|
return $this->country;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCountry(?string $country): static
|
||||||
|
{
|
||||||
|
$this->country = $country;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||||
|
|
||||||
|
class Communication
|
||||||
|
{
|
||||||
|
#[SerializedName('telefonprivat')]
|
||||||
|
private ?string $phone = null;
|
||||||
|
|
||||||
|
#[SerializedName('telefonmobil')]
|
||||||
|
private ?string $mobile = null;
|
||||||
|
|
||||||
|
#[SerializedName('email')]
|
||||||
|
private ?string $email = null;
|
||||||
|
|
||||||
|
public function getPhone(): ?string
|
||||||
|
{
|
||||||
|
return $this->phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPhone(?string $phone): static
|
||||||
|
{
|
||||||
|
$this->phone = $phone;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMobile(): ?string
|
||||||
|
{
|
||||||
|
return $this->mobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMobile(?string $mobile): static
|
||||||
|
{
|
||||||
|
$this->mobile = $mobile;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmail(): ?string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmail(?string $email): static
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\Ignore;
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||||
|
|
||||||
|
class CrmAttribute
|
||||||
|
{
|
||||||
|
#[SerializedName('@id')]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[SerializedName('@bezeichnung')]
|
||||||
|
private ?string $label = null;
|
||||||
|
|
||||||
|
#[SerializedName('@auswahl')]
|
||||||
|
private ?string $selectedAsString = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setId(?int $id): static
|
||||||
|
{
|
||||||
|
$this->id = $id;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): ?string
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLabel(?string $label): static
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSelectedAsString(): ?string
|
||||||
|
{
|
||||||
|
return $this->selectedAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSelectedAsString(?string $selectedAsString): static
|
||||||
|
{
|
||||||
|
$this->selectedAsString = $selectedAsString;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSelected(): bool
|
||||||
|
{
|
||||||
|
return 'true' === strtolower($this->selectedAsString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSelected(bool $selected): static
|
||||||
|
{
|
||||||
|
$this->selectedAsString = $selected ? 'True' : 'False';
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedPath;
|
||||||
|
|
||||||
|
class CrmAttributeSelection
|
||||||
|
{
|
||||||
|
#[SerializedPath('[selektionsmerkmale][selektionsgruppe]')]
|
||||||
|
private ?array $selectionGroups = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CrmAttributeSelectionGroup[]|null
|
||||||
|
*/
|
||||||
|
public function getSelectionGroups(): ?array
|
||||||
|
{
|
||||||
|
return $this->selectionGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CrmAttributeSelectionGroup[]|null $selectionGroups
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSelectionGroups(?array $selectionGroups): static
|
||||||
|
{
|
||||||
|
$this->selectionGroups = $selectionGroups;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||||
|
|
||||||
|
class CrmAttributeSelectionGroup
|
||||||
|
{
|
||||||
|
#[SerializedName('@bezeichnung')]
|
||||||
|
private ?string $label = null;
|
||||||
|
|
||||||
|
#[SerializedName('selektion')]
|
||||||
|
private ?array $attributes = null;
|
||||||
|
|
||||||
|
public function getLabel(): ?string
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLabel(?string $label): static
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CrmAttribute[]|null
|
||||||
|
*/
|
||||||
|
public function getAttributes(): ?array
|
||||||
|
{
|
||||||
|
return $this->attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CrmAttribute[]|null $attributes
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setAttributes(?array $attributes): static
|
||||||
|
{
|
||||||
|
$this->attributes = $attributes;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedPath;
|
||||||
|
|
||||||
|
class ErrorResponse
|
||||||
|
{
|
||||||
|
#[SerializedPath('[satz][nr]')]
|
||||||
|
private ?string $code;
|
||||||
|
|
||||||
|
#[SerializedPath('[satz][text]')]
|
||||||
|
private ?string $type;
|
||||||
|
|
||||||
|
public function getCode(): ?string
|
||||||
|
{
|
||||||
|
return $this->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCode(?string $code): static
|
||||||
|
{
|
||||||
|
$this->code = $code;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): ?string
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType(?string $type): static
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\BusProNet\Model;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\Context;
|
||||||
|
use Symfony\Component\Serializer\Annotation\SerializedPath;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||||
|
|
||||||
|
class Profile
|
||||||
|
{
|
||||||
|
#[SerializedPath('[idadresse]')]
|
||||||
|
private ?int $addressId = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[idperson]')]
|
||||||
|
private ?int $personId = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][name]')]
|
||||||
|
private ?string $name = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][vorname]')]
|
||||||
|
private ?string $firstName = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][anrede]')]
|
||||||
|
private ?string $salutation = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][titel]')]
|
||||||
|
private ?string $title = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][geschlecht]')]
|
||||||
|
private ?string $gender = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][geburtsdatum]')]
|
||||||
|
#[Context([DateTimeNormalizer::FORMAT_KEY => 'd.m.Y'])]
|
||||||
|
private ?\DateTimeImmutable $dateOfBirth = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][anschrift]')]
|
||||||
|
private ?Address $address = null;
|
||||||
|
|
||||||
|
#[SerializedPath('[adressdaten][kommunikation]')]
|
||||||
|
private ?Communication $communication = null;
|
||||||
|
|
||||||
|
public function getAddressId(): ?int
|
||||||
|
{
|
||||||
|
return $this->addressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAddressId(?int $addressId): static
|
||||||
|
{
|
||||||
|
$this->addressId = $addressId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPersonId(): ?int
|
||||||
|
{
|
||||||
|
return $this->personId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPersonId(?int $personId): static
|
||||||
|
{
|
||||||
|
$this->personId = $personId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(?string $name): static
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFirstName(): ?string
|
||||||
|
{
|
||||||
|
return $this->firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFirstName(?string $firstName): static
|
||||||
|
{
|
||||||
|
$this->firstName = $firstName;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSalutation(): ?string
|
||||||
|
{
|
||||||
|
return $this->salutation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSalutation(?string $salutation): static
|
||||||
|
{
|
||||||
|
$this->salutation = $salutation;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): ?string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTitle(?string $title): static
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGender(): ?string
|
||||||
|
{
|
||||||
|
return $this->gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGender(?string $gender): static
|
||||||
|
{
|
||||||
|
$this->gender = $gender;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateOfBirth(): \DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->dateOfBirth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateOfBirth(?\DateTimeImmutable $dateOfBirth): static
|
||||||
|
{
|
||||||
|
$this->dateOfBirth = $dateOfBirth;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddress(): ?Address
|
||||||
|
{
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAddress(?Address $address): static
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommunication(): ?Communication
|
||||||
|
{
|
||||||
|
return $this->communication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCommunication(?Communication $communication): static
|
||||||
|
{
|
||||||
|
$this->communication = $communication;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Security;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
|
class LoginController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/login', name: 'app_security_login')]
|
||||||
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
|
{
|
||||||
|
// get the login error if there is one
|
||||||
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
|
||||||
|
// last username entered by the user
|
||||||
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
|
return $this->render('security/login.html.twig', [
|
||||||
|
'last_username' => $lastUsername,
|
||||||
|
'error' => $error,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||||
|
class User implements UserInterface
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $busProAddressId = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $busProPersonId = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $email = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $firstName = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $lastName = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $role = null;
|
||||||
|
|
||||||
|
#[ORM\Column(nullable: true)]
|
||||||
|
private ?\DateTimeImmutable $lastLoginAt = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBusProAddressId(): ?int
|
||||||
|
{
|
||||||
|
return $this->busProAddressId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBusProAddressId(int $busProAddressId): static
|
||||||
|
{
|
||||||
|
$this->busProAddressId = $busProAddressId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBusProPersonId(): ?int
|
||||||
|
{
|
||||||
|
return $this->busProPersonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBusProPersonId(int $busProPersonId): static
|
||||||
|
{
|
||||||
|
$this->busProPersonId = $busProPersonId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmail(): ?string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmail(string $email): static
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFirstName(): ?string
|
||||||
|
{
|
||||||
|
return $this->firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFirstName(string $firstName): static
|
||||||
|
{
|
||||||
|
$this->firstName = $firstName;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastName(): ?string
|
||||||
|
{
|
||||||
|
return $this->lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLastName(string $lastName): static
|
||||||
|
{
|
||||||
|
$this->lastName = $lastName;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRole(): ?string
|
||||||
|
{
|
||||||
|
return $this->role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRole(string $role): static
|
||||||
|
{
|
||||||
|
$this->role = $role;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastLoginAt(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->lastLoginAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLastLoginAt(?\DateTimeImmutable $lastLoginAt): static
|
||||||
|
{
|
||||||
|
$this->lastLoginAt = $lastLoginAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultRoute(): string
|
||||||
|
{
|
||||||
|
return 'app_index';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoles(): array
|
||||||
|
{
|
||||||
|
return ['ROLE_USER'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eraseCredentials(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdentifier(): string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<User>
|
||||||
|
*
|
||||||
|
* @method User|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method User|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method User[] findAll()
|
||||||
|
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class UserRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save(User $entity, bool $flush = false): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->persist($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove(User $entity, bool $flush = false): void
|
||||||
|
{
|
||||||
|
$this->getEntityManager()->remove($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return User[] Returns an array of User objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('u.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?User
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Security;
|
||||||
|
|
||||||
|
use App\BusProNet\ApiClient;
|
||||||
|
use App\BusProNet\ApiClientException;
|
||||||
|
use App\BusProNet\Model\ErrorResponse;
|
||||||
|
use App\BusProNet\Model\Profile;
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||||
|
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
||||||
|
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||||
|
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||||
|
|
||||||
|
class BpnAuthenticator extends AbstractLoginFormAuthenticator implements AuthenticationEntryPointInterface
|
||||||
|
{
|
||||||
|
use TargetPathTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly UrlGeneratorInterface $urlGenerator,
|
||||||
|
private readonly EntityManagerInterface $entityManager,
|
||||||
|
private readonly ApiClient $apiClient,
|
||||||
|
private readonly LoggerInterface $logger
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getLoginUrl(Request $request): string
|
||||||
|
{
|
||||||
|
return $this->urlGenerator->generate('app_security_login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate(Request $request): Passport
|
||||||
|
{
|
||||||
|
$email = trim($request->request->get('_username', ''));
|
||||||
|
$password = trim($request->request->get('_password', ''));
|
||||||
|
$csrfToken = $request->request->get('_csrf_token', '');
|
||||||
|
|
||||||
|
return new SelfValidatingPassport(
|
||||||
|
new UserBadge($email, function () use ($email, $password) {
|
||||||
|
try {
|
||||||
|
$response = $this->apiClient->getProfile($email, $password);
|
||||||
|
} catch (ApiClientException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response instanceof ErrorResponse) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getOrCreateLocalUser($response, $email, $password);
|
||||||
|
}),
|
||||||
|
[new CsrfTokenBadge('authenticate', $csrfToken)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||||
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $token->getUser();
|
||||||
|
|
||||||
|
$user->setLastLoginAt(new \DateTimeImmutable());
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
||||||
|
return new RedirectResponse($targetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = $this->urlGenerator->generate($user->getDefaultRoute());
|
||||||
|
|
||||||
|
return new RedirectResponse($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getOrCreateLocalUser(Profile $profile, string $email, string $password): User
|
||||||
|
{
|
||||||
|
$repository = $this->entityManager->getRepository(User::class);
|
||||||
|
|
||||||
|
$user = $repository->findOneBy([
|
||||||
|
'busProAddressId' => $profile->getAddressId(),
|
||||||
|
'busProPersonId' => $profile->getPersonId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (null !== $user) {
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->apiClient->getCrmSelection($email, $password);
|
||||||
|
} catch (ApiClientException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user
|
||||||
|
->setBusProAddressId($profile->getAddressId())
|
||||||
|
->setBusProPersonId($profile->getPersonId())
|
||||||
|
->setRole('ROLE_FOO')
|
||||||
|
->setEmail($profile->getCommunication()->getEmail())
|
||||||
|
->setFirstName($profile->getFirstName())
|
||||||
|
->setLastName($profile->getName())
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->entityManager->persist($user);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,18 @@
|
|||||||
"tests/bootstrap.php"
|
"tests/bootstrap.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/apache-pack": {
|
||||||
|
"version": "1.0",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes-contrib",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "efb318193e48384eb5c5aadff15396ed698f8ffc"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"public/.htaccess"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/console": {
|
"symfony/console": {
|
||||||
"version": "6.3",
|
"version": "6.3",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% if error %}
|
||||||
|
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ path('app_security_login') }}" method="post">
|
||||||
|
<label for="username">Email:</label>
|
||||||
|
<input type="text" id="username" name="_username" value="{{ last_username }}">
|
||||||
|
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input type="password" id="password" name="_password">
|
||||||
|
|
||||||
|
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||||
|
|
||||||
|
<button type="submit">login</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user