luyadev/luya-module-admin

View on GitHub
src/commands/SetupController.php

Summary

Maintainability
C
1 day
Test Coverage
F
0%
<?php

namespace luya\admin\commands;

use luya\admin\models\Config;
use luya\admin\models\Group;
use luya\admin\models\User;
use Yii;
use yii\console\Exception;
use yii\db\Query;
use yii\helpers\VarDumper;
use yii\imagine\Image;

/**
 * Setup the Administration Interface.
 *
 * You can also use the parameters to run the setup command for example.
 *
 * ```php
 * ./vendor/bin/luya admin/setup --email=foo@bar.com --password=test --firstname=John --lastname=Doe --interactive=0
 * ```
 *
 * This will perform the Setup task silent and does not prompt any questions.
 *
 * @author Basil Suter <basil@nadar.io>
 * @since 1.0.0
 */
class SetupController extends \luya\console\Command
{
    /**
     * @var string The email of the user to create or change.
     */
    public $email;

    /**
     * @var string The blank password of the user to create or change.
     */
    public $password;

    /**
     * @var string The first name of the user to create.
     */
    public $firstname;

    /**
     * @var string The last name of the user to create.
     */
    public $lastname;

    /**
     * @var string Whether the setup is interactive or not.
     */
    public $interactive = true;

    /**
     * @var string The name of the default language, e.g. English
     */
    public $langName;

    /**
     * @var string The short code of the language, e.g. en
     */
    public $langShortCode;

    /**
     * @inheritdoc
     */
    public function options($actionID)
    {
        return ['email', 'password', 'firstname', 'lastname', 'interactive'];
    }

    /**
     * Setup the administration area.
     *
     * This action of setup will add a new user, group, language, permissions, default homepage and container.
     *
     * @return boolean
     */
    public function actionIndex()
    {
        try {
            Image::getImagine();
        } catch (\Exception $e) {
            return $this->outputError('Setup error - Unable to find image library: ' . $e->getMessage());
        }

        if (!Config::has(Config::CONFIG_LAST_IMPORT_TIMESTAMP)) {
            return $this->outputError("You have to run the 'import' process first. Run in terminal: ./vendor/bin/luya import");
        }

        if (Config::has(Config::CONFIG_SETUP_COMMAND_TIMESTAMP)) {
            return $this->outputError('The setup process already have been executed at '.date('d.m.Y H:i', Config::get(Config::CONFIG_SETUP_COMMAND_TIMESTAMP)).'. If you like to reinstall your application, drop all tables from your database, run the migrate and import command and then re-run the setup command.');
        }

        if (empty($this->email)) {
            $this->email = $this->prompt('User Email:', ['required' => true]);
        }

        if (empty($this->password)) {
            $this->password = $this->prompt('User Password:', ['required' => true]);
        }

        if (empty($this->firstname)) {
            $this->firstname = $this->prompt('First Name:', ['required' => true]);
        }

        if (empty($this->lastname)) {
            $this->lastname = $this->prompt('Last Name:', ['required' => true]);
        }

        if (empty($this->langName)) {
            $this->langName = $this->prompt('Default Language:', ['required' => true, 'default' => 'English']);
        }

        if (empty($this->langShortCode)) {
            $this->langShortCode = $this->prompt('Short Code of the Default Language:', ['required' => true, 'default' => 'en', 'validator' => function ($input, &$error) {
                if (strlen($input) !== 2) {
                    $error = 'The Short Code must be 2 chars length only. Examples: de, en, fr, ru';
                    return false;
                }
                return true;
            }]);
        }

        if ($this->interactive) {
            $this->outputInfo('User Email: '. $this->email);
            $this->outputInfo('First Name: '. $this->firstname);
            $this->outputInfo('Last Name: '. $this->lastname);
            $this->outputInfo('Default Language: '. $this->langName);

            if ($this->confirm("Confirm your login details in order to proceed with the setup. Are those informations correct?") !== true) {
                return $this->outputError('Aborted by user.');
            }
        }

        $salt = Yii::$app->security->generateRandomString();
        $pw = Yii::$app->security->generatePasswordHash($this->password.$salt);

        $this->insert('{{%admin_user}}', [
            'title' => 1,
            'firstname' => $this->firstname,
            'lastname' => $this->lastname,
            'email' => $this->email,
            'password' => $pw,
            'password_salt' => $salt,
            'is_deleted' => false,
        ]);

        $this->insert('{{%admin_group}}', [
            'name' => 'Administrator',
            'text' => 'Administrator accounts have full access to all areas and can create, update and delete all data records.',
        ]);

        $this->insert('{{%admin_user_group}}', [
            'user_id' => 1,
            'group_id' => 1,
        ]);

        // get the api-admin-user and api-admin-group auth rights
        $data = (new Query())->select(['id'])->from('{{%admin_auth}}')->all();

        foreach ($data as $item) {
            $this->insert('{{%admin_group_auth}}', [
                'group_id' => 1,
                'auth_id' => $item['id'],
                'crud_create' => 1,
                'crud_update' => 1,
                'crud_delete' => 1,
            ]);
        }

        $this->insert('{{%admin_lang}}', [
            'name' => $this->langName,
            'short_code' => $this->langShortCode,
            'is_default' => true,
        ]);

        if (Yii::$app->hasModule('cms')) {
            // insert default page
            $this->insert("cms_nav_container", ['id' => 1, 'name' => 'Default Container', 'alias' => 'default', 'is_deleted' => false]);
            $this->insert("cms_nav", ['nav_container_id' => 1, 'parent_nav_id' => 0, 'sort_index' => 0, 'is_deleted' => false, 'is_hidden' => false, 'is_offline' => false, 'is_home' => true, 'is_draft' => false]);
            $this->insert("cms_nav_item", ['nav_id' => 1, 'lang_id' => 1, 'nav_item_type' => 1, 'nav_item_type_id' => 1, 'create_user_id' => 1, 'update_user_id' => 1, 'timestamp_create' => time(), 'title' => 'Homepage', 'alias' => 'homepage']);
            $this->insert('cms_nav_item_page', ['layout_id' => 1, 'create_user_id' => 1, 'timestamp_create' => time(), 'version_alias' => 'Initial', 'nav_item_id' => 1]);
        }

        Config::set(Config::CONFIG_SETUP_COMMAND_TIMESTAMP, time());

        return $this->outputSuccess("Setup is finished. You can now login into the administration area with the email '{$this->email}'.");
    }

