HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Services/WarmupStrategyService.php
<?php

namespace App\Services;

use App\Dto\WarmupStrategyData;
use App\Dto\WarmupStrategyPreviewData;
use App\Model\SendingServer;
use App\Model\User;
use App\Model\WarmupStrategy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;

class WarmupStrategyService
{
    public function listQuery(?string $keyword = null): Builder
    {
        return WarmupStrategy::query()->search($keyword);
    }

    public function newStrategy(?string $preset = null): WarmupStrategy
    {
        $strategy = WarmupStrategy::newDefault();

        if ($preset !== null) {
            $strategy->fill($this->presetPayload($preset));
        }

        return $strategy;
    }

    public function create(WarmupStrategyData $data): WarmupStrategy
    {
        return DB::transaction(function () use ($data) {
            $strategy = new WarmupStrategy();

            return $this->persist($strategy, $data);
        });
    }

    public function update(WarmupStrategy $strategy, WarmupStrategyData $data): WarmupStrategy
    {
        return DB::transaction(function () use ($strategy, $data) {
            return $this->persist($strategy, $data);
        });
    }

    public function assignToSendingServer(SendingServer $server, ?WarmupStrategy $warmupStrategy): void
    {
        $server->saveWarmupStrategy($warmupStrategy);
    }

    public function deleteMany(iterable $strategies, User $user): array
    {
        $total = 0;
        $deleted = 0;

        foreach ($strategies as $strategy) {
            $total++;
            if ($user->admin->can('delete', $strategy)) {
                $strategy->delete();
                $deleted++;
            }
        }

        return [$deleted, $total];
    }

    public function enableMany(iterable $strategies, User $user): array
    {
        return $this->toggleMany($strategies, $user, 'enable');
    }

    public function disableMany(iterable $strategies, User $user): array
    {
        return $this->toggleMany($strategies, $user, 'disable');
    }

    public function buildPreview(WarmupStrategy|WarmupStrategyData $source): WarmupStrategyPreviewData
    {
        $strategy = $source instanceof WarmupStrategy ? $source : $this->previewModel($source);
        $planDetails = $strategy->getPlanDetails();
        $estimatedFullWarmupDay = $strategy->estimatedFullWarmupDay();
        $milestones = array_map(function ($step) {
            return [
                'label' => 'Day '.$step['step'],
                'volume' => (int) $step['sendingOfStep'],
            ];
        }, $this->samplePlanDetails($planDetails, 4));
        $chartPoints = array_map(function ($step) {
            return [
                'day' => (int) $step['step'],
                'volume' => (int) $step['sendingOfStep'],
                'cumulative' => (int) $step['quota'],
            ];
        }, $this->samplePlanDetails($planDetails, 14));

        return new WarmupStrategyPreviewData(
            growthStrategy: (string) ($strategy->growth_strategy ?: WarmupStrategy::GROWTH_STRATEGY_LINEAR),
            limitType: (string) ($strategy->limit_type ?: WarmupStrategy::LIMIT_TYPE_PER_DAY_CAP),
            startVolume: (int) $strategy->starting_volume,
            dailyIncrement: (int) $strategy->daily_increment,
            exponentialFactor: (float) ($strategy->exponential_factor ?: WarmupStrategy::exponentialFactorFromIncrement((int) $strategy->daily_increment)),
            activeLimitValue: $strategy->activeLimitValue(),
            projectedPeakVolume: $strategy->projectedPeakVolume(),
            projectedTotalVolume: $strategy->projectedTotalVolume(),
            estimatedFullWarmupDay: $estimatedFullWarmupDay,
            riskLevel: $strategy->riskLevel(),
            milestones: $milestones,
            chartPoints: $chartPoints,
            planDetails: $planDetails,
        );
    }

