View file upload/src/addons/AddonFlare/PaidRegistrations/XF/Pub/Controller/Register.php

File size: 10.17Kb
<?php

namespace AddonFlare\PaidRegistrations\XF\Pub\Controller;

use XF\ConnectedAccount\Provider\AbstractProvider;
use XF\ConnectedAccount\ProviderData\AbstractProviderData;
use XF\Mvc\ParameterBag;

class Register extends XFCP_Register
{
    public function checkCsrfIfNeeded($action, ParameterBag $params)
    {
        if (in_array($action, ['Index', 'AccountType'])) return;

        parent::checkCsrfIfNeeded($action, $params);
    }

    public function actionIndex()
    {
        if (!$this->options()->af_paidregistrations_guest)
        {
            return parent::actionIndex();
        }

        $accountTypeId = $this->filter('accountType', 'uint');

        if (($purchaseRequestKey = $this->filter('custom', 'str')) || ($purchaseRequestKey = $this->filter('cm', 'str')) || ($purchaseRequestKey = $this->filter('prk', 'str')))
        {
            $purchaseRequest = $this->em()->findOne('XF:PurchaseRequest', [
                'request_key' => $purchaseRequestKey,
                'user_id'     => 0,
                'purchasable_type_id' => 'user_upgrade',
            ]);

            if ($purchaseRequest)
            {
                $userUpgrade = $this->em()->find('XF:UserUpgrade', $purchaseRequest->extra_data['user_upgrade_id']);

                if ($userUpgrade && $userUpgrade->can_purchase)
                {
                    $reply = parent::actionIndex();

                    if ($reply instanceof \XF\Mvc\Reply\View)
                    {
                        if (!empty($purchaseRequest->extra_data['email']))
                        {
                            $this->assertPaidRegistrationEmailNotRegistered($purchaseRequest->extra_data['email']);
                        }

                        // use the purchase request cost amount instead just incase it was a custom amount
                        $userUpgrade->cost_amount = $purchaseRequest->cost_amount;
                        // set to read only just incase it somehow attempts to save, shouldn't happen though
                        $userUpgrade->setReadOnly(true);

                        $reply->setParam('purchaseRequest', $purchaseRequest);
                        $reply->setParam('userUpgrade', $userUpgrade);

                        $fields = $reply->getParam('fields');
                        $fields['email'] = $purchaseRequest->extra_data['email'];
                        $reply->setParam('fields', $fields);
                    }

                    return $reply;
                }
            }
        }

        $accountType = $this->getAccountType($accountTypeId);

        // if no or invalid account type was chosen or a valid account type was chosen but it's not a "free" type
        // entering a valid user_upgrade_id ex. register/?accountType=3 should still show the list because we handle the purchase in actionPurchase()
        if (!$accountType || $accountType->user_upgrade_id != -1)
        {
            // at least one account type must be available
            if ($this->getAccountTypeRepo()->findActiveAccountTypesForList()->total())
            {
                return $this->accountTypes();
            }
        }

        // regular registration form, only executed by "free type"
        return parent::actionIndex();
    }

    public function actionRegister()
    {
        if (!$this->options()->af_paidregistrations_guest)
        {
            return parent::actionRegister();
        }

        $purchaseRequest = null;

        if ($purchaseRequestKey = $this->filter('prk', 'str'))
        {
            $purchaseRequest = $this->em()->findOne('XF:PurchaseRequest', [
                'request_key' => $purchaseRequestKey,
                'user_id'     => 0,
                'purchasable_type_id' => 'user_upgrade',
            ]);

            if ($purchaseRequest && !empty($purchaseRequest->extra_data['email']))
            {
                $this->assertPaidRegistrationEmailNotRegistered($purchaseRequest->extra_data['email']);
            }
        }

        $freeAccountTypes = $this->getAccountTypeRepo()->findActiveAccountTypesForList()
        ->where('user_upgrade_id', '=', -1)->fetch();

        if (!$purchaseRequest && !$freeAccountTypes->count())
        {
            if ($this->getAccountTypeRepo()->findActiveAccountTypesForList()->total())
            {
                // there's no valid purchase request and there's no free account type and we have at least one active account type the guest could've used to register
                return $this->error(\XF::phrase('invalid_purchase_request'));
            }
        }

        // make sure the same email is being used to register
        if ($this->options()->af_paidregistrations_force_same_email && $purchaseRequest && !empty($purchaseRequest->extra_data['email']))
        {
            $regForm = $this->service('XF:User\RegisterForm', $this->session());
            if ($purchaseRequest->extra_data['email'] != $this->filter($regForm->getFieldName('email'), 'str'))
            {
                return $this->error(\XF::phrase('af_paidregistrations_must_use_same_email', ['email' => $purchaseRequest->extra_data['email']]));
            }
        }

        // process normal registration
        $reply = parent::actionRegister();

        $visitor = \XF::visitor();

        // if registration was successful & we have a purchase request, link it to the new user
        if ($visitor->user_id && $purchaseRequest)
        {
            $purchaseRequest->fastUpdate('user_id', $visitor->user_id);
        }

        return $reply;
    }

