Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
<?php
namespace Mautic\ApiBundle\Form\Type;
use Mautic\ApiBundle\Entity\oAuth2\Client;
use Mautic\ApiBundle\Form\Validator\Constraints\OAuthCallback;
use Mautic\CoreBundle\Form\DataTransformer as Transformers;
use Mautic\CoreBundle\Form\EventListener\CleanFormSubscriber;
use Mautic\CoreBundle\Form\EventListener\FormExitSubscriber;
use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @extends AbstractType<Client>
*/
class ClientType extends AbstractType
{
public function __construct(
private RequestStack $requestStack,
private TranslatorInterface $translator,
private ValidatorInterface $validator,
private RouterInterface $router,
) {
}
/**
* @return bool|mixed
*/
private function getApiMode()
{
return $this->requestStack->getCurrentRequest()->get(
'api_mode',
$this->requestStack->getSession()->get('mautic.client.filter.api_mode', 'oauth2')
);
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$apiMode = $this->getApiMode();
$builder->addEventSubscriber(new CleanFormSubscriber([]));
$builder->addEventSubscriber(new FormExitSubscriber('api.client', $options));
if (!$options['data']->getId()) {
$builder->add(
'api_mode',
ChoiceType::class,
[
'mapped' => false,
'label' => 'mautic.api.client.form.auth_protocol',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'onchange' => 'Mautic.refreshApiClientForm(\''.$this->router->generate('mautic_client_action', ['objectAction' => 'new']).'\', this)',
],
'choices' => [
'OAuth 2' => 'oauth2',
],
'required' => false,
'placeholder' => false,
'data' => $apiMode,
]
);
}
$builder->add(
'name',
TextType::class,
[
'label' => 'mautic.core.name',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
]
);
$arrayStringTransformer = new Transformers\ArrayStringTransformer();
$builder->add(
$builder->create(
'redirectUris',
TextType::class,
[
'label' => 'mautic.api.client.redirecturis',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'tooltip' => 'mautic.api.client.form.help.requesturis',
],
]
)
->addViewTransformer($arrayStringTransformer)
);
$builder->add(
'publicId',
TextType::class,
[
'label' => 'mautic.api.client.form.clientid',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'disabled' => true,
'required' => false,
'mapped' => false,
'data' => $options['data']->getPublicId(),
]
);
$builder->add(
'secret',
TextType::class,
[
'label' => 'mautic.api.client.form.clientsecret',
'label_attr' => ['class' => 'control-label'],
'attr' => ['class' => 'form-control'],
'disabled' => true,
'required' => false,
]
);
$builder->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event): void {
$form = $event->getForm();
$data = $event->getData();
if ($form->has('redirectUris')) {
foreach ($data->getRedirectUris() as $uri) {
$urlConstraint = new OAuthCallback();
$urlConstraint->message = $this->translator->trans(
'mautic.api.client.redirecturl.invalid',
['%url%' => $uri],
'validators'
);
$errors = $this->validator->validate($uri, $urlConstraint);
foreach ($errors as $error) {
$form['redirectUris']->addError(new FormError($error->getMessage()));
}
}
}
}
);
$builder->add('buttons', FormButtonsType::class);
if (!empty($options['action'])) {
$builder->setAction($options['action']);
}
}
public function configureOptions(OptionsResolver $resolver): void
{
$dataClass = Client::class;
$resolver->setDefaults(
[
'data_class' => $dataClass,
]
);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Mautic\ApiBundle\Form\Type;
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* @extends AbstractType<mixed>
*/
class ConfigType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add(
'api_enabled',
YesNoButtonGroupType::class,
[
'label' => 'mautic.api.config.form.api.enabled',
'data' => isset($options['data']['api_enabled']) && (bool) $options['data']['api_enabled'],
'help' => 'mautic.api.config.form.api.enabled.help',
]
);
$builder->add(
'api_enable_basic_auth',
YesNoButtonGroupType::class,
[
'label' => 'mautic.api.config.form.api.basic_auth_enabled',
'data' => isset($options['data']['api_enable_basic_auth']) && (bool) $options['data']['api_enable_basic_auth'],
'attr' => [
'tooltip' => 'mautic.api.config.form.api.basic_auth.tooltip',
],
]
);
$builder->add(
'api_oauth2_access_token_lifetime',
NumberType::class,
[
'label' => 'mautic.api.config.form.api.oauth2_access_token_lifetime',
'attr' => [
'tooltip' => 'mautic.api.config.form.api.oauth2_access_token_lifetime.tooltip',
'class' => 'form-control',
'data-show-on' => '{"config_apiconfig_api_enabled_1":"checked"}',
],
'constraints' => [
new NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
],
]
);
$builder->add(
'api_oauth2_refresh_token_lifetime',
NumberType::class,
[
'label' => 'mautic.api.config.form.api.oauth2_refresh_token_lifetime',
'attr' => [
'tooltip' => 'mautic.api.config.form.api.oauth2_refresh_token_lifetime.tooltip',
'class' => 'form-control',
'data-show-on' => '{"config_apiconfig_api_enabled_1":"checked"}',
],
'constraints' => [
new NotBlank(
[
'message' => 'mautic.core.value.required',
]
),
],
]
);
}
public function getBlockPrefix(): string
{
return 'apiconfig';
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Mautic\ApiBundle\Form\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
class OAuthCallback extends Constraint
{
public $message = 'The callback URL is invalid.';
public function validatedBy(): string
{
return OAuthCallbackValidator::class;
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Mautic\ApiBundle\Form\Validator\Constraints;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class OAuthCallbackValidator extends ConstraintValidator
{
public const PATTERN = '~^[0-9a-z].*://(.*?)(:[0-9]+)?(/?|/\S+)$~ixu';
/**
* @param mixed $value
*/
public function validate($value, Constraint $constraint): void
{
if (!$constraint instanceof OAuthCallback) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\OAuthCallback');
}
if (null === $value || '' === $value) {
return;
}
if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
throw new UnexpectedTypeException($value, 'string');
}
$value = (string) $value;
if (!preg_match(static::PATTERN, $value)) {
$this->context->buildViolation($constraint->message)
->setParameter('{{ value }}', $this->formatValue($value))
->addViolation();
}
}
}