Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 138 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
AccountUserEmailLogic | |
0.00% |
0 / 138 |
|
0.00% |
0 / 7 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
startup | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
12 | |||
validateImpl | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
executeImpl | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
executeEdit | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
2 | |||
executeConfirm | |
0.00% |
0 / 59 |
|
0.00% |
0 / 1 |
30 | |||
cleanup | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\App\Models\Domain\Page\Account; |
6 | |
7 | use PeServer\App\Models\AppConfiguration; |
8 | use PeServer\App\Models\AppCryptography; |
9 | use PeServer\App\Models\AppMailer; |
10 | use PeServer\App\Models\AppTemplate; |
11 | use PeServer\App\Models\AuditLog; |
12 | use PeServer\App\Models\Dao\Domain\UserDomainDao; |
13 | use PeServer\App\Models\Dao\Entities\UserChangeWaitEmailsEntityDao; |
14 | use PeServer\App\Models\Domain\AccountValidator; |
15 | use PeServer\App\Models\Domain\Page\PageLogicBase; |
16 | use PeServer\App\Models\SessionKey; |
17 | use PeServer\Core\Cryptography; |
18 | use PeServer\Core\Database\IDatabaseContext; |
19 | use PeServer\Core\I18n; |
20 | use PeServer\Core\Mail\EmailAddress; |
21 | use PeServer\Core\Mail\EmailMessage; |
22 | use PeServer\Core\Mail\Mailer; |
23 | use PeServer\Core\Mvc\LogicCallMode; |
24 | use PeServer\Core\Mvc\LogicParameter; |
25 | use PeServer\Core\Mvc\Validator; |
26 | use PeServer\Core\Text; |
27 | use PeServer\Core\Throws\NotImplementedException; |
28 | |
29 | class AccountUserEmailLogic extends PageLogicBase |
30 | { |
31 | /** |
32 | * Undocumented function |
33 | * |
34 | * @var array{email:string,wait_email:string,token_timestamp_utc:string} |
35 | */ |
36 | private array $defaultValues = [ |
37 | 'email' => Text::EMPTY, |
38 | 'wait_email' => Text::EMPTY, |
39 | 'token_timestamp_utc' => Text::EMPTY, |
40 | ]; |
41 | |
42 | public function __construct(LogicParameter $parameter, private AppConfiguration $config, private AppCryptography $cryptography, private Mailer $mailer, private AppTemplate $appTemplate) |
43 | { |
44 | parent::__construct($parameter); |
45 | } |
46 | |
47 | #region PageLogicBase |
48 | |
49 | protected function startup(LogicCallMode $callMode): void |
50 | { |
51 | $userInfo = $this->requireSession(SessionKey::ACCOUNT); |
52 | |
53 | $database = $this->openDatabase(); |
54 | |
55 | $userDomainDao = new UserDomainDao($database); |
56 | $values = $userDomainDao->selectEmailAndWaitTokenTimestamp( |
57 | $userInfo->userId, |
58 | $this->config->setting->config->confirm->userChangeWaitEmailMinutes |
59 | ); |
60 | |
61 | if (!Text::isNullOrWhiteSpace($values->fields['email'])) { |
62 | $this->defaultValues['email'] = $this->cryptography->decrypt($values->fields['email']); |
63 | } else { |
64 | $this->defaultValues['email'] = Text::EMPTY; |
65 | } |
66 | if (!Text::isNullOrWhiteSpace($values->fields['wait_email'])) { |
67 | $this->defaultValues['wait_email'] = $this->cryptography->decrypt($values->fields['wait_email']); |
68 | } else { |
69 | $this->defaultValues['wait_email'] = Text::EMPTY; |
70 | } |
71 | |
72 | $this->defaultValues['token_timestamp_utc'] = $values->fields['token_timestamp_utc']; |
73 | |
74 | parent::registerParameterKeys([ |
75 | 'account_email_email', |
76 | 'account_email_token', |
77 | 'wait_email', |
78 | 'token_timestamp_utc', |
79 | ], true); |
80 | |
81 | $this->setValue('account_email_token', Text::EMPTY); |
82 | } |
83 | |
84 | protected function validateImpl(LogicCallMode $callMode): void |
85 | { |
86 | if ($callMode === LogicCallMode::Initialize) { |
87 | return; |
88 | } |
89 | |
90 | $mode = $this->getRequest('account_email_mode'); |
91 | if ($mode === 'edit') { |
92 | $this->validation('account_email_email', function (string $key, string $value) { |
93 | $accountValidator = new AccountValidator($this, $this->validator); |
94 | $accountValidator->isEmail($key, $value); |
95 | }); |
96 | } elseif ($mode === 'confirm') { |
97 | $this->validation('account_email_token', function (string $key, string $value) { |
98 | $this->validator->isNotWhiteSpace($key, $value); |
99 | |
100 | if (Text::isNullOrWhiteSpace($this->defaultValues['token_timestamp_utc'])) { |
101 | $this->addError($key, I18n::message('error/email_confirm_token_not_found')); |
102 | } |
103 | }); |
104 | } else { |
105 | $this->logger->warn('不明なモード要求 {0}', $mode); |
106 | $this->addCommonError(I18n::message('error/unknown_email_mode')); |
107 | } |
108 | } |
109 | |
110 | protected function executeImpl(LogicCallMode $callMode): void |
111 | { |
112 | if ($callMode === LogicCallMode::Initialize) { |
113 | return; |
114 | } |
115 | |
116 | $mode = $this->getRequest('account_email_mode'); |
117 | |
118 | if ($mode === 'edit') { |
119 | $this->executeEdit($callMode); |
120 | } else { |
121 | if ($mode !== 'confirm') { |
122 | throw new NotImplementedException(); |
123 | } |
124 | |
125 | $this->executeConfirm($callMode); |
126 | } |
127 | } |
128 | |
129 | private function executeEdit(LogicCallMode $callMode): void |
130 | { |
131 | $account = $this->requireSession(SessionKey::ACCOUNT); |
132 | |
133 | $email = $this->getRequest('account_email_email'); |
134 | |
135 | $params = [ |
136 | 'user_id' => $account->userId, |
137 | 'email' => $this->cryptography->encrypt($email), |
138 | 'mark_email' => $this->cryptography->toMark($email), |
139 | 'token' => sprintf('%08d', Cryptography::generateRandomInteger(0, 99999999)), |
140 | ]; |
141 | |
142 | $database = $this->openDatabase(); |
143 | |
144 | $database->transaction(function (IDatabaseContext $context) use ($params) { |
145 | $userChangeWaitEmailsEntityDao = new UserChangeWaitEmailsEntityDao($context); |
146 | |
147 | $userChangeWaitEmailsEntityDao->deleteByUserId($params['user_id']); |
148 | $userChangeWaitEmailsEntityDao->insertWaitEmails($params['user_id'], $params['email'], $params['mark_email'], $params['token']); |
149 | |
150 | $this->writeAuditLogCurrentUser(AuditLog::USER_EMAIL_CHANGING, ['token' => $params['token']], $context); |
151 | |
152 | return true; |
153 | }); |
154 | |
155 | // トークン通知メール送信 |
156 | $subject = I18n::message('subject/email_change_token'); |
157 | $values = [ |
158 | 'name' => $account->name, |
159 | 'token' => $params['token'], |
160 | ]; |
161 | $html = $this->appTemplate->createMailTemplate('change_email_token', $subject, $values); |
162 | |
163 | $this->mailer->toAddresses = [ |
164 | new EmailAddress($email, $account->name), |
165 | ]; |
166 | $this->mailer->subject = $subject; |
167 | $this->mailer->setMessage(new EmailMessage(null, $html)); |
168 | |
169 | $this->mailer->send(); |
170 | //file_put_contents('X:\00_others\00_others\a.html',$html); |
171 | $this->addTemporaryMessage(I18n::message('message/flash/send_email_token')); |
172 | } |
173 | |
174 | private function executeConfirm(LogicCallMode $callMode): void |
175 | { |
176 | $account = $this->requireSession(SessionKey::ACCOUNT); |
177 | |
178 | $params = [ |
179 | 'user_id' => $account->userId, |
180 | 'token' => $this->getRequest('account_email_token'), |
181 | ]; |
182 | |
183 | $database = $this->openDatabase(); |
184 | $result = $database->transaction(function (IDatabaseContext $context) use ($params) { |
185 | $userDomainDao = new UserDomainDao($context); |
186 | $userChangeWaitEmailsEntityDao = new UserChangeWaitEmailsEntityDao($context); |
187 | |
188 | $existsToken = $userChangeWaitEmailsEntityDao->selectExistsToken( |
189 | $params['user_id'], |
190 | $params['token'], |
191 | $this->config->setting->config->confirm->userChangeWaitEmailMinutes |
192 | ); |
193 | |
194 | if (!$existsToken) { |
195 | return false; |
196 | } |
197 | |
198 | $updated = $userDomainDao->updateEmailFromWaitEmail( |
199 | $params['user_id'], |
200 | $params['token'] |
201 | ); |
202 | |
203 | if (!$updated) { |
204 | return false; |
205 | } |
206 | |
207 | $userChangeWaitEmailsEntityDao->deleteByUserId($params['user_id']); |
208 | |
209 | $this->writeAuditLogCurrentUser(AuditLog::USER_EMAIL_CHANGED, ['token' => $params['token']], $context); |
210 | |
211 | return true; |
212 | }); |
213 | |
214 | if (!$result) { |
215 | $this->addError('account_email_token', I18n::message('error/email_confirm_token_not_found')); |
216 | return; |
217 | } |
218 | |
219 | // 新旧メールアドレスにそれぞれ通知メール送信 |
220 | $items = [ |
221 | [ |
222 | 'template' => 'change_email_new', |
223 | 'subject' => 'subject/email_change_new', |
224 | 'email' => $this->defaultValues['wait_email'], |
225 | ], |
226 | [ |
227 | 'template' => 'change_email_old', |
228 | 'subject' => 'subject/email_change_old', |
229 | 'email' => $this->defaultValues['email'], |
230 | ], |
231 | ]; |
232 | |
233 | foreach ($items as $item) { |
234 | $subject = I18n::message($item['subject']); |
235 | $values = [ |
236 | 'user_id' => $account->userId, |
237 | 'login_id' => $account->loginId, |
238 | 'name' => $account->name, |
239 | 'new_email' => $this->defaultValues['wait_email'], |
240 | 'old_email' => $this->defaultValues['email'], |
241 | ]; |
242 | $html = $this->appTemplate->createMailTemplate($item['template'], $subject, $values); |
243 | |
244 | $this->mailer->toAddresses = [ |
245 | new EmailAddress($item['email'], $account->name), |
246 | ]; |
247 | $this->mailer->subject = $subject; |
248 | $this->mailer->setMessage(new EmailMessage(null, $html)); |
249 | |
250 | $this->mailer->send(); |
251 | } |
252 | |
253 | $this->result['confirm'] = true; |
254 | |
255 | $this->addTemporaryMessage(I18n::message('message/flash/updated_email')); |
256 | } |
257 | |
258 | protected function cleanup(LogicCallMode $callMode): void |
259 | { |
260 | if (!($this->getRequest('account_email_mode') == 'edit' && $callMode === LogicCallMode::Submit)) { |
261 | $this->setValue('account_email_email', $this->defaultValues['email']); |
262 | } |
263 | |
264 | $this->setValue('wait_email', $this->defaultValues['wait_email']); |
265 | $this->setValue('token_timestamp_utc', $this->defaultValues['token_timestamp_utc']); |
266 | } |
267 | |
268 | #endregion |
269 | } |