    public function actionPurchase()
    {
        $accountTypeId = $this->filter('accountType', 'uint');

        $accountType = $this->getAccountType($accountTypeId);

        if
        (
            !$accountType ||
            $accountType->user_upgrade_id == -1 ||
            !$accountType->UserUpgrade ||
            !$accountType->UserUpgrade->can_purchase ||
            ($accountType->allow_custom_amount && $accountType->disable_custom_amount_guest)
        )
        {
            return $this->error(\XF::phrase('af_paidregistrations_invalid_accountType'));
        }

        /** @var \XF\Repository\Payment $paymentRepo */
        $paymentRepo = $this->repository('XF:Payment');
        $profiles = $paymentRepo->findPaymentProfilesForList()
            ->where(['Provider.provider_id', '=', \AddonFlare\PaidRegistrations\Entity\AccountType::getSupportedPaymentProviderIds()])
            ->pluckFrom(function ($e)
            {
                return ($e->display_title ?: $e->title);
            })
        ->fetch();

        $aliasUpgrades = [];

        if ($accountType->alias_user_upgrades)
        {
            $aliasUserUpgradeIds = array_keys($accountType->alias_user_upgrades);
            // add the main/parent user_upgrade_id
            $aliasUserUpgradeIds[] = $accountType->user_upgrade_id;

            $upgradeRepo = $this->repository('XF:UserUpgrade');
            $aliasUpgrades = $upgradeRepo->findUserUpgradesForList()
                ->where('can_purchase', '=', 1)
                ->whereIds($aliasUserUpgradeIds)
            ->fetch();
        }

        $viewParams = [
            'accountType'       => $accountType,
            'upgrade'           => $accountType->UserUpgrade,
            'profiles'          => $profiles,
            'aliasUpgrades'     => $aliasUpgrades,
            'isRegistration'    => true,
            'hasOnlyPayPal'     => false, // never true for guests, they need to fill out email field
            'allowCustomAmount' => $accountType->allow_custom_amount,
        ];

        return $this->view('', 'af_paidregistrations_purchase', $viewParams);
    }

    protected function accountTypes()
    {
        if (\XF::visitor()->user_id)
        {
            return $this->redirect($this->getDynamicRedirectIfNot($this->buildLink('register')));
        }

        $this->assertRegistrationActive();

        $purchasable = $this->em()->find('XF:Purchasable', 'user_upgrade', 'AddOn');
        if (!$purchasable->isActive())
        {
            return $this->message(\XF::phrase('no_account_upgrades_can_be_purchased_at_this_time'));
        }

        $upgradeRepo = $this->repository('XF:UserUpgrade');
        $upgrades = $upgradeRepo->findUserUpgradesForList()->fetch();

        if (!$upgrades->count())
        {
            return $this->message(\XF::phrase('no_account_upgrades_can_be_purchased_at_this_time'));
        }

        $accountTypes = $this->getAccountTypeRepo()->findActiveAccountTypesForList()->fetch();

        $has = false;
        foreach ($accountTypes as $accountType)
        {
            if ($accountType->user_upgrade_id == -1 || $accountType->version)
            {
                $has = true;
                break;
            }
        }

        if (!$has)
        {
            $this->em()->create('AddonFlare\PaidRegistrations:AccountType')->save();
            $accountTypes = $this->getAccountTypeRepo()->findActiveAccountTypesForList()->fetch();
        }

        // since this controller is used by guests only, make sure custom amount is disabled or allowed for guests
        $accountTypes = $accountTypes->filter(function($accountType)
        {
            return (!$accountType->allow_custom_amount || !$accountType->disable_custom_amount_guest);
        });

        $accountTypeRows = $accountTypes->groupBy('row');

        ksort($accountTypeRows);

        $viewParams = [
            'accountTypeRows' => $accountTypeRows,
        ];

        return $this->view('', 'af_paidregistrations_accounttype', $viewParams);
    }

    protected function getAccountTypeRepo()
    {
        return $this->repository('AddonFlare\PaidRegistrations:AccountType');
    }

    protected function getAccountType($accountTypeId)
    {
        $accountType = $this->getAccountTypeRepo()->findAccountTypesForList()
            ->where('account_type_id', '=', $accountTypeId)
        ->fetchOne();

        return $accountType;
    }

    protected function assertPaidRegistrationEmailNotRegistered($email)
    {
        if ($existingUser = \XF::finder('XF:User')->where('email', $email)->fetchOne())
        {
            throw $this->exception($this->error(\XF::phrase('af_paidregistrations_already_registered_username_x', ['username' => $existingUser['username']])));
        }

        return true;
    }
}