1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2023 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Cli\Commands; 21 22use Fisharebest\Webtrees\Contracts\UserInterface; 23use Fisharebest\Webtrees\DB; 24use Fisharebest\Webtrees\Services\UserService; 25use Symfony\Component\Console\Command\Command; 26use Symfony\Component\Console\Input\InputInterface; 27use Symfony\Component\Console\Input\InputOption; 28use Symfony\Component\Console\Output\OutputInterface; 29use Symfony\Component\Console\Style\SymfonyStyle; 30 31use function bin2hex; 32use function random_bytes; 33 34class UserCreate extends Command 35{ 36 public function __construct(private readonly UserService $user_service) 37 { 38 parent::__construct(); 39 } 40 41 protected function configure(): void 42 { 43 $this 44 ->setName(name: 'user-create') 45 ->setDescription(description: 'Create a new user') 46 ->addOption(name: 'username', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'The username of the new user') 47 ->addOption(name: 'realname', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'The real name of the new user') 48 ->addOption(name: 'email', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'The email of the new user') 49 ->addOption(name: 'password', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'The password of the new user') 50 ->addOption(name: 'timezone', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'Set the timezone', default: 'UTC') 51 ->addOption(name: 'language', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'Set the language', default: 'en-US') 52 ->addOption(name: 'admin', shortcut: null, mode: InputOption::VALUE_NONE, description: 'Make the new user an administrator'); 53 } 54 55 protected function execute(InputInterface $input, OutputInterface $output): int 56 { 57 $io = new SymfonyStyle(input: $input, output: $output); 58 59 $username = $input->getOption(name: 'username'); 60 $realname = $input->getOption(name: 'realname'); 61 $email = $input->getOption(name: 'email'); 62 $password = $input->getOption(name: 'password'); 63 $admin = (bool) $input->getOption(name: 'admin'); 64 $timezone = $input->getOption(name: 'timezone'); 65 $language = $input->getOption(name: 'language'); 66 67 $errors = false; 68 69 if ($username === null) { 70 $io->error(message: 'Missing required option: --username'); 71 $errors = true; 72 } 73 74 if ($realname === null) { 75 $io->error(message: 'Missing required option: --realname'); 76 $errors = true; 77 } 78 79 if ($email === null) { 80 $io->error(message: 'Missing required option: --email'); 81 $errors = true; 82 } 83 84 if ($timezone === null) { 85 $io->error(message: 'Missing required option: --timezone'); 86 $errors = true; 87 } 88 89 if ($errors) { 90 return Command::INVALID; 91 } 92 93 $user = $this->user_service->findByUserName(user_name: $username); 94 95 if ($user !== null) { 96 $io->error(message: 'A user with the username "' . $username . '" already exists.'); 97 98 return Command::FAILURE; 99 } 100 101 $user = $this->user_service->findByEmail(email: $email); 102 103 if ($user !== null) { 104 $io->error(message: 'A user with the email "' . $email . '" already exists'); 105 106 return Command::FAILURE; 107 } 108 109 if ($password === null) { 110 $password = bin2hex(string: random_bytes(length: 8)); 111 $io->info(message: 'Generated password: ' . $password); 112 } 113 114 $user = $this->user_service->create(user_name: $username, real_name:$realname, email: $email, password: $password); 115 $user->setPreference(setting_name: UserInterface::PREF_TIME_ZONE, setting_value: $timezone); 116 $user->setPreference(setting_name: UserInterface::PREF_LANGUAGE, setting_value: $language); 117 $user->setPreference(setting_name: UserInterface::PREF_IS_ACCOUNT_APPROVED, setting_value: '1'); 118 $user->setPreference(setting_name: UserInterface::PREF_IS_EMAIL_VERIFIED, setting_value: '1'); 119 $user->setPreference(setting_name: UserInterface::PREF_CONTACT_METHOD, setting_value: 'messaging'); 120 $io->success('User ' . $user->id() . ' created.'); 121 122 if ($admin) { 123 $user->setPreference(setting_name: UserInterface::PREF_IS_ADMINISTRATOR, setting_value: '1'); 124 $io->success(message: 'User granted administrator role.'); 125 } 126 127 DB::exec(sql: 'COMMIT'); 128 129 return Command::SUCCESS; 130 } 131} 132