Issues (281)

Branch: master

src/Backend/Modules/Profiles/Actions/Edit.php (1 issue)

1
<?php
2
3
namespace Backend\Modules\Profiles\Actions;
4
5
use Backend\Core\Engine\Base\ActionEdit as BackendBaseActionEdit;
6
use Backend\Core\Engine\Authentication as BackendAuthentication;
7
use Backend\Core\Engine\DataGridDatabase as BackendDataGridDatabase;
8
use Backend\Core\Engine\DataGridFunctions as BackendDataGridFunctions;
9
use Backend\Core\Engine\Form as BackendForm;
10
use Backend\Core\Language\Language as BL;
11
use Backend\Core\Engine\Model as BackendModel;
12
use Backend\Form\Type\DeleteType;
13
use Backend\Modules\Profiles\Engine\Model as BackendProfilesModel;
14
use Symfony\Component\Intl\Intl as Intl;
15
16
/**
17
 * This is the edit-action, it will display a form to edit an existing profile.
18
 */
19
class Edit extends BackendBaseActionEdit
20
{
21
    /**
22
     * Groups data grid.
23
     *
24
     * @var BackendDataGridDatabase
25
     */
26
    private $dgGroups;
27
28
    /**
29
     * @var bool
30
     */
31
    private $notifyProfile;
32
33
    /**
34
     * Info about the current profile.
35
     *
36
     * @var array
37
     */
38
    private $profile;
39
40
    public function execute(): void
41
    {
42
        $this->id = $this->getRequest()->query->getInt('id');
43
44
        // does the item exist?
45
        if ($this->id !== 0 && BackendProfilesModel::exists($this->id)) {
46
            parent::execute();
47
            $this->getData();
48
            $this->loadGroups();
49
            $this->loadForm();
50
            $this->validateForm();
51
            $this->loadDeleteForm();
52
            $this->parse();
53
            $this->display();
54
        } else {
55
            $this->redirect(BackendModel::createUrlForAction('Index') . '&error=non-existing');
56
        }
57
    }
58
59
    private function getData(): void
60
    {
61
        // get general info
62
        $this->profile = BackendProfilesModel::get($this->id);
63
64
        $this->notifyProfile = $this->get('fork.settings')->get(
65
            $this->url->getModule(),
66
            'send_new_profile_mail',
67
            false
68
        );
69
    }
70
71
    private function loadForm(): void
72
    {
73
        // gender dropdown values
74
        $genderValues = [
75
            'male' => \SpoonFilter::ucfirst(BL::getLabel('Male')),
76
            'female' => \SpoonFilter::ucfirst(BL::getLabel('Female')),
77
        ];
78
79
        // birthdate dropdown values
80
        $days = range(1, 31);
81
        $months = \SpoonLocale::getMonths(BL::getInterfaceLanguage());
82
        $years = range(date('Y'), 1900);
83
84
        // get settings
85
        $birthDate = BackendProfilesModel::getSetting($this->id, 'birth_date');
86
87
        // get day, month and year
88
        if ($birthDate) {
89
            list($birthYear, $birthMonth, $birthDay) = explode('-', $birthDate);
90
        } else {
91
            // no birth date setting
92
            $birthDay = '';
93
            $birthMonth = '';
94
            $birthYear = '';
95
        }
96
97
        // create form
98
        $this->form = new BackendForm('edit');
99
100
        // create elements
101
        $this->form->addCheckbox('new_email');
102
        $this->form
103
            ->addText('email', $this->profile['email'])
104
        ;
105
        $this->form->addCheckbox('new_password');
106
        $this->form
107
            ->addPassword('password')
108
            ->setAttribute('autocomplete', 'new-password')
109
        ;
110
        $this->form
111
            ->addPassword('password_repeat')
112
            ->setAttribute('autocomplete', 'new-password')
113
        ;
114
        $this->form
115
            ->addText('display_name', $this->profile['display_name'])
116
            ->makeRequired()
117
        ;
118
        $this->form
119
            ->addText('first_name', BackendProfilesModel::getSetting($this->id, 'first_name'))
120
        ;
121
        $this->form
122
            ->addText('last_name', BackendProfilesModel::getSetting($this->id, 'last_name'))
123
        ;
124
        $this->form
125
            ->addText('city', BackendProfilesModel::getSetting($this->id, 'city'))
126
        ;
127
        $this->form
128
            ->addDropdown('gender', $genderValues, BackendProfilesModel::getSetting($this->id, 'gender'))
129
        ;
130
        $this->form
131
            ->addDropdown('day', array_combine($days, $days), $birthDay)
132
        ;
133
        $this->form
134
            ->addDropdown('month', $months, $birthMonth)
135
        ;
136
        $this->form
137
            ->addDropdown('year', array_combine($years, $years), (int) $birthYear)
138
        ;
139
        $this->form
140
            ->addDropdown(
141
                'country',
142
                Intl::getRegionBundle()->getCountryNames(BL::getInterfaceLanguage()),
0 ignored issues
show
Deprecated Code introduced by
The function Symfony\Component\Intl\Intl::getRegionBundle() has been deprecated: since Symfony 4.3, to be removed in 5.0. Use {@see Countries} instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

142
                /** @scrutinizer ignore-deprecated */ Intl::getRegionBundle()->getCountryNames(BL::getInterfaceLanguage()),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
143
                BackendProfilesModel::getSetting($this->id, 'country')
144
            )
145
            ->setAttribute('autocomplete', 'country-name')
146
        ;
147
        $this->form->addTextarea('about', BackendProfilesModel::getSetting($this->id, 'about'));
148
149
        // set default elements dropdowns
150
        $this->form->getField('gender')->setDefaultElement('');
151
        $this->form->getField('day')->setDefaultElement('');
152
        $this->form->getField('month')->setDefaultElement('');
153
        $this->form->getField('year')->setDefaultElement('');
154
        $this->form->getField('country')->setDefaultElement('');
155
    }
156
157
    private function loadGroups(): void
158
    {
159
        // create the data grid
160
        $this->dgGroups = new BackendDataGridDatabase(
161
            BackendProfilesModel::QUERY_DATAGRID_BROWSE_PROFILE_GROUPS,
162
            [$this->profile['id']]
163
        );
164
        $this->dgGroups->setColumnFunction('htmlspecialchars', ['[group_name]'], 'group_name', false);
165
166
        // sorting columns
167
        $this->dgGroups->setSortingColumns(['group_name'], 'group_name');
168
169
        // disable paging
170
        $this->dgGroups->setPaging(false);
171
172
        // set column function
173
        $this->dgGroups->setColumnFunction(
174
            [new BackendDataGridFunctions(), 'getLongDate'],
175
            ['[expires_on]'],
176
            'expires_on',
177
            true
178
        );
179
180
        // check if this action is allowed
181
        if (BackendAuthentication::isAllowedAction('EditProfileGroup')) {
182
            // set column URLs
183
            $this->dgGroups->setColumnURL(
184
                'group_name',
185
                BackendModel::createUrlForAction('EditProfileGroup') . '&amp;id=[id]&amp;profile_id=' . $this->id
186
            );
187
188
            // edit column
189
            $this->dgGroups->addColumn(
190
                'edit',
191
                null,
192
                BL::getLabel('Edit'),
193
                BackendModel::createUrlForAction('EditProfileGroup') . '&amp;id=[id]&amp;profile_id=' . $this->id,
194
                BL::getLabel('Edit')
195
            );
196
        }
197
    }
198
199
    protected function parse(): void
200
    {
201
        parent::parse();
202
203
        $this->template->assign('notifyProfile', $this->notifyProfile);
204
205
        // assign the active record and additional variables
206
        $this->template->assign('profile', $this->profile);
207
208
        // parse data grids
209
        $this->template->assign('dgGroups', ($this->dgGroups->getNumResults() != 0) ? $this->dgGroups->getContent() : false);
210
211
        // show delete or undelete button?
212
        if ($this->profile['status'] === 'deleted') {
213
            $this->template->assign('deleted', true);
214
        }
215
216
        // show block or unblock button?
217
        if ($this->profile['status'] === 'blocked') {
218
            $this->template->assign('blocked', true);
219
        }
220
221
        $this->header->appendDetailToBreadcrumbs($this->profile['display_name']);
222
    }
223
224
    private function validateForm(): void
225
    {
226
        // is the form submitted?
227
        if ($this->form->isSubmitted()) {
228
            // cleanup the submitted fields, ignore fields that were added by hackers
229
            $this->form->cleanupFields();
230
231
            // get fields
232
            $chkNewEmail = $this->form->getField('new_email');
233
            $txtEmail = $this->form->getField('email');
234
            $txtDisplayName = $this->form->getField('display_name');
235
            $chkNewPassword = $this->form->getField('new_password');
236
            $txtPassword = $this->form->getField('password');
237
            $txtPasswordRepeat = $this->form->getField('password_repeat');
238
            $txtFirstName = $this->form->getField('first_name');
239
            $txtLastName = $this->form->getField('last_name');
240
            $txtCity = $this->form->getField('city');
241
            $ddmGender = $this->form->getField('gender');
242
            $ddmDay = $this->form->getField('day');
243
            $ddmMonth = $this->form->getField('month');
244
            $ddmYear = $this->form->getField('year');
245
            $ddmCountry = $this->form->getField('country');
246
            $txtAbout = $this->form->getField('about');
247
248
            // email filled in?
249
            if ($chkNewEmail->isChecked() && $txtEmail->isFilled(BL::getError('EmailIsRequired'))) {
250
                // email must not be the same as previous one
251
                if ($txtEmail->getValue() == $this->profile['email']) {
252
                    $txtEmail->addError(BL::getError('EmailMatchesPrevious'));
253
                }
254
255
                // valid email?
256
                if ($txtEmail->isEmail(BL::getError('EmailIsInvalid'))) {
257
                    // email already exists?
258
                    if (BackendProfilesModel::existsByEmail($txtEmail->getValue(), $this->id)) {
259
                        // set error
260
                        $txtEmail->addError(BL::getError('EmailExists'));
261
                    }
262
                }
263
            }
264
265
            // display name filled in?
266
            if ($txtDisplayName->isFilled(BL::getError('DisplayNameIsRequired'))) {
267
                // display name already exists?
268
                if (BackendProfilesModel::existsDisplayName($txtDisplayName->getValue(), $this->id)) {
269
                    // set error
270
                    $txtDisplayName->addError(BL::getError('DisplayNameExists'));
271
                }
272
            }
273
274
            // new_password is checked, so verify new password (only if profile should not be notified)
275
            // because then if the password field is empty, it will generate a new password
276
            if ($chkNewPassword->isChecked() && !$this->notifyProfile) {
277
                $txtPassword->isFilled(BL::err('FieldIsRequired'));
278
                $txtPasswordRepeat->isFilled(BL::err('FieldIsRequired'));
279
280
                // both password fields are filled in and should match
281
                if ($txtPassword->isFilled() && $txtPasswordRepeat->isFilled()
282
                    && ($txtPassword->getValue() != $txtPasswordRepeat->getValue())) {
283
                    $txtPasswordRepeat->addError(BL::err('PasswordRepeatIsRequired'));
284
                }
285
            }
286
287
            // one of the bday fields are filled in
288
            if ($ddmDay->isFilled() || $ddmMonth->isFilled() || $ddmYear->isFilled()) {
289
                // valid date?
290
                if (!checkdate($ddmMonth->getValue(), $ddmDay->getValue(), $ddmYear->getValue())) {
291
                    // set error
292
                    $ddmYear->addError(BL::getError('DateIsInvalid'));
293
                }
294
            }
295
296
            // no errors?
297
            if ($this->form->isCorrect()) {
298
                // build item
299
                $values = ['email' => $chkNewEmail->isChecked() ? $txtEmail->getValue() : $this->profile['email']];
300
                $password = BL::lbl('YourExistingPassword');
301
302
                // only update if display name changed
303
                if ($txtDisplayName->getValue() != $this->profile['display_name']) {
304
                    $values['display_name'] = $txtDisplayName->getValue();
305
                    $values['url'] = BackendProfilesModel::getUrl(
306
                        $txtDisplayName->getValue(),
307
                        $this->id
308
                    );
309
                }
310
311
                // new password filled in?
312
                if ($chkNewPassword->isChecked()) {
313
                    // new password filled in? otherwise generate a password
314
                    $password = ($txtPassword->isFilled()) ?
315
                        $txtPassword->getValue() : BackendModel::generatePassword(8);
316
317
                    // build password
318
                    $values['password'] = BackendProfilesModel::encryptPassword($password);
319
                }
320
321
                // update values
322
                BackendProfilesModel::update($this->id, $values);
323
324
                // birthday is filled in
325
                if ($ddmYear->isFilled()) {
326
                    // mysql format
327
                    $birthDate = $ddmYear->getValue() . '-';
328
                    $birthDate .= str_pad($ddmMonth->getValue(), 2, '0', STR_PAD_LEFT) . '-';
329
                    $birthDate .= str_pad($ddmDay->getValue(), 2, '0', STR_PAD_LEFT);
330
                } else {
331
                    $birthDate = null;
332
                }
333
334
                // update settings
335
                BackendProfilesModel::setSetting($this->id, 'first_name', $txtFirstName->getValue());
336
                BackendProfilesModel::setSetting($this->id, 'last_name', $txtLastName->getValue());
337
                BackendProfilesModel::setSetting($this->id, 'gender', $ddmGender->getValue());
338
                BackendProfilesModel::setSetting($this->id, 'birth_date', $birthDate);
339
                BackendProfilesModel::setSetting($this->id, 'city', $txtCity->getValue());
340
                BackendProfilesModel::setSetting($this->id, 'country', $ddmCountry->getValue());
341
                BackendProfilesModel::setSetting($this->id, 'about', $txtAbout->getValue());
342
343
                $displayName = $values['display_name'] ?? $this->profile['display_name'];
344
345
                $redirectUrl = BackendModel::createUrlForAction('Index') .
346
                               '&var=' . rawurlencode($values['email']) .
347
                    '&highlight=row-' . $this->id .
348
                    '&var=' . rawurlencode($displayName) .
349
                    '&report='
350
                ;
351
352
                if ($this->notifyProfile &&
353
                    ($chkNewEmail->isChecked() || $chkNewPassword->isChecked())
354
                ) {
355
                    // notify values
356
                    $notifyValues = array_merge(
357
                        $values,
358
                        [
359
                            'id' => $this->id,
360
                            'first_name' => $txtFirstName->getValue(),
361
                            'last_name' => $txtLastName->getValue(),
362
                            'unencrypted_password' => $password,
363
                        ]
364
                    );
365
366
                    if (!isset($notifyValues['display_name'])) {
367
                        $notifyValues['display_name'] = $this->profile['display_name'];
368
                    }
369
370
                    BackendProfilesModel::notifyProfile($notifyValues, true);
371
372
                    $redirectUrl .= 'saved-and-notified';
373
                } else {
374
                    $redirectUrl .= 'saved';
375
                }
376
377
                // everything is saved, so redirect to the overview
378
                $this->redirect($redirectUrl);
379
            }
380
        }
381
    }
382
383
    private function loadDeleteForm(): void
384
    {
385
        $deleteForm = $this->createForm(
386
            DeleteType::class,
387
            ['id' => $this->profile['id']],
388
            ['module' => $this->getModule()]
389
        );
390
        $this->template->assign('deleteForm', $deleteForm->createView());
391
    }
392
}
393