Issues (3627)

EventListener/FormSubscriber.php (2 issues)

1
<?php
2
3
/*
4
 * @copyright   2016 Mautic Contributors. All rights reserved
5
 * @author      Mautic
6
 *
7
 * @link        http://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace MauticPlugin\MauticCitrixBundle\EventListener;
13
14
use Doctrine\Common\Collections\Collection;
15
use Doctrine\ORM\EntityManager;
16
use Mautic\CoreBundle\Helper\TemplatingHelper;
17
use Mautic\FormBundle\Entity\Action;
18
use Mautic\FormBundle\Entity\Field;
19
use Mautic\FormBundle\Entity\Form;
20
use Mautic\FormBundle\Entity\SubmissionRepository;
21
use Mautic\FormBundle\Event as Events;
22
use Mautic\FormBundle\Event\SubmissionEvent;
23
use Mautic\FormBundle\Exception\ValidationException;
24
use Mautic\FormBundle\FormEvents;
25
use Mautic\FormBundle\Model\FormModel;
26
use Mautic\FormBundle\Model\SubmissionModel;
27
use Mautic\LeadBundle\Entity\Lead;
28
use Mautic\PluginBundle\Event\PluginIntegrationRequestEvent;
29
use Mautic\PluginBundle\PluginEvents;
30
use MauticPlugin\MauticCitrixBundle\CitrixEvents;
31
use MauticPlugin\MauticCitrixBundle\Form\Type\CitrixActionType;
32
use MauticPlugin\MauticCitrixBundle\Form\Type\CitrixListType;
33
use MauticPlugin\MauticCitrixBundle\Helper\CitrixHelper;
34
use MauticPlugin\MauticCitrixBundle\Helper\CitrixProducts;
35
use MauticPlugin\MauticCitrixBundle\Model\CitrixModel;
36
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
37
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
38
use Symfony\Component\Process\Exception\InvalidArgumentException;
39
use Symfony\Component\Translation\TranslatorInterface;
40
41
class FormSubscriber implements EventSubscriberInterface
42
{
43
    use CitrixRegistrationTrait;
44
    use CitrixStartTrait;
45
46
    /**
47
     * @var FormModel
48
     */
49
    private $formModel;
50
51
    /**
52
     * @var SubmissionModel
53
     */
54
    private $submissionModel;
55
56
    /**
57
     * @var CitrixModel
58
     */
59
    private $citrixModel;
60
61
    /**
62
     * @var TranslatorInterface
63
     */
64
    private $translator;
65
66
    /**
67
     * @var EntityManager
68
     */
69
    private $entityManager;
70
71
    /**
72
     * ヽ(ಠ_ಠ)ノ Used in the CitrixStartTrait.
73
     *
74
     * @var TemplatingHelper
75
     */
76
    private $templating;
77
78
    public function __construct(
79
        CitrixModel $citrixModel,
80
        FormModel $formModel,
81
        SubmissionModel $submissionModel,
82
        TranslatorInterface $translator,
83
        EntityManager $entityManager,
84
        TemplatingHelper $templating
85
    ) {
86
        $this->citrixModel     = $citrixModel;
87
        $this->formModel       = $formModel;
88
        $this->submissionModel = $submissionModel;
89
        $this->translator      = $translator;
90
        $this->entityManager   = $entityManager;
91
        $this->templating      = $templating;
92
    }
93
94
    public static function getSubscribedEvents()
95
    {
96
        return [
97
            FormEvents::FORM_ON_BUILD                    => ['onFormBuilder', 0],
98
            CitrixEvents::ON_WEBINAR_REGISTER_ACTION     => ['onWebinarRegister', 0],
99
            CitrixEvents::ON_MEETING_START_ACTION        => ['onMeetingStart', 0],
100
            CitrixEvents::ON_TRAINING_REGISTER_ACTION    => ['onTrainingRegister', 0],
101
            CitrixEvents::ON_TRAINING_START_ACTION       => ['onTrainingStart', 0],
102
            CitrixEvents::ON_ASSIST_REMOTE_ACTION        => ['onAssistRemote', 0],
103
            CitrixEvents::ON_FORM_VALIDATE_ACTION        => ['onFormValidate', 0],
104
            FormEvents::FORM_PRE_SAVE                    => ['onFormPreSave', 0],
105
            PluginEvents::PLUGIN_ON_INTEGRATION_REQUEST  => ['onRequest', 0],
106
        ];
107
    }