    /**
     * Create a new user and append them to an existing group.
     * @return bool
     * @throws Exception
     */
    public function actionUser()
    {
        while (true) {
            $email = $this->prompt('User Email:');
            if (!empty(User::findByEmail($email))) {
                $this->outputError('The provided email already exists in the system.');
            } else {
                break;
            }
        }

        $titleArray = ['Mr' => 1, 'Mrs' => 2];
        $title = $this->select('Title:', $titleArray);

        $firstname = $this->prompt('First Name:');
        $lastname = $this->prompt('Last Name:');
        $password = $this->prompt('User Password:');

        if ($this->confirm("Are you sure to create the user '$email'?") !== true) {
            return $this->outputError('Abort user creation process.');
        }

        $user = new User();
        $user->email = $email;
        $user->password_salt = Yii::$app->getSecurity()->generateRandomString();
        $user->password = Yii::$app->getSecurity()->generatePasswordHash($password.$user->password_salt);
        $user->firstname = $firstname;
        $user->lastname = $lastname;
        $user->title = $titleArray[$title];
        if (!$user->save()) {
            return $this->outputError('User validation error: ' . VarDumper::dumpAsString($user->getErrors()));
        }

        $groupSelect = [];

        foreach (Group::find()->all() as $entry) {
            $groupSelect[$entry->id] = $entry->name.' ('.$entry->text.')';
            $this->output($entry->id.' - '.$groupSelect[$entry->id]);
        }
        $groupId = $this->select('Select group the user should belong to:', $groupSelect);

        $this->insert('{{%admin_user_group}}', [
            'user_id' => $user->id,
            'group_id' => $groupId,
        ]);

        return $this->outputSuccess("The user '$email' has been created.");
    }

    /**
     * Change the password of an admin user.
     *
     * @return bool
     * @since 2.0.0
     */
    public function actionResetPassword()
    {
        $email = null;
        /** @var User $user */
        $user = null;

        while (empty($user)) {
            $email = $this->email ?: $this->prompt('User Email:');
            $user = User::findByEmail($email);
            if (empty($user)) {
                $this->outputError('The provided email was not found in the system.');
            }
        }

        $password = $this->password ?: $this->prompt('User Password:');

        if ($this->confirm("Are you sure to change the password of user '$email'?") !== true) {
            return $this->outputError('Abort password change process.');
        }

        $user->password_salt = Yii::$app->getSecurity()->generateRandomString();
        $user->password = Yii::$app->getSecurity()->generatePasswordHash($password.$user->password_salt);
        if ($user->save(true, ['password', 'password_salt'])) {
            return $this->outputSuccess("The password for user '$email' has been changed.");
        }

        return $this->outputError("The password could not be changed.\n" . implode("\n", $user->firstErrors));
    }

    /**
     * Helper to insert data in database table.
     *
     * @param string $table The database table
     * @param array $fields The array with insert fields
     * @return int
     */
    private function insert($table, array $fields)
    {
        return Yii::$app->db->createCommand()->insert($table, $fields)->execute();
    }
}