    public function presetPayload(?string $preset): array
    {
        return match ($preset) {
            WarmupStrategy::PRESET_CAUTIOUS => [
                'preset' => WarmupStrategy::PRESET_CAUTIOUS,
                'growth_strategy' => WarmupStrategy::GROWTH_STRATEGY_LINEAR,
                'starting_volume' => 15,
                'daily_increment' => 8,
                'exponential_factor' => 1.08,
                'limit_per_day_cap' => 500,
                'limit_target_volume' => 4000,
                'limit_stop_after_days' => 45,
                'send_on_weekends' => false,
                'enable_safety_checks' => true,
                'pause_on_negative_signals' => true,
                'max_bounce_rate' => 3.0,
                'max_complaint_rate' => 0.2,
                'limit_type' => WarmupStrategy::LIMIT_TYPE_PER_DAY_CAP,
                'quota_type' => WarmupStrategy::QUOTA_TYPE_DAILY,
            ],
            WarmupStrategy::PRESET_AGGRESSIVE => [
                'preset' => WarmupStrategy::PRESET_AGGRESSIVE,
                'growth_strategy' => WarmupStrategy::GROWTH_STRATEGY_EXPONENTIAL,
                'starting_volume' => 50,
                'daily_increment' => 20,
                'exponential_factor' => 1.20,
                'limit_per_day_cap' => 3000,
                'limit_target_volume' => 15000,
                'limit_stop_after_days' => 21,
                'send_on_weekends' => true,
                'enable_safety_checks' => true,
                'pause_on_negative_signals' => true,
                'max_bounce_rate' => 5.0,
                'max_complaint_rate' => 0.5,
                'limit_type' => WarmupStrategy::LIMIT_TYPE_STOP_AFTER_DAYS,
                'quota_type' => WarmupStrategy::QUOTA_TYPE_DAILY,
            ],
            default => [
                'preset' => WarmupStrategy::PRESET_BALANCED,
                'growth_strategy' => WarmupStrategy::GROWTH_STRATEGY_LINEAR,
                'starting_volume' => 20,
                'daily_increment' => 15,
                'exponential_factor' => 1.15,
                'limit_per_day_cap' => 1000,
                'limit_target_volume' => 8000,
                'limit_stop_after_days' => 30,
                'send_on_weekends' => false,
                'enable_safety_checks' => true,
                'pause_on_negative_signals' => true,
                'max_bounce_rate' => 4.0,
                'max_complaint_rate' => 0.3,
                'limit_type' => WarmupStrategy::LIMIT_TYPE_PER_DAY_CAP,
                'quota_type' => WarmupStrategy::QUOTA_TYPE_DAILY,
            ],
        };
    }

    private function persist(WarmupStrategy $strategy, WarmupStrategyData $data): WarmupStrategy
    {
        $previewStrategy = $this->previewModel($data);

        $strategy->fill([
            'name' => $data->name,
            'description' => $data->description,
            'preset' => $data->preset,
            'growth_strategy' => $previewStrategy->growth_strategy,
            'starting_volume' => $data->startingVolume,
            'quota_type' => $data->quotaType,
            'daily_increment' => $previewStrategy->daily_increment,
            'exponential_factor' => $previewStrategy->exponential_factor,
            'limit_type' => $data->limitType,
            'limit_per_day_cap' => $data->limitPerDayCap,
            'limit_target_volume' => $data->limitTargetVolume,
            'limit_stop_after_days' => $data->limitStopAfterDays,
            'send_on_weekends' => $data->sendOnWeekends,
            'enable_safety_checks' => $data->enableSafetyChecks,
            'pause_on_negative_signals' => $data->pauseOnNegativeSignals,
            'max_bounce_rate' => $data->maxBounceRate,
            'max_complaint_rate' => $data->maxComplaintRate,
            'status' => $data->status,
            'sending_count' => $previewStrategy->sending_count,
            'sending_limit' => $previewStrategy->sending_limit,
            'increment_percentage' => $previewStrategy->increment_percentage,
        ]);

        $strategy->save();

        return $strategy;
    }

    private function previewModel(WarmupStrategyData $data): WarmupStrategy
    {
        $strategy = WarmupStrategy::newDefault();
        $strategy->fill(array_filter($data->toArray(), function ($value) {
            return $value !== null;
        }));
        $strategy->growth_strategy = $data->growthStrategy;
        $strategy->daily_increment = $data->growthStrategy === WarmupStrategy::GROWTH_STRATEGY_EXPONENTIAL
            ? WarmupStrategy::incrementFromExponentialFactor((float) ($data->exponentialFactor ?? WarmupStrategy::DEFAULT_EXPONENTIAL_FACTOR))
            : $data->dailyIncrement;
        $strategy->exponential_factor = $data->exponentialFactor ?? WarmupStrategy::DEFAULT_EXPONENTIAL_FACTOR;
        $strategy->limit_type = $data->limitType;
        $strategy->limit_per_day_cap = $data->limitPerDayCap;
        $strategy->limit_target_volume = $data->limitTargetVolume;
        $strategy->limit_stop_after_days = $data->limitStopAfterDays;

        $planDetails = $strategy->getPlanDetails();

        $strategy->sending_count = max(1, count($planDetails));
        $strategy->sending_limit = max(1, (int) collect($planDetails)->max('sendingOfStep'));
        $strategy->increment_percentage = $strategy->daily_increment;

        return $strategy;
    }

    private function toggleMany(iterable $strategies, User $user, string $action): array
    {
        $total = 0;
        $done = 0;

        foreach ($strategies as $strategy) {
            $total++;
            if ($user->admin->can($action, $strategy)) {
                $strategy->{$action}();
                $done++;
            }
        }

        return [$done, $total];
    }

    private function samplePlanDetails(array $planDetails, int $count): array
    {
        $total = count($planDetails);

        if ($total <= $count) {
            return $planDetails;
        }

        $indices = [];

        for ($position = 0; $position < $count; $position++) {
            $indices[] = (int) round(($position * ($total - 1)) / max(1, $count - 1));
        }

        $indices = array_values(array_unique($indices));

        return array_map(function ($index) use ($planDetails) {
            return $planDetails[$index];
        }, $indices);
    }
}