108
109
    /**
110
     * @param string $product
111
     * @param string $startType indicates that this is a start product, not registration
112
     *
113
     * @throws ValidationException
114
     */
115
    private function _doRegistration(SubmissionEvent $event, $product, $startType = null)
116
    {
117
        $submission = $event->getSubmission();
118
        $form       = $submission->getForm();
119
        $post       = $event->getPost();
120
        $fields     = $form->getFields();
121
        $actions    = $form->getActions();
122
123
        try {
124
            // gotoassist screen sharing does not need a product
125
            if ('assist' !== $product) {
126
                // check if there are products in the actions
127
                /** @var Action $action */
128
                foreach ($actions as $action) {
129
                    if (0 === strpos($action->getType(), 'plugin.citrix.action')) {
130
                        $actionAction = preg_filter('/^.+\.([^\.]+\.[^\.]+)$/', '$1', $action->getType());
131
                        $actionAction = str_replace('.', '_', $actionAction);
132
                        if (!array_key_exists($actionAction, $submission->getResults())) {
133
                            // add new hidden field to store the product id
134
                            $field = new Field();
135
                            $field->setType('hidden');
136
                            $field->setLabel(ucfirst($product).' ID');
137
                            $field->setAlias($actionAction);
138
                            $field->setForm($form);
139
                            $field->setOrder(99999);
140
                            $field->setSaveResult(true);
141
                            $form->addField($actionAction, $field);
142
                            $this->entityManager->persist($form);
143
                            /* @var FormModel $formModel */
144
                            $this->formModel->createTableSchema($form);
145
                        }
146
                    }
147
                }
148
            }
149
150
            $productsToRegister = self::_getProductsFromPost($actions, $fields, $post, $product);
151
            if ('assist' === $product || (0 !== count($productsToRegister))) {
152
                $results = $submission->getResults();
153
154
                // persist the new values
155
                if ('assist' !== $product) {
156
                    // replace the submitted value with something more legible
157
                    foreach ($productsToRegister as $productToRegister) {
158
                        $results[$productToRegister['fieldName']] = $productToRegister['productTitle'].' ('.$productToRegister['productId'].')';
159
                    }
160
161
                    /** @var SubmissionRepository $repo */
162
                    $repo             = $this->submissionModel->getRepository();
163
                    $resultsTableName = $repo->getResultsTableName($form->getId(), $form->getAlias());
164
                    $tableKeys        = ['submission_id' => $submission->getId()];
165
                    $this->entityManager
166
                        ->getConnection()
167
                        ->update($resultsTableName, $results, $tableKeys);
168
                } else {
169
                    // dummy field for assist
170
                    $productsToRegister[] = // needed because there are no ids
171
                        [
172
                            'fieldName'    => $startType,
173
                            'productId'    => $startType,
174
                            'productTitle' => $startType,
175
                        ];
176
                }
177
178
                /** @var Lead $currentLead */
179
                $currentLead = $event->getLead();
180
181
                // execute action
182
                if ($currentLead instanceof Lead) {
183
                    if (null !== $startType) {
184
                        /** @var Action $action */
185
                        foreach ($actions as $action) {
186
                            $actionAction = preg_filter('/^.+\.([^\.]+\.[^\.]+)$/', '$1', $action->getType());
187
                            if ($actionAction === $startType) {
188
                                if (array_key_exists('template', $action->getProperties())) {
189
                                    $emailId = $action->getProperties()['template'];
190
                                    $this->startProduct(
191
                                        $product,
192
                                        $currentLead,
193
                                        $productsToRegister,
194
                                        $emailId,
195
                                        $action->getId()
196
                                    );
197
                                } else {
198
                                    throw new BadRequestHttpException('Email template not found!');
199
                                }
200
                            }
201
                        }
202
                    } else {
203
                        $this->registerProduct($product, $currentLead, $productsToRegister);
204
                    }
205
                } else {
206
                    throw new BadRequestHttpException('Lead not found!');
207
                }
208
            } else {
209
                throw new BadRequestHttpException('There are no products to '.((null === $startType) ? 'register' : 'start'));
210
            } // end-block
211
        } catch (\Exception $ex) {
212
            CitrixHelper::log('onProductRegistration - '.$product.': '.$ex->getMessage());
213
            $validationException = new ValidationException($ex->getMessage());
214
            $validationException->setViolations(
215
                [
216
                    'email' => $ex->getMessage(),
217
                ]
218
            );
219
            throw $validationException;
220
        }
221
    }
