Passed
Push — main ( a22652...94920f )
by Greg
08:47
created

UserEdit::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 11
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2025 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
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Cli\Commands;
21
22
use Fisharebest\Webtrees\Contracts\UserInterface;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\Contracts\UserInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Fisharebest\Webtrees\Services\MessageService;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\Services\MessageService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use Fisharebest\Webtrees\Services\UserService;
25
use Fisharebest\Webtrees\Site;
26
use Fisharebest\Webtrees\User;
27
use Symfony\Component\Console\Command\Command;
28
use Symfony\Component\Console\Input\InputArgument;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Input\InputOption;
31
use Symfony\Component\Console\Output\OutputInterface;
32
use Symfony\Component\Console\Style\SymfonyStyle;
33
34
final class UserEdit extends AbstractCommand
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')
45
            ->setDescription(description: 'Create/delete/edit a user')
46
            ->addArgument(name: 'user-name', mode: InputArgument::REQUIRED, description: 'The username')
47
            ->addOption(name: 'create', mode: InputOption::VALUE_NONE, description: 'Create a new user')
48
            ->addOption(name: 'delete', mode: InputOption::VALUE_NONE, description: 'Delete an existing user')
49
            ->addOption(name: 'real-name', mode: InputOption::VALUE_REQUIRED, description: 'Set the real name of the user')
50
            ->addOption(name: 'email', mode: InputOption::VALUE_REQUIRED, description: 'Set the email of the user')
51
            ->addOption(name: 'password', mode: InputOption::VALUE_REQUIRED, description: 'Set the password of the user');
52
    }
53
54
    protected function execute(InputInterface $input, OutputInterface $output): int
55
    {
56
        $io = new SymfonyStyle(input: $input, output: $output);
57
58
        $user_name = $this->stringArgument(input: $input, name: 'user-name');
59
        $real_name = $this->stringOption(input: $input, name: 'real-name');
60
        $email     = $this->stringOption(input: $input, name: 'email');
61
        $password  = $this->stringOption(input: $input, name: 'password');
62
        $create    = $this->boolOption(input: $input, name: 'create');
63
        $delete    = $this->boolOption(input: $input, name: 'delete');
64
65
        if ($user_name === '') {
66
            $io->error(message: 'The user- name cannot be empty.');
67
68
            return Command::INVALID;
69
        }
70
71
        if ($delete && $create) {
72
            $io->error(message: 'Invalid options: cannot use --delete and --create at the same time.');
73
74
            return Command::INVALID;
75
        }
76
77
        if ($delete && $real_name !== '') {
78
            $io->error(message: 'Invalid options: cannot use --delete and --real-name at the same time.');
79
80
            return Command::INVALID;
81
        }
82
83
        if ($delete && $email !== '') {
84
            $io->error(message: 'Invalid options: cannot use --delete and --email at the same time.');
85
86
            return Command::INVALID;
87
        }
88
89
        if ($delete && $password !== '') {
90
            $io->error(message: 'Invalid options: cannot use --delete and --password at the same time.');
91
92
            return Command::INVALID;
93
        }
94
95
        $user = $this->user_service->all()->first(callback: static fn (User $user): bool => $user->userName() === $user_name);
96
97
        if ($create) {
98
            if ($user instanceof User) {
99
                $io->error(message: 'A user with the username "' . $user_name . '" already exists.');
100
101
                return Command::FAILURE;
102
            }
103
104
            if ($real_name === '') {
105
                $io->error(message: 'Invalid options: --real-name is required when using --create.');
106
107
                return Command::FAILURE;
108
            }
109
110
            if ($email === '') {
111
                $io->error(message: 'Invalid options: --email is required when using --create.');
112
113
                return Command::FAILURE;
114
            }
115
116
            if ($password === '') {
117
                $password = bin2hex(string: random_bytes(length: 8));
118
                $io->info(message: 'No password specified. Using a random password ‘' . $password . '’.');
119
            }
120
121
            $user = $this->user_service->create(
122
                user_name: $user_name,
123
                real_name: $real_name,
124
                email: $email,
125
                password: $password,
126
            );
127
128
            // Some preferences need to be set for all users.
129
            $user->setPreference(
130
                setting_name: UserInterface::PREF_LANGUAGE,
131
                setting_value: 'en-US',
132
            );
133
            $user->setPreference(
134
                setting_name: UserInterface::PREF_TIME_ZONE,
135
                setting_value: Site::getPreference('TIMEZONE'),
136
            );
137
            $user->setPreference(
138
                setting_name: UserInterface::PREF_IS_EMAIL_VERIFIED,
139
                setting_value: '1',
140
            );
141
            $user->setPreference(
142
                setting_name: UserInterface::PREF_IS_ACCOUNT_APPROVED,
143
                setting_value: '1',
144
            );
145
            $user->setPreference(
146
                setting_name: UserInterface::PREF_CONTACT_METHOD,
147
                setting_value: MessageService::CONTACT_METHOD_INTERNAL_AND_EMAIL,
148
            );
149
            $user->setPreference(
150
                setting_name: UserInterface::PREF_IS_VISIBLE_ONLINE,
151
                setting_value: '1',
152
            );
153
            $io->info(message: 'User ‘' . $user_name . '’ was created.  Account set to approved and verified.');
154
155
            return self::SUCCESS;
156
        }
157
158
        if ($user === null) {
159
            $io->error(message: 'User ‘' . $user_name . '’ does not exist.');
160
161
            return Command::FAILURE;
162
        }
163
164
        if ($delete) {
165
            $this->user_service->delete(user: $user);
166
            $io->success(message: 'User ‘' . $user_name . '’ was deleted..');
167
168
            return self::SUCCESS;
169
        }
170
171
        if ($real_name === '' && $email === '' && $password === '') {
172
            $io->info(message: 'Nothing to do. Specify --real-name, --email or --password.');
173
174
            return Command::INVALID;
175
        }
176
177
        if ($real_name !== '') {
178
            $user->setRealName($real_name);
179
            $io->info(message: 'Real name set to ‘' . $real_name . '’.');
180
        }
181
182
        if ($email !== '') {
183
            $user->setEmail($email);
184
            $io->info(message: 'E-mail set to ‘' . $email . '’.');
185
        }
186
187
        if ($password !== '') {
188
            $user->setPassword($password);
189
            $io->info(message: 'Password set to ‘' . $password . '’.');
190
        }
191
192
        return self::SUCCESS;
193
    }
194
}
195