Remove usage old model from Throttling

[MAILPOET-3032]
This commit is contained in:
Jan Lysý
2021-04-02 17:11:07 +02:00
committed by Veljko V
parent 4631fb7320
commit 4d56020071
3 changed files with 77 additions and 40 deletions

View File

@ -4,6 +4,7 @@ namespace MailPoet\Subscribers;
use MailPoet\Doctrine\Repository;
use MailPoet\Entities\SubscriberIPEntity;
use MailPoetVendor\Carbon\Carbon;
/**
* @extends Repository<SubscriberIPEntity>
@ -12,4 +13,39 @@ class SubscriberIPsRepository extends Repository {
protected function getEntityClassName() {
return SubscriberIPEntity::class;
}
public function findOneByIPAndCreatedAtAfterTimeInSeconds(string $ip, int $seconds): ?SubscriberIPEntity {
return $this->entityManager->createQueryBuilder()
->select('sip')
->from(SubscriberIPEntity::class, 'sip')
->where('sip.ip = :ip')
->andWhere('sip.createdAt >= :timeThreshold')
->setParameter('ip', $ip)
->setParameter('timeThreshold', (new Carbon())->subSeconds($seconds))
->setMaxResults(1)
->getQuery()
->getOneOrNullResult();
}
public function getCountByIPAndCreatedAtAfterTimeInSeconds(string $ip, int $seconds): int {
return $this->entityManager->createQueryBuilder()
->select('COUNT(sip)')
->from(SubscriberIPEntity::class, 'sip')
->where('sip.ip = :ip')
->andWhere('sip.createdAt >= :timeThreshold')
->setParameter('ip', $ip)
->setParameter('timeThreshold', (new Carbon())->subSeconds($seconds))
->getQuery()
->getSingleScalarResult();
}
public function deleteCreatedAtBeforeTimeInSeconds(int $seconds): int {
return (int)$this->entityManager->createQueryBuilder()
->delete()
->from(SubscriberIPEntity::class, 'sip')
->where('sip.createdAt < :timeThreshold')
->setParameter('timeThreshold', (new Carbon())->subSeconds($seconds))
->getQuery()
->execute();
}
}

View File

@ -2,42 +2,37 @@
namespace MailPoet\Subscription;
use MailPoet\Models\SubscriberIP;
use MailPoet\Entities\SubscriberIPEntity;
use MailPoet\Subscribers\SubscriberIPsRepository;
use MailPoet\Util\Helpers;
use MailPoet\WP\Functions as WPFunctions;
class Throttling {
/** @var SubscriberIPsRepository */
private $subscriberIPsRepository;
/** @var WPFunctions */
private $wp;
public function __construct(WPFunctions $wp) {
public function __construct(SubscriberIPsRepository $subscriberIPsRepository, WPFunctions $wp) {
$this->wp = $wp;
$this->subscriberIPsRepository = $subscriberIPsRepository;
}
public function throttle() {
$subscriptionLimitEnabled = $this->wp->applyFilters('mailpoet_subscription_limit_enabled', true);
$subscriptionLimitWindow = $this->wp->applyFilters('mailpoet_subscription_limit_window', DAY_IN_SECONDS);
$subscriptionLimitBase = $this->wp->applyFilters('mailpoet_subscription_limit_base', MINUTE_IN_SECONDS);
$subscriptionLimitWindow = (int)$this->wp->applyFilters('mailpoet_subscription_limit_window', DAY_IN_SECONDS);
$subscriptionLimitBase = (int)$this->wp->applyFilters('mailpoet_subscription_limit_base', MINUTE_IN_SECONDS);
$subscriberIp = Helpers::getIP();
if ($subscriptionLimitEnabled && !$this->wp->isUserLoggedIn()) {
if (!empty($subscriberIp)) {
$subscriptionCount = SubscriberIP::where('ip', $subscriberIp)
->whereRaw(
'(`created_at` >= NOW() - INTERVAL ? SECOND)',
[(int)$subscriptionLimitWindow]
)->count();
$subscriptionCount = $this->subscriberIPsRepository->getCountByIPAndCreatedAtAfterTimeInSeconds($subscriberIp, $subscriptionLimitWindow);
if ($subscriptionCount > 0) {
$timeout = $subscriptionLimitBase * pow(2, $subscriptionCount - 1);
$existingUser = SubscriberIP::where('ip', $subscriberIp)
->whereRaw(
'(`created_at` >= NOW() - INTERVAL ? SECOND)',
[(int)$timeout]
)->findOne();
$existingUser = $this->subscriberIPsRepository->findOneByIPAndCreatedAtAfterTimeInSeconds($subscriberIp, $timeout);
if (!empty($existingUser)) {
return $timeout;
}
@ -45,21 +40,23 @@ class Throttling {
}
}
$ip = SubscriberIP::create();
$ip->ip = $subscriberIp;
$ip->save();
if ($subscriberIp !== null) {
$ip = new SubscriberIPEntity($subscriberIp);
$existingIp = $this->subscriberIPsRepository->findOneBy(['ip' => $ip->getIP(), 'createdAt' => $ip->getCreatedAt()]);
if (!$existingIp) {
$this->subscriberIPsRepository->persist($ip);
$this->subscriberIPsRepository->flush();
}
}
$this->purge();
return false;
}
public function purge() {
public function purge(): void {
$interval = $this->wp->applyFilters('mailpoet_subscription_purge_window', MONTH_IN_SECONDS);
return SubscriberIP::whereRaw(
'(`created_at` < NOW() - INTERVAL ? SECOND)',
[$interval]
)->deleteMany();
$this->subscriberIPsRepository->deleteCreatedAtBeforeTimeInSeconds($interval);
}
public function secondsToTimeString($seconds): string {

View File

@ -2,7 +2,8 @@
namespace MailPoet\Subscription;
use MailPoet\Models\SubscriberIP;
use MailPoet\Entities\SubscriberIPEntity;
use MailPoet\Subscribers\SubscriberIPsRepository;
use MailPoet\WP\Functions as WPFunctions;
use MailPoetVendor\Carbon\Carbon;
@ -10,9 +11,13 @@ class ThrottlingTest extends \MailPoetTest {
/** @var Throttling */
private $throttling;
/** @var SubscriberIPsRepository */
private $subscriberIPsRepository;
protected function _before() {
parent::_before();
$this->throttling = $this->diContainer->get(Throttling::class);
$this->subscriberIPsRepository = $this->diContainer->get(SubscriberIPsRepository::class);
}
public function testItProgressivelyThrottlesSubscriptions() {
@ -20,10 +25,7 @@ class ThrottlingTest extends \MailPoetTest {
expect($this->throttling->throttle())->equals(false);
expect($this->throttling->throttle())->equals(60);
for ($i = 1; $i <= 10; $i++) {
$ip = SubscriberIP::create();
$ip->ip = '127.0.0.1';
$ip->createdAt = Carbon::now()->subMinutes($i);
$ip->save();
$this->createSubscriberIP('127.0.0.1', Carbon::now()->subMinutes($i));
}
expect($this->throttling->throttle())->equals(MINUTE_IN_SECONDS * pow(2, 10));
}
@ -49,18 +51,12 @@ class ThrottlingTest extends \MailPoetTest {
}
public function testItPurgesOldSubscriberIps() {
$ip = SubscriberIP::create();
$ip->ip = '127.0.0.1';
$ip->save();
$this->createSubscriberIP('127.0.0.1', Carbon::now());
$this->createSubscriberIP('127.0.0.1', Carbon::now()->subDays(30)->subSeconds(1));
$ip2 = SubscriberIP::create();
$ip2->ip = '127.0.0.1';
$ip2->createdAt = Carbon::now()->subDays(30)->subSeconds(1);
$ip2->save();
expect(SubscriberIP::count())->equals(2);
expect($this->subscriberIPsRepository->countBy([]))->equals(2);
$this->throttling->throttle();
expect(SubscriberIP::count())->equals(1);
expect($this->subscriberIPsRepository->countBy([]))->equals(1);
}
public function testItConvertsSecondsToTimeString() {
@ -73,7 +69,15 @@ class ThrottlingTest extends \MailPoetTest {
expect($this->throttling->secondsToTimeString(59))->equals('59 seconds');
}
private function createSubscriberIP(string $ip, Carbon $createdAt): SubscriberIPEntity {
$subscriberIP = new SubscriberIPEntity($ip);
$subscriberIP->setCreatedAt($createdAt);
$this->entityManager->persist($subscriberIP);
$this->entityManager->flush();
return $subscriberIP;
}
public function _after() {
SubscriberIP::deleteMany();
$this->truncateEntity(SubscriberIPEntity::class);
}
}