Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Service/User/UsernameChange.php
<?php

namespace XF\Service\User;

use
XF\Entity\User;
use
XF\Service\ValidateAndSavableTrait;

class
UsernameChange extends \XF\Service\AbstractService
{
    use
ValidateAndSavableTrait;

   
/**
     * @var User
     */
   
protected $user;

   
/**
     * @var \XF\Entity\UsernameChange
     */
   
protected $usernameChange;

    protected
$logIp = true;

    protected
$isModeratorAction = false;

    protected
$notify = false;

    public function
__construct(\XF\App $app, $userOrChange)
    {
       
parent::__construct($app);

        if (
$userOrChange instanceof User)
        {
           
$this->user = $userOrChange;
           
$this->usernameChange = $this->setupNewUsernameChange($userOrChange);
        }
        else if (
$userOrChange instanceof \XF\Entity\UsernameChange)
        {
            if (
$userOrChange->change_state != 'moderated')
            {
                throw new \
InvalidArgumentException("Can only action existing username changes when pending");
            }

            if (!
$userOrChange->User)
            {
                throw new \
InvalidArgumentException("Username change is missing User relation value");
            }

           
$this->usernameChange = $userOrChange;
           
$this->user = $userOrChange->User;
        }
        else
        {
            throw new \
InvalidArgumentException("Must pass User or UsernameChange entity into service");
        }
    }

    protected function
setupNewUsernameChange(\XF\Entity\User $user): \XF\Entity\UsernameChange
   
{
       
/** @var \XF\Entity\UsernameChange $usernameChange */
       
$usernameChange = $this->em()->create('XF:UsernameChange');
       
$usernameChange->user_id = $this->user->user_id;
       
$usernameChange->old_username = $this->user->username;
       
$usernameChange->change_user_id = \XF::visitor()->user_id;
       
$usernameChange->change_state = $this->getDefaultChangeState();

        return
$usernameChange;
    }

    protected function
getDefaultChangeState(): string
   
{
       
$visitor = \XF::visitor();

        if (
$visitor->hasPermission('general', 'approveUsernameChange')
            ||
$visitor->hasPermission('general', 'changeUsernameNoApproval')
        )
        {
            return
'approved';
        }
        else
        {
            return
'moderated';
        }
    }

    public function
getUser(): \XF\Entity\User
   
{
        return
$this->user;
    }

    public function
getUsernameChange(): \XF\Entity\UsernameChange
   
{
        return
$this->usernameChange;
    }

    public function
setAdminEdit()
    {
       
$this->logIp(false);
       
$this->usernameChange->setOption('admin_edit', true);
       
$this->usernameChange->change_state = 'approved';
    }

    public function
setModeratorRejection(bool $notify = false, string $reason = '')
    {
       
$this->usernameChange->change_state = 'rejected';
       
$this->usernameChange->moderator_user_id = \XF::visitor()->user_id;
       
$this->usernameChange->reject_reason = $reason;

       
$this->logIp(false);
       
$this->isModeratorAction = true;
       
$this->notify = $notify;
    }

    public function
setModeratorApproval(bool $notify = false)
    {
       
$this->usernameChange->change_state = 'approved';
       
$this->usernameChange->moderator_user_id = \XF::visitor()->user_id;

       
$this->logIp(false);
       
$this->isModeratorAction = true;
       
$this->notify = $notify;
    }

    public function
setNewUsername(string $newUsername)
    {
       
$this->usernameChange->new_username = $newUsername;
    }

    public function
setChangeReason(string $reason)
    {
       
$this->usernameChange->change_reason = $reason;
    }

    public function
setVisibility(bool $visibility)
    {
       
$this->usernameChange->visible = $visibility;
    }

    public function
logIp($logIp)
    {
       
$this->logIp = $logIp;
    }

    protected function
finalSetup()
    {
    }

    protected function
_validate()
    {
       
$this->finalSetup();

       
$this->usernameChange->preSave();
        return
$this->usernameChange->getErrors();
    }

    protected function
_save()
    {
       
$user = $this->user;
       
$usernameChange = $this->usernameChange;

       
$isInsert = $usernameChange->isInsert();

        if (
$usernameChange->change_state == 'approved')
        {
           
// set the user to admin_edit as we have already validated most changes and we want to bypass things like
            // the pending name check
           
$user->setOption('admin_edit', true);
           
$user->username = $usernameChange->new_username;
           
$user->setOption('admin_edit', false);

           
// we already have that record here
           
$user->setOption('insert_username_change_history', false);

           
$usernameChange->addCascadedSave($user);
        }

       
$this->db()->beginTransaction();

       
$usernameChange->save(true, false);

        if (
$usernameChange->change_state == 'approved')
        {
           
$this->onApproval();
        }
        else if (
$usernameChange->change_state == 'rejected')
        {
           
$this->onRejection();
        }
        else if (
$isInsert && $usernameChange->change_state == 'moderated')
        {
           
$this->onAwaitingApproval();
        }

       
$this->db()->commit();

       
// reset this
       
$user->setOption('insert_username_change_history', true);

        return
$usernameChange;
    }

    protected function
onApproval()
    {
       
$user = $this->user;
       
$usernameChange = $this->usernameChange;

        if (
$this->logIp)
        {
           
$ip = ($this->logIp === true ? $this->app->request()->getIp() : $this->logIp);
           
$this->writeIpLog($ip);
        }

        if (
$this->notify)
        {
           
/** @var \XF\Repository\UserAlert $alertRepo */
           
$alertRepo = \XF::app()->repository('XF:UserAlert');
           
$alertRepo->alert(
               
$this->user,
               
0, '',
               
'user', $user->user_id,
               
'username_change_approved', [
                   
'oldUsername' => $usernameChange->old_username,
                   
'newUsername' => $usernameChange->new_username
               
]
            );
        }

        if (
$this->isModeratorAction)
        {
            \
XF::app()->logger()->logModeratorAction('user', $user, 'username_change_approved', [
               
'old' => $usernameChange->old_username,
               
'new' => $usernameChange->new_username
           
]);
        }
    }

    protected function
onRejection()
    {
       
$user = $this->user;
       
$usernameChange = $this->usernameChange;
       
$reason = $usernameChange->reject_reason;

        if (
$this->notify)
        {
           
/** @var \XF\Repository\UserAlert $alertRepo */
           
$alertRepo = \XF::app()->repository('XF:UserAlert');
           
$alertRepo->alert(
               
$user,
               
0, '',
               
'user', $user->user_id,
               
'username_change_rejected', [
                   
'rejectedUsername' => $usernameChange->new_username,
                   
'reason' => $reason
               
]
            );
        }

        if (
$this->isModeratorAction)
        {
            \
XF::app()->logger()->logModeratorAction('user', $user, 'username_change_rejected', [
               
'old' => $usernameChange->old_username,
               
'new' => $usernameChange->new_username,
               
'reason' => $reason
           
]);
        }
    }

    protected function
onAwaitingApproval()
    {
        if (
$this->logIp)
        {
           
$ip = ($this->logIp === true ? $this->app->request()->getIp() : $this->logIp);
           
$user = $this->user;

           
/** @var \XF\Repository\Ip $ipRepo */
           
$ipRepo = $this->repository('XF:Ip');
           
$ipRepo->logIp($user->user_id, $ip, 'user', $user->user_id, 'username_change_request');
           
// note: can't use writeIpLog as the action is different than expected there
       
}
    }

    protected function
writeIpLog($ip)
    {
       
$user = $this->user;

       
/** @var \XF\Repository\Ip $ipRepo */
       
$ipRepo = $this->repository('XF:Ip');
       
$ipRepo->logIp($user->user_id, $ip, 'user', $user->user_id, 'username_change');
    }
}