222
223
    public function onWebinarRegister(SubmissionEvent $event)
224
    {
225
        $this->_doRegistration($event, CitrixProducts::GOTOWEBINAR);
226
    }
227
228
    public function onMeetingStart(SubmissionEvent $event)
229
    {
230
        $this->_doRegistration($event, CitrixProducts::GOTOMEETING, 'start.meeting');
231
    }
232
233
    public function onTrainingRegister(SubmissionEvent $event)
234
    {
235
        $this->_doRegistration($event, CitrixProducts::GOTOTRAINING);
236
    }
237
238
    public function onTrainingStart(SubmissionEvent $event)
239
    {
240
        $this->_doRegistration($event, CitrixProducts::GOTOTRAINING, 'start.training');
241
    }
242
243
    public function onAssistRemote(SubmissionEvent $event)
244
    {
245
        $this->_doRegistration($event, CitrixProducts::GOTOASSIST, 'screensharing.assist');
246
    }
247
248
    /**
249
     * Helper function to debug REST requests.
250
     */
251
    public function onRequest(PluginIntegrationRequestEvent $event)
252
    {
253
        // clean parameter that was breaking the call
254
        if (preg_match('/\/G2W\/rest\//', $event->getUrl())) {
255
            $params = $event->getParameters();
256
            unset($params['access_token']);
257
            $event->setParameters($params);
258
        }
259
    }
260
261
    /**
262
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
263
     * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException
264
     */
265
    public function onFormValidate(Events\ValidationEvent $event)
266
    {
267
        $field        = $event->getField();
268
        $eventType    = preg_filter('/^plugin\.citrix\.select\.(.*)$/', '$1', $field->getType());
269
        $doValidation = CitrixHelper::isAuthorized('Goto'.$eventType);
270
271
        if ($doValidation) {
272
            $list = CitrixHelper::getCitrixChoices($eventType);
273
            /** @var array $values */
274
            $values = $event->getValue();
275
276
            if (!is_array($values) && !is_object($values)) {
0 ignored issues
show
The condition is_array($values) is always true.
Loading history...
277
                $values = [$values];
278
            }
279
280
            if (is_array($values) || is_object($values)) {
0 ignored issues
show
The condition is_array($values) is always true.
Loading history...
281
                foreach ($values as $value) {
282
                    if (!array_key_exists($value, $list)) {
283
                        $event->failedValidation(
284
                            $value.': '.$this->translator->trans('plugin.citrix.'.$eventType.'.nolongeravailable')
285
                        );
286
                    }
287
                }
288
            }
289
        }
290
    }
291
292
    /**
293
     * @param Collection $actions
294
     * @param Collection $fields
295
     * @param array      $post
296
     * @param string     $product
297
     *
298
     * @return array
299
     */
300
    private static function _getProductsFromPost($actions, $fields, $post, $product)
