Skip to content

Commit

Permalink
Merge pull request #8440 from mautic/release-2.16
Browse files Browse the repository at this point in the history
Release 2.16.0
  • Loading branch information
dennisameling committed Feb 13, 2020
2 parents 64b4115 + 1b3c35d commit 77b1165
Show file tree
Hide file tree
Showing 146 changed files with 5,991 additions and 1,743 deletions.
25 changes: 13 additions & 12 deletions .github/ISSUE_TEMPLATE.md
@@ -1,22 +1,24 @@
**Please DO NOT report security vulnerabilities here. Send them to security@mautic.com instead.**
[//]: # (READ THIS BEFORE PUBLISHING YOUR ISSUE)

What type of report is this:
[//]: # (Please post questions, support requests and feature requests/ideas at https://forum.mautic.org.)
[//]: # (Strictly follow the instructions hereunder, otherwise your issue will be closed for lack of information.)
[//]: # (DO NOT report security vulnerabilities here. Send them to security@mautic.com.)

Detail your bug report:

| Q | A
| ---| ---
| Bug report? |
| Feature request? |
| Enhancement? |
| Confirm it is a Bug report |
| Mautic version |
| PHP version |

[//]: # (Feature request? ---> Go to forum please ---> https://forum.mautic.org/c/ideas)
[//]: # (Enhancement? ---> Go to forum please ---> https://forum.mautic.org/c/ideas)
[//]: # (Need support, have questions? ---> Go to forum please ---> https://forum.mautic.org/c/support)

## Description:
The more details the better...

## If a bug:

| Q | A
| --- | ---
| Mautic version |
| PHP version |

### Steps to reproduce:
1.
Expand All @@ -25,4 +27,3 @@ The more details the better...
### Log errors:

_Please check for related errors in the latest log file in [mautic root]/app/log/ and/or the web server's logs and post them here. Be sure to remove sensitive information if applicable._

44 changes: 27 additions & 17 deletions .htaccess
Expand Up @@ -97,21 +97,31 @@
</IfModule>
</IfModule>

# Denie access via HTTP requests to all PHP files.
<Files "*.php">
Require all denied
</Files>
# Apache 2.4+
<IfModule authz_core_module>
# Deny access via HTTP requests to all PHP files.
<FilesMatch "\.php$">
Require all denied
</FilesMatch>

# Except those whitelisted bellow.
<FilesMatch "^(index|index_dev|filemanager|upgrade)\.php$">
Require all granted
</FilesMatch>
</IfModule>

# Fallback for Apache < 2.4
<IfModule !authz_core_module>
# Deny access via HTTP requests to all PHP files.
<FilesMatch "\.php$">
Order deny,allow
Deny from all
</FilesMatch>

# Except those whitelisted bellow.
<FilesMatch "^(index|index_dev|filemanager|upgrade)\.php$">
Order allow,deny
Allow from all
</FilesMatch>
</IfModule>

# Except those whitelisted bellow.
<Files "index.php">
Require all granted
</Files>
<Files "index_dev.php">
Require all granted
</Files>
<Files "filemanager.php">
Require all granted
</Files>
<Files "upgrade.php">
Require all granted
</Files>
1 change: 1 addition & 0 deletions .php_cs
Expand Up @@ -18,5 +18,6 @@ return PhpCsFixer\Config::create()
'array_syntax' => [
'syntax' => 'short'
],
'no_unused_imports' => false,
])
->setFinder($finder);
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -9,6 +9,7 @@ php:
- 7.0
- 7.1
- 7.2
- 7.3

cache:
directories:
Expand Down
11 changes: 11 additions & 0 deletions README.md
Expand Up @@ -2,6 +2,17 @@ Mautic Introduction
===========
![Mautic](https://www.mautic.org/media/images/github_readme.png "Mautic Open Source Marketing Automation")

## Supported Versions
Please note that the release dates indicated with * below are *estimations*, no rights can be derived from them.

| Branch | Beta Release | Initial Release | Active Support Until | Security Support Until
|--|--|--|--|--|
|2.15 | 27 Sep 2019 | 8 Oct 2019 | 8 Oct 2019 | 8 Oct 2019
|2.16 | 30 Jan 2020* | 13 Feb 2020* | 13 Feb 2020 | June 2020? (TBD)**
|3.0 | 27 Jan 2020* | 3 Feb 2020* | TBD | TBD

** = Security Support for 2.16 will only be provided for Mautic itself, not for core dependencies that are EOL like Symfony 2.8.

## Getting Started

The GitHub version is recommended for development or testing. Production package ready for install with all the libraries is at [https://www.mautic.org/download](https://www.mautic.org/download).
Expand Down
4 changes: 2 additions & 2 deletions app/AppKernel.php
Expand Up @@ -34,14 +34,14 @@ class AppKernel extends Kernel
*
* @const integer
*/
const MINOR_VERSION = 15;
const MINOR_VERSION = 16;

/**
* Patch version number.
*
* @const integer
*/
const PATCH_VERSION = 3;
const PATCH_VERSION = 0;

/**
* Extra version identifier.
Expand Down
18 changes: 18 additions & 0 deletions app/bundles/ApiBundle/ApiEvents.php
Expand Up @@ -51,4 +51,22 @@ final class ApiEvents
* @var string
*/
const BUILD_ROUTE = 'mautic.build_api_route';

/**
* The mautic.api_on_entity_pre_save event is thrown after an entity about to be saved via API.
*
* The event listener receives a Mautic\ApiBundle\Event\ApiEntityEvent instance.
*
* @var string
*/
const API_ON_ENTITY_PRE_SAVE = 'mautic.api_on_entity_pre_save';

/**
* The mautic.api_on_entity_post_save event is thrown after an entity is saved via API.
*
* The event listener receives a Mautic\ApiBundle\Event\ApiEntityEvent instance.
*
* @var string
*/
const API_ON_ENTITY_POST_SAVE = 'mautic.api_on_entity_post_save';
}
18 changes: 18 additions & 0 deletions app/bundles/ApiBundle/Controller/CommonApiController.php
Expand Up @@ -17,6 +17,8 @@
use FOS\RestBundle\Util\Codes;
use JMS\Serializer\Exclusion\ExclusionStrategyInterface;
use JMS\Serializer\SerializationContext;
use Mautic\ApiBundle\ApiEvents;
use Mautic\ApiBundle\Event\ApiEntityEvent;
use Mautic\ApiBundle\Serializer\Exclusion\ParentChildrenExclusionStrategy;
use Mautic\ApiBundle\Serializer\Exclusion\PublishDetailsExclusionStrategy;
use Mautic\CategoryBundle\Entity\Category;
Expand Down Expand Up @@ -1175,6 +1177,14 @@ protected function processForm($entity, $parameters = null, $method = 'PUT')
return $preSaveError;
}

try {
if ($this->dispatcher->hasListeners(ApiEvents::API_ON_ENTITY_PRE_SAVE)) {
$this->dispatcher->dispatch(ApiEvents::API_ON_ENTITY_PRE_SAVE, new ApiEntityEvent($entity, $this->entityRequestParameters, $this->request));
}
} catch (\Exception $e) {
return $this->returnError($e->getMessage(), $e->getCode());
}

$this->model->saveEntity($entity);
$headers = [];
//return the newly created entities location if applicable
Expand All @@ -1188,6 +1198,14 @@ protected function processForm($entity, $parameters = null, $method = 'PUT')
);
}

try {
if ($this->dispatcher->hasListeners(ApiEvents::API_ON_ENTITY_POST_SAVE)) {
$this->dispatcher->dispatch(ApiEvents::API_ON_ENTITY_POST_SAVE, new ApiEntityEvent($entity, $this->entityRequestParameters, $this->request));
}
} catch (\Exception $e) {
return $this->returnError($e->getMessage(), $e->getCode());
}

$this->preSerializeEntity($entity, $action);

if ($this->inBatchMode) {
Expand Down
69 changes: 69 additions & 0 deletions app/bundles/ApiBundle/Event/ApiEntityEvent.php
@@ -0,0 +1,69 @@
<?php

/*
* @copyright 2019 Mautic Contributors. All rights reserved
* @author Mautic
*
* @link https://mautic.org
*
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
*/

namespace Mautic\ApiBundle\Event;

use Mautic\CoreBundle\Event\CommonEvent;
use Symfony\Component\HttpFoundation\Request;

class ApiEntityEvent extends CommonEvent
{
/**
* @var object
*/
protected $entity;

/**
* @var array
*/
protected $entityRequestParameters;

/**
* @var Request
*/
private $request;

/**
* @param object $entity
* @param array $entityRequestParameters
* @param Request $request
*/
public function __construct($entity, array $entityRequestParameters, Request $request)
{
$this->entity = $entity;
$this->entityRequestParameters = $entityRequestParameters;
$this->request = $request;
}

/**
* @return object
*/
public function getEntity()
{
return $this->entity;
}

/**
* @return array
*/
public function getEntityRequestParameters()
{
return $this->entityRequestParameters;
}

/**
* @return Request
*/
public function getRequest()
{
return $this->request;
}
}
24 changes: 23 additions & 1 deletion app/bundles/CampaignBundle/Entity/CampaignRepository.php
Expand Up @@ -106,7 +106,7 @@ public function getPublishedCampaigns($specificId = null, $leadId = null, $forLi
->where($this->getPublishedByDateExpression($q));

if (!$viewOther) {
$q->andWhere($q->expr()->eq('c.created_by', ':id'))
$q->andWhere($q->expr()->eq('c.createdBy', ':id'))
->setParameter('id', $this->currentUser->getId());
}

Expand Down Expand Up @@ -738,6 +738,28 @@ public function getCampaignLeadsFromLists($id, array $lists, $args = [])
return $leads;
}

/**
* @param int $segmentId
* @param array $campaignIds
*
* @return array
*/
public function getCampaignsSegmentShare($segmentId, $campaignIds = [])
{
$q = $this->getEntityManager()->getConnection()->createQueryBuilder();
$q->select('c.id, c.name, ROUND(IFNULL(COUNT(DISTINCT t.lead_id)/COUNT(DISTINCT cl.lead_id)*100, 0),1) segmentCampaignShare');
$q->from(MAUTIC_TABLE_PREFIX.'campaigns', 'c')
->leftJoin('c', MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl', 'cl.campaign_id = c.id AND cl.manually_removed = 0')
->leftJoin('cl', '(SELECT lll.lead_id AS ll, lll.lead_id FROM lead_lists_leads lll WHERE lll.leadlist_id = '.$segmentId.' AND lll.manually_removed = 0)', 't', 't.lead_id = cl.lead_id');
$q->groupBy('c.id');

if (!empty($campaignIds)) {
$q->where($q->expr()->in('c.id', $campaignIds));
}

return $q->execute()->fetchAll();
}

/**
* Get leads that do not belong based on lead lists.
*
Expand Down
20 changes: 13 additions & 7 deletions app/bundles/CampaignBundle/Entity/LeadRepository.php
Expand Up @@ -415,7 +415,7 @@ public function getCountsForCampaignContactsBySegment($campaignId, ContactLimite
);

$this->updateQueryFromContactLimiter('ll', $qb, $limiter, true);
$this->updateQueryWithExistingMembershipExclusion($campaignId, $qb);
$this->updateQueryWithExistingMembershipExclusion($campaignId, $qb, $campaignCanBeRestarted);

if (!$campaignCanBeRestarted) {
$this->updateQueryWithHistoryExclusion($campaignId, $qb);
Expand Down Expand Up @@ -450,7 +450,7 @@ public function getCampaignContactsBySegments($campaignId, ContactLimiter $limit
);

$this->updateQueryFromContactLimiter('ll', $qb, $limiter);
$this->updateQueryWithExistingMembershipExclusion($campaignId, $qb);
$this->updateQueryWithExistingMembershipExclusion($campaignId, $qb, $campaignCanBeRestarted);

if (!$campaignCanBeRestarted) {
$this->updateQueryWithHistoryExclusion($campaignId, $qb);
Expand Down Expand Up @@ -588,16 +588,22 @@ private function getCampaignSegments($campaignId)
* @param $campaignId
* @param QueryBuilder $qb
*/
private function updateQueryWithExistingMembershipExclusion($campaignId, QueryBuilder $qb)
private function updateQueryWithExistingMembershipExclusion($campaignId, QueryBuilder $qb, $campaignCanBeRestarted = false)
{
$membershipConditions = [
$qb->expr()->eq('cl.lead_id', 'll.lead_id'),
$qb->expr()->eq('cl.campaign_id', (int) $campaignId),
];

if ($campaignCanBeRestarted) {
$membershipConditions[] = $qb->expr()->eq('cl.manually_removed', 0);
}

$subq = $this->getEntityManager()->getConnection()->createQueryBuilder()
->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl')
->where(
$qb->expr()->andX(
$qb->expr()->eq('cl.lead_id', 'll.lead_id'),
$qb->expr()->eq('cl.campaign_id', (int) $campaignId)
)
$qb->expr()->andX(...$membershipConditions)
);

$qb->andWhere(
Expand Down
30 changes: 30 additions & 0 deletions app/bundles/CampaignBundle/Model/CampaignModel.php
Expand Up @@ -1022,4 +1022,34 @@ private function getArrayCollectionOfContactsById(array $contacts)

return new ArrayCollection($keyById);
}

/**
* @param $segmentId
*
* @return array
*/
public function getCampaignIdsWithDependenciesOnSegment($segmentId)
{
$entities = $this->getRepository()->getEntities(
[
'filter' => [
'force' => [
[
'column' => 'l.id',
'expr' => 'eq',
'value' => $segmentId,
],
],
],
'joinLists' => true,
]
);

$ids = [];
foreach ($entities as $entity) {
$ids[] = $entity->getId();
}

return $ids;
}
}

0 comments on commit 77b1165

Please sign in to comment.