301
    {
302
        /** @var array $productlist */
303
        $productlist = [];
304
305
        $products = [];
306
        /** @var \Mautic\FormBundle\Entity\Field $field */
307
        foreach ($fields as $field) {
308
            if ('plugin.citrix.select.'.$product === $field->getType()) {
309
                if (0 === count($productlist)) {
310
                    $productlist = CitrixHelper::getCitrixChoices($product);
311
                }
312
                $alias = $field->getAlias();
313
                /** @var array $productIds */
314
                $productIds = $post[$alias];
315
                if (!is_array($productIds) && !is_object($productIds)) {
316
                    $productIds = [$productIds];
317
                }
318
                if (is_array($productIds) || is_object($productIds)) {
319
                    foreach ($productIds as $productId) {
320
                        $products[] = [
321
                            'fieldName'    => $alias,
322
                            'productId'    => $productId,
323
                            'productTitle' => array_key_exists(
324
                                $productId,
325
                                $productlist
326
                            ) ? $productlist[$productId] : 'untitled',
327
                        ];
328
                    }
329
                }
330
            }
331
        }
332
333
        // gotoassist screen sharing does not need a product
334
        if ('assist' !== $product) {
335
            // check if there are products in the actions
336
            /** @var Action $action */
337
            foreach ($actions as $action) {
338
                if (0 === strpos($action->getType(), 'plugin.citrix.action')) {
339
                    if (0 === count($productlist)) {
340
                        $productlist = CitrixHelper::getCitrixChoices($product);
341
                    }
342
                    $actionProduct = preg_filter('/^.+\.([^\.]+)$/', '$1', $action->getType());
343
                    if (!CitrixHelper::isAuthorized('Goto'.$actionProduct)) {
344
                        continue;
345
                    }
346
                    $actionAction = preg_filter('/^.+\.([^\.]+\.[^\.]+)$/', '$1', $action->getType());
347
                    $productId    = $action->getProperties()['product'];
348
                    if (array_key_exists(
349
                        $productId,
350
                        $productlist
351
                    )) {
352
                        $products[] = [
353
                            'fieldName'    => str_replace('.', '_', $actionAction),
354
                            'productId'    => $productId,
355
                            'productTitle' => $productlist[$productId],
356
                        ];
357
                    }
358
                }
359
            }
360
        }
361
362
        return $products;
363
    }
364
365
    /**
366
     * @throws ValidationException
367
     */
368
    public function onFormPreSave(Events\FormEvent $event)
369
    {
370
        $form   = $event->getForm();
371
        $fields = $form->getFields()->getValues();
372
373
        // Verify if the form is well configured
374
        if (0 !== count($fields)) {
375
            $violations = $this->_checkFormValidity($form);
376
            if (0 !== count($violations)) {
377
                $event->stopPropagation();
378
                $error     = implode('<br/>', $violations);
379
                $exception = (new ValidationException($error))
380
                    ->setViolations($violations);
381
                throw $exception;
382
            }
383
        }
384
    }
385
386
    /**
387
     * @return array
388
     *
389
     * @throws \InvalidArgumentException
390
     */
391
    private function _checkFormValidity(Form $form)
392
    {
393
        $errors  = [];
394
        $actions = $form->getActions();
395
        $fields  = $form->getFields();
396
397
        if (null !== $actions && null !== $fields) {
398
            $actionFields = [
399
                'register.webinar'     => ['email', 'firstname', 'lastname'],
400
                'register.training'    => ['email', 'firstname', 'lastname'],
401
                'start.meeting'        => ['email'],
402
                'start.training'       => ['email'],
403
                'screensharing.assist' => ['email', 'firstname', 'lastname'],
404
            ];
405
406
            $errorMessages = [
407
                'lead_field_not_found' => $this->translator->trans(
408
                    'plugin.citrix.formaction.validator.leadfieldnotfound'
409
                ),
410
                'field_not_found'          => $this->translator->trans('plugin.citrix.formaction.validator.fieldnotfound'),
411
                'field_should_be_required' => $this->translator->trans(
412
                    'plugin.citrix.formaction.validator.fieldshouldberequired'
413
                ),
414
            ];
415
416
            /** @var Action $action */
417
            foreach ($actions as $action) {
418
                if (0 === strpos($action->getType(), 'plugin.citrix.action')) {
419
                    $actionProduct = preg_filter('/^.+\.([^\.]+)$/', '$1', $action->getType());
420
                    if (!CitrixHelper::isAuthorized('Goto'.$actionProduct)) {
421
                        continue;
422
                    }
423
                    $actionAction = preg_filter('/^.+\.([^\.]+\.[^\.]+)$/', '$1', $action->getType());
424
425
                    // get lead fields
426
                    $currentLeadFields = [];
427
                    foreach ($fields as $field) {
428
                        $leadField = $field->getLeadField();
429
                        if ('' !== $leadField) {
430
                            $currentLeadFields[$leadField] = $field->getIsRequired();
431
                        }
432
                    }
433
434
                    $props = $action->getProperties();
435
                    if (array_key_exists('product', $props) && 'form' === $props['product']) {
436
                        // the product will be selected from a list in the form
437
                        // search for the select field and perform validation for a corresponding action
438
439
                        $hasCitrixListField = false;
440
                        /** @var Field $field */
441
                        foreach ($fields as $field) {
442
                            $fieldProduct = preg_filter('/^.+\.([^\.]+)$/', '$1', $field->getType());
443
                            if ($fieldProduct === $actionProduct) {
444
                                $hasCitrixListField = true;
445
                                if (!$field->getIsRequired()) {
446
                                    $errors[$fieldProduct.'required'] = sprintf(
447
                                        $errorMessages['field_should_be_required'],
448
                                        $this->translator->trans('plugin.citrix.'.$fieldProduct.'.listfield')
449
                                    );
450
                                }
451
                            }
452
                        } // foreach $fields
453
454
                        if (!$hasCitrixListField) {
455
                            $errors[$actionProduct.'listfield'] = sprintf(
456
                                $errorMessages['field_not_found'],
457
                                $this->translator->trans('plugin.citrix.'.$actionProduct.'.listfield')
458
                            );
459
                        }
460
                    }
461
462
                    // check that the corresponding fields for the values in the form exist
463
                    /** @var array $mandatoryActionFields */
464
                    $mandatoryActionFields = $actionFields[$actionAction];
465
                    foreach ($mandatoryActionFields as $actionField) {
466
                        /** @var Field $field */
467
                        $field = $fields->get($props[$actionField]);
468
                        if (null === $field) {
469
                            $errors[$actionField.'notfound'] = sprintf($errorMessages['lead_field_not_found'], $actionField);
470
                            break;
471
                        } else {
472
                            if (!$field->getIsRequired()) {
473
                                $errors[$actionField.'required'] = sprintf($errorMessages['field_should_be_required'], $actionField);
474
                                break;
475
                            }
476
                        }
477
                    }
478
479
                    // check for lead fields
480
                    /** @var array $mandatoryFields */
481
                    $mandatoryFields = $actionFields[$actionAction];
482
                    foreach ($mandatoryFields as $mandatoryField) {
483
                        if (!array_key_exists($mandatoryField, $currentLeadFields)) {
484
                            $errors[$mandatoryField.'notfound'] = sprintf($errorMessages['lead_field_not_found'], $mandatoryField);
485
                        } else {
486
                            if (!$currentLeadFields[$mandatoryField]) {
487
                                $errors[$mandatoryField.'required'] = sprintf(
488
                                    $errorMessages['field_should_be_required'],
489
                                    $mandatoryField
490
                                );
491
                            }
492
                        }
493
                    }
494
                } // end-if there is a Citrix action
495
            } // foreach $actions
496
        }
497
498
        return $errors;
499
    }
500
501
    /**
502
     * @throws InvalidArgumentException
503
     */
504
    public function onFormBuilder(Events\FormBuilderEvent $event)
505
    {
506
        $activeProducts = array_filter(CitrixProducts::toArray(), function ($product) {
507
            return CitrixHelper::isAuthorized('Goto'.$product);
508
        });
509
510
        if (0 === count($activeProducts)) {
511
            return;
512
        }
513
514
        foreach ($activeProducts as $product) {
515
            $event->addFormField('plugin.citrix.select.'.$product, [
516
                'label'    => 'plugin.citrix.'.$product.'.listfield',
517
                'formType' => CitrixListType::class,
518
                'template' => 'MauticCitrixBundle:Field:citrixlist.html.php',
519
                'listType' => $product,
520
            ]);
521
522
            $event->addValidator('plugin.citrix.validate.'.$product, [
523
                'eventName' => CitrixEvents::ON_FORM_VALIDATE_ACTION,
524
                'fieldType' => 'plugin.citrix.select.'.$product,
525
            ]);
526
527
            switch ($product) {
528
                case CitrixProducts::GOTOWEBINAR:
529
                    $event->addSubmitAction('plugin.citrix.action.register.webinar', [
530
                        'group'           => 'plugin.citrix.form.header',
531
                        'description'     => 'plugin.citrix.form.header.webinar',
532
                        'label'           => 'plugin.citrix.action.register.webinar',
533
                        'formType'        => CitrixActionType::class,
534
                        'formTypeOptions' => [
535
                            'attr' => [
536
                                'data-product'        => $product,
537
                                'data-product-action' => 'register',
538
                            ],
539
                        ],
540
                        'template'  => 'MauticFormBundle:Action:generic.html.php',
541
                        'eventName' => CitrixEvents::ON_WEBINAR_REGISTER_ACTION,
542
                    ]);
543
                    break;
544
                case CitrixProducts::GOTOMEETING:
545
                    $event->addSubmitAction('plugin.citrix.action.start.meeting', [
546
                        'group'           => 'plugin.citrix.form.header',
547
                        'description'     => 'plugin.citrix.form.header.meeting',
548
                        'label'           => 'plugin.citrix.action.start.meeting',
549
                        'formType'        => CitrixActionType::class,
550
                        'template'        => 'MauticFormBundle:Action:generic.html.php',
551
                        'eventName'       => CitrixEvents::ON_MEETING_START_ACTION,
552
                        'formTypeOptions' => [
553
                            'attr' => [
554
                                'data-product'        => $product,
555
                                'data-product-action' => 'start',
556
                            ],
557
                        ],
558
                    ]);
559
                    break;
560
                case CitrixProducts::GOTOTRAINING:
561
                    $event->addSubmitAction('plugin.citrix.action.register.training', [
562
                        'group'           => 'plugin.citrix.form.header',
563
                        'description'     => 'plugin.citrix.form.header.training',
564
                        'label'           => 'plugin.citrix.action.register.training',
565
                        'formType'        => CitrixActionType::class,
566
                        'template'        => 'MauticFormBundle:Action:generic.html.php',
567
                        'eventName'       => CitrixEvents::ON_TRAINING_REGISTER_ACTION,
568
                        'formTypeOptions' => [
569
                            'attr' => [
570
                                'data-product'        => $product,
571
                                'data-product-action' => 'register',
572
                            ],
573
                        ],
574
                    ]);
575
576
                    $event->addSubmitAction('plugin.citrix.action.start.training', [
577
                        'group'           => 'plugin.citrix.form.header',
578
                        'description'     => 'plugin.citrix.form.header.start.training',
579
                        'label'           => 'plugin.citrix.action.start.training',
580
                        'formType'        => CitrixActionType::class,
581
                        'template'        => 'MauticFormBundle:Action:generic.html.php',
582
                        'eventName'       => CitrixEvents::ON_TRAINING_START_ACTION,
583
                        'formTypeOptions' => [
584
                            'attr' => [
585
                                'data-product'        => $product,
586
                                'data-product-action' => 'start',
587
                            ],
588
                        ],
589
                    ]);
590
                    break;
591
                case CitrixProducts::GOTOASSIST:
592
                    $event->addSubmitAction('plugin.citrix.action.screensharing.assist', [
593
                        'group'           => 'plugin.citrix.form.header',
594
                        'description'     => 'plugin.citrix.form.header.assist',
595
                        'label'           => 'plugin.citrix.action.screensharing.assist',
596
                        'formType'        => CitrixActionType::class,
597
                        'template'        => 'MauticFormBundle:Action:generic.html.php',
598
                        'eventName'       => CitrixEvents::ON_ASSIST_REMOTE_ACTION,
599
                        'formTypeOptions' => [
600
                            'attr' => [
601
                                'data-product'        => $product,
602
                                'data-product-action' => 'screensharing',
603
                            ],
604
                        ],
605
                    ]);
606
                    break;
607
                default:
608
                    break;
609
            }
610
        }
611
    }
612
}
613