GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — 3.0.x (#2829)
by Nicolas
04:01
created

contentSystemAuthors::__form()   F

Complexity

Conditions 63
Paths > 20000

Size

Total Lines 366
Code Lines 193

Duplication

Lines 0
Ratio 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
cc 63
eloc 193
nc 18579456
nop 0
dl 0
loc 366
rs 2
c 8
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package content
5
 */
6
7
/**
8
 * Controller page for all Symphony Author related activity
9
 * including making new Authors, editing Authors or deleting
10
 * Authors from Symphony
11
 */
12
13
class contentSystemAuthors extends AdministrationPage
14
{
15
    public $_Author;
16
    public $_errors = array();
17
18
    public function sort(&$sort, &$order, $params)
19
    {
20
        $authorQuery = (new AuthorManager)->select();
21
        if (is_null($sort) || $sort == 'name') {
22
            $authorQuery
23
                ->sort('first_name', $order)
24
                ->sort('last_name', $order);
25
        } else {
26
            $authorQuery->sort((string)$sort, $order);
27
        }
28
29
        return $authorQuery->execute()->rows();
30
    }
31
32
    public function isRemoteLoginActionChecked()
33
    {
34
        return @array_key_exists('remote_login', $_POST['action']) && $_POST['action']['remote_login'] === 'yes';
35
    }
36
37
    public function __viewIndex()
38
    {
39
        $this->setPageType('table');
40
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Authors'), __('Symphony'))));
41
42
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
43
            $this->appendSubheading(__('Authors'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new author'), 'create button', null, array('accesskey' => 'c')));
44
        } else {
45
            $this->appendSubheading(__('Authors'));
46
        }
47
48
        Sortable::initialize($this, $authors, $sort, $order);
49
50
        $columns = array(
51
            array(
52
                'label' => __('Name'),
53
                'sortable' => true,
54
                'handle' => 'name'
55
            ),
56
            array(
57
                'label' => __('Email Address'),
58
                'sortable' => true,
59
                'handle' => 'email'
60
            ),
61
            array(
62
                'label' => __('Last Seen'),
63
                'sortable' => true,
64
                'handle' => 'last_seen'
65
            )
66
        );
67
68
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
69
            $columns = array_merge($columns, array(
70
                array(
71
                    'label' => __('User Type'),
72
                    'sortable' => true,
73
                    'handle' => 'user_type'
74
                ),
75
                array(
76
                    'label' => __('Language'),
77
                    'sortable' => true,
78
                    'handle' => 'language'
79
                )
80
            ));
81
        }
82
83
        /**
84
         * Allows the creation of custom table columns for each author. Called
85
         * after all the table headers columns have been added.
86
         *
87
         * @delegate AddCustomAuthorColumn
88
         * @since Symphony 2.7.0
89
         * @param string $context
90
         * '/system/authors/'
91
         * @param array $columns
92
         * An array of the current columns, passed by reference
93
         */
94
        Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumn', '/system/authors/', array(
95
            'columns' => &$columns,
96
        ));
97
98
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
99
100
        $aTableBody = array();
101
102
        if (!is_array($authors) || empty($authors)) {
103
            $aTableBody = array(
104
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
105
            );
106
        } else {
107
            foreach ($authors as $a) {
108
                // Setup each cell
109
                if (
110
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper() && !$a->isManager()))
111
                    || Symphony::Author()->get('id') == $a->get('id')
112
                ) {
113
                    $td1 = Widget::TableData(
114
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
115
                    );
116
                } else {
117
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
118
                }
119
120
                // Can this Author be edited by the current Author?
121
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
122
                    if ($a->get('id') != Symphony::Author()->get('id')) {
123
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
124
                            'for' => 'author-' . $a->get('id')
125
                        )));
126
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
127
                            'id' => 'author-' . $a->get('id')
128
                        )));
129
                    }
130
                }
131
132
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
133
134
                if (!is_null($a->get('last_seen'))) {
135
                    $td3 = Widget::TableData(
136
                        DateTimeObj::format($a->get('last_seen'), __SYM_DATETIME_FORMAT__)
0 ignored issues
show
Bug introduced by
It seems like DateTimeObj::format($a->..._SYM_DATETIME_FORMAT__) can also be of type false; however, parameter $value of Widget::TableData() does only seem to accept string|XMLElement, maybe add an additional type check? ( Ignorable by Annotation )

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

136
                        /** @scrutinizer ignore-type */ DateTimeObj::format($a->get('last_seen'), __SYM_DATETIME_FORMAT__)
Loading history...
Bug introduced by
The constant __SYM_DATETIME_FORMAT__ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
137
                    );
138
                } else {
139
                    $td3 = Widget::TableData(__('Unknown'), 'inactive');
140
                }
141
142
                if ($a->isDeveloper()) {
143
                    $type = 'Developer';
144
                } elseif ($a->isManager()) {
145
                    $type = 'Manager';
146
                } else {
147
                    $type = 'Author';
148
                }
149
150
                $td4 = Widget::TableData(__($type));
151
152
                $languages = Lang::getAvailableLanguages();
153
154
                $td5 = Widget::TableData($a->get("language") == null ? __("System Default") : $languages[$a->get("language")]);
155
156
                $tableData = array();
157
                // Add a row to the body array, assigning each cell to the row
158
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
159
                    $tableData = array($td1, $td2, $td3, $td4, $td5);
160
                } else {
161
                    $tableData = array($td1, $td2, $td3);
162
                }
163
164
                /**
165
                 * Allows Extensions to inject custom table data for each Author
166
                 * into the Authors Index
167
                 *
168
                 * @delegate AddCustomAuthorColumnData
169
                 * @since Symphony 2.7.0
170
                 * @param string $context
171
                 * '/system/authors/'
172
                 * @param array $tableData
173
                 *  An array of `Widget::TableData`, passed by reference
174
                 * @param array $columns
175
                 * An array of the current columns
176
                 * @param Author $author
177
                 *  The Author object.
178
                 */
179
                Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumnData', '/system/authors/', array(
180
                    'tableData' => &$tableData,
181
                    'columns' => $columns,
182
                    'author' => $a,
183
                ));
184
185
                $aTableBody[] = Widget::TableRow($tableData);
186
            }
187
        }
188
189
        $table = Widget::Table(
190
            Widget::TableHead($aTableHead),
191
            null,
192
            Widget::TableBody($aTableBody),
193
            'selectable',
194
            null,
195
            array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading')
196
        );
197
198
        $this->Form->appendChild($table);
199
200
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
201
            'id' => 'version'
202
        ));
203
204
        $this->Form->appendChild($version);
205
    }
206
207
    // Both the Edit and New pages need the same form
208
    public function __viewNew()
209
    {
210
        $this->__form();
211
    }
212
213
    public function __viewEdit()
214
    {
215
        $this->__form();
216
    }
217
218
    public function __form()
219
    {
220
        // Handle unknown context
221
        if (!in_array($this->_context[0], array('new', 'edit'))) {
222
            Administration::instance()->errorPageNotFound();
223
        }
224
225
        if ($this->_context[0] == 'new' && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
226
            Administration::instance()->throwCustomError(
227
                __('You are not authorised to access this page.'),
228
                __('Access Denied'),
229
                Page::HTTP_STATUS_UNAUTHORIZED
230
            );
231
        }
232
233
        if (isset($this->_context[2])) {
234
            $time = Widget::Time();
235
236
            switch ($this->_context[2]) {
237
                case 'saved':
238
                    $message = __('Author updated at %s.', array($time->generate()));
239
                    break;
240
                case 'created':
241
                    $message = __('Author created at %s.', array($time->generate()));
242
            }
243
244
            $this->pageAlert(
245
                $message
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.
Loading history...
246
                . ' <a href="' . SYMPHONY_URL . '/system/authors/new/" accesskey="c">'
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
247
                . __('Create another?')
248
                . '</a> <a href="' . SYMPHONY_URL . '/system/authors/" accesskey="a">'
249
                . __('View all Authors')
250
                . '</a>',
251
                Alert::SUCCESS
252
            );
253
        }
254
255
        $this->setPageType('form');
256
        $isOwner = false;
257
        $isEditing = ($this->_context[0] == 'edit');
258
        $canonical_link = null;
259
260
        if (isset($_POST['fields'])) {
261
            $author = $this->_Author;
262
        } elseif ($this->_context[0] == 'edit') {
263
            if (!$author_id = (int)$this->_context[1]) {
264
                redirect(SYMPHONY_URL . '/system/authors/');
265
            }
266
267
            if (!$author = AuthorManager::fetchByID($author_id)) {
268
                Administration::instance()->throwCustomError(
269
                    __('The author profile you requested does not exist.'),
270
                    __('Author not found'),
271
                    Page::HTTP_STATUS_NOT_FOUND
272
                );
273
            }
274
            $canonical_link = '/system/authors/edit/' . $author_id . '/';
275
        } else {
276
            $author = new Author();
277
        }
278
279
        if ($isEditing && $author->get('id') == Symphony::Author()->get('id')) {
280
            $isOwner = true;
281
        }
282
283
        if ($isEditing && !$isOwner && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
284
            Administration::instance()->throwCustomError(
285
                __('You are not authorised to edit other authors.'),
286
                __('Access Denied'),
287
                Page::HTTP_STATUS_FORBIDDEN
288
            );
289
        }
290
291
        $this->setTitle(__(($this->_context[0] == 'new' ? '%2$s &ndash; %3$s' : '%1$s &ndash; %2$s &ndash; %3$s'), array($author->getFullName(), __('Authors'), __('Symphony'))));
292
        if ($canonical_link) {
293
            $this->addElementToHead(new XMLElement('link', null, array(
294
                'rel' => 'canonical',
295
                'href' => SYMPHONY_URL . $canonical_link,
296
            )));
297
        }
298
        $this->appendSubheading(($this->_context[0] == 'new' ? __('Untitled') : $author->getFullName()));
299
        $this->insertBreadcrumbs(array(
300
            Widget::Anchor(__('Authors'), SYMPHONY_URL . '/system/authors/'),
301
        ));
302
303
        // Essentials
304
        $group = new XMLElement('fieldset');
305
        $group->setAttribute('class', 'settings');
306
        $group->appendChild(new XMLElement('legend', __('Essentials')));
307
308
        $div = new XMLElement('div');
309
        $div->setAttribute('class', 'two columns');
310
311
        $label = Widget::Label(__('First Name'), null, 'column');
312
        $label->appendChild(Widget::Input('fields[first_name]', $author->get('first_name')));
313
        $div->appendChild((isset($this->_errors['first_name']) ? Widget::Error($label, $this->_errors['first_name']) : $label));
314
315
316
        $label = Widget::Label(__('Last Name'), null, 'column');
317
        $label->appendChild(Widget::Input('fields[last_name]', $author->get('last_name')));
318
        $div->appendChild((isset($this->_errors['last_name']) ? Widget::Error($label, $this->_errors['last_name']) : $label));
319
320
        $group->appendChild($div);
321
322
        $label = Widget::Label(__('Email Address'));
323
        $label->appendChild(Widget::Input('fields[email]', $author->get('email'), 'text', array('autocomplete' => 'off')));
324
        $group->appendChild((isset($this->_errors['email']) ? Widget::Error($label, $this->_errors['email']) : $label));
325
326
        $this->Form->appendChild($group);
327
328
        // Login Details
329
        $group = new XMLElement('fieldset');
330
        $group->setAttribute('class', 'settings');
331
        $group->appendChild(new XMLElement('legend', __('Login Details')));
332
333
        $div = new XMLElement('div');
334
335
        $label = Widget::Label(__('Username'));
336
        $label->appendChild(Widget::Input('fields[username]', $author->get('username'), 'text', array('autocomplete' => 'off')));
337
        $div->appendChild((isset($this->_errors['username']) ? Widget::Error($label, $this->_errors['username']) : $label));
338
339
        // Only developers can change the user type. Primary account should NOT be able to change this
340
        if ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && !$author->isPrimaryAccount()) {
341
342
            // Create columns
343
            $div->setAttribute('class', 'two columns');
344
            $label->setAttribute('class', 'column');
345
346
            // User type
347
            $label = Widget::Label(__('User Type'), null, 'column');
348
349
            $options = array(
350
                array('author', false, __('Author')),
351
            );
352
353
            if (Symphony::Author()->isDeveloper() || ($isOwner && $author->isManager())) {
354
                $options[] = array('manager', $author->isManager(), __('Manager'));
355
            }
356
357
            if (Symphony::Author()->isDeveloper()) {
358
                $options[] = array('developer', $author->isDeveloper(), __('Developer'));
359
            }
360
361
            $label->appendChild(Widget::Select('fields[user_type]', $options));
362
            if (isset($this->_errors['user_type'])) {
363
                $div->appendChild(Widget::Error($label, $this->_errors['user_type']));
364
            } else {
365
                $div->appendChild($label);
366
            }
367
        }
368
369
        $group->appendChild($div);
370
371
        // Password
372
        $fieldset = new XMLElement('fieldset', null, array('class' => 'two columns', 'id' => 'password'));
373
        $legend = new XMLElement('legend', __('Password'));
374
        $help = new XMLElement('i', __('Leave password fields blank to keep the current password'));
375
        $fieldset->appendChild($legend);
376
        $fieldset->appendChild($help);
377
378
        /*
379
            Password reset rules:
380
            - Primary account can edit all accounts.
381
            - Developers can edit all developers, managers and authors, and their own.
382
            - Managers can edit all Authors, and their own.
383
            - Authors can edit their own.
384
        */
385
386
        $canEdit = // Managers can edit all Authors, and their own.
387
                (Symphony::Author()->isManager() && $author->isAuthor())
388
            // Primary account can edit all accounts.
389
            || Symphony::Author()->isPrimaryAccount()
390
            // Developers can edit all developers, managers and authors, and their own.
391
            || Symphony::Author()->isDeveloper() && $author->isPrimaryAccount() === false;
392
393
        // At this point, only developers, managers and owner are authorized
394
        // Make sure all users except developers needs to input the old password
395
        if ($isEditing && ($canEdit || $isOwner) && !Symphony::Author()->isDeveloper()) {
396
            $fieldset->setAttribute('class', 'three columns');
397
398
            $label = Widget::Label(null, null, 'column');
399
            $label->appendChild(Widget::Input('fields[old-password]', null, 'password', array('placeholder' => __('Old Password'), 'autocomplete' => 'off')));
400
            $fieldset->appendChild((isset($this->_errors['old-password']) ? Widget::Error($label, $this->_errors['old-password']) : $label));
401
        }
402
403
        // New password
404
        $placeholder = ($isEditing ? __('New Password') : __('Password'));
405
        $label = Widget::Label(null, null, 'column');
406
        $label->appendChild(Widget::Input('fields[password]', null, 'password', array('placeholder' => $placeholder, 'autocomplete' => 'off')));
407
        $fieldset->appendChild((isset($this->_errors['password']) ? Widget::Error($label, $this->_errors['password']) : $label));
408
409
        // Confirm password
410
        $label = Widget::Label(null, null, 'column');
411
        $label->appendChild(Widget::Input('fields[password-confirmation]', null, 'password', array('placeholder' => __('Confirm Password'), 'autocomplete' => 'off')));
412
        $fieldset->appendChild((isset($this->_errors['password-confirmation']) ? Widget::Error($label, $this->_errors['password']) : $label));
413
414
        $group->appendChild($fieldset);
415
416
        // Auth token
417
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager() || $isOwner) {
418
            $label = Widget::Label();
419
            $group->appendChild(Widget::Input('action[remote_login]', 'no', 'hidden'));
420
            $input = Widget::Input('action[remote_login]', 'yes', 'checkbox');
421
422
            if ($author->isTokenActive()) {
423
                $input->setAttribute('checked', 'checked');
424
                $tokenUrl = SYMPHONY_URL . '/login/' . $author->getAuthToken() . '/';
425
                $label->setValue(__('%s Remote login with the token %s is enabled.', [
426
                     $input->generate(),
427
                     '<a href="' . $tokenUrl . '">' . $author->getAuthToken() . '</a>',
428
                ]));
429
            } else {
430
                $label->setValue(__('%s Remote login is currently disabled.', [
431
                    $input->generate(),
432
                ]) . ' ' . __('Check the box to generate a new token.'));
433
            }
434
435
            $group->appendChild($label);
436
        }
437
438
        $label = Widget::Label(__('Default Area'));
439
440
        $sections = (new SectionManager)->select()->sort('sortorder')->execute()->rows();
441
442
        $options = array();
443
444
        // If the Author is the Developer, allow them to set the Default Area to
445
        // be the Sections Index.
446
        if ($author->isDeveloper()) {
447
            $options[] = array(
448
                '/blueprints/sections/',
449
                $author->get('default_area') == '/blueprints/sections/',
450
                __('Sections Index')
451
            );
452
        }
453
454
        if (is_array($sections) && !empty($sections)) {
455
            foreach ($sections as $s) {
456
                $options[] = array(
457
                    $s->get('id'),
458
                    $author->get('default_area') == $s->get('id'),
459
                    General::sanitize($s->get('name'))
460
                );
461
            }
462
        }
463
464
        /**
465
        * Allows injection or manipulation of the Default Area dropdown for an Author.
466
        * Take care with adding in options that are only valid for Developers, as if a
467
        * normal Author is set to that option, they will be redirected to their own
468
        * Author record.
469
        *
470
        *
471
        * @delegate AddDefaultAuthorAreas
472
        * @since Symphony 2.2
473
        * @param string $context
474
        * '/system/authors/'
475
        * @param array $options
476
        * An associative array of options, suitable for use for the Widget::Select
477
        * function. By default this will be an array of the Sections in the current
478
        * installation. New options should be the path to the page after the `SYMPHONY_URL`
479
        * constant.
480
        * @param string $default_area
481
        * The current `default_area` for this Author.
482
        * @param Author $author
483
        *  The Author object.
484
        *  This parameter is available @since Symphony 2.7.0
485
        */
486
        Symphony::ExtensionManager()->notifyMembers('AddDefaultAuthorAreas', '/system/authors/', array(
487
            'options' => &$options,
488
            'default_area' => $author->get('default_area'),
489
            'author' => $author,
490
        ));
491
492
        $label->appendChild(Widget::Select('fields[default_area]', $options));
493
        $group->appendChild($label);
494
495
        $this->Form->appendChild($group);
496
497
        // Custom Language Selection
498
        $languages = Lang::getAvailableLanguages();
499
        if (count($languages) > 1) {
500
            // Get language names
501
            asort($languages);
502
503
            $group = new XMLElement('fieldset');
504
            $group->setAttribute('class', 'settings');
505
            $group->appendChild(new XMLElement('legend', __('Custom Preferences')));
506
507
            $label = Widget::Label(__('Language'));
508
509
            $options = array(
510
                array(null, is_null($author->get('language')), __('System Default'))
511
            );
512
513
            foreach ($languages as $code => $name) {
514
                $options[] = array($code, $code == $author->get('language'), $name);
515
            }
516
            $select = Widget::Select('fields[language]', $options);
517
            $label->appendChild($select);
518
            $group->appendChild($label);
519
520
            $this->Form->appendChild($group);
521
        }
522
523
        // Administration password double check
524
        if ($isEditing && !$isOwner) {
525
            $group = new XMLElement('fieldset');
526
            $group->setAttribute('class', 'settings');
527
            $group->setAttribute('id', 'confirmation');
528
            $group->appendChild(new XMLElement('legend', __('Confirmation')));
529
            $group->appendChild(new XMLELement('p', __('Please confirm changes to this author with your password.'), array('class' => 'help')));
530
531
            $label = Widget::Label(__('Password'));
532
            $label->appendChild(Widget::Input('fields[confirm-change-password]', null, 'password', array(
533
                'autocomplete' => 'off',
534
                'placeholder' => __('Your Password')
535
            )));
536
            $group->appendChild(
537
                isset($this->_errors['confirm-change-password']) ? Widget::Error($label, $this->_errors['confirm-change-password']) : $label
538
            );
539
540
            $this->Form->appendChild($group);
541
        }
542
543
        // Actions
544
        $div = new XMLElement('div');
545
        $div->setAttribute('class', 'actions');
546
547
        $div->appendChild(Widget::Input('action[save]', ($this->_context[0] == 'edit' ? __('Save Changes') : __('Create Author')), 'submit', array('accesskey' => 's')));
548
549
        if ($isEditing && !$isOwner && !$author->isPrimaryAccount() && $canEdit) {
550
            $button = new XMLElement('button', __('Delete'));
551
            $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this author'), 'type' => 'submit', 'accesskey' => 'd', 'data-message' => __('Are you sure you want to delete this author?')));
552
            $div->appendChild($button);
553
        }
554
555
        $this->Form->appendChild($div);
556
557
        /**
558
        * Allows the injection of custom form fields given the current `$this->Form`
559
        * object. Please note that this custom data should be saved in own extension
560
        * tables and that modifying `tbl_authors` to house your data is highly discouraged.
561
        *
562
        * @delegate AddElementstoAuthorForm
563
        * @since Symphony 2.2
564
        * @param string $context
565
        * '/system/authors/'
566
        * @param XMLElement $form
567
        * The contents of `$this->Form` after all the default form elements have been appended.
568
        * @param Author $author
569
        * The current Author object that is being edited
570
        * @param array $fields
571
        *  The POST fields
572
        *  This parameter is available @since Symphony 2.7.0
573
        * @param array $errors
574
        *  The error array used to validate the Author.
575
        *  Extension should register their own errors elsewhere and used the value
576
        *  to modify the UI accordingly.
577
        *  This parameter is available @since Symphony 2.7.0
578
        */
579
        Symphony::ExtensionManager()->notifyMembers('AddElementstoAuthorForm', '/system/authors/', array(
580
            'form' => &$this->Form,
581
            'author' => $author,
582
            'fields' => $_POST['fields'],
583
            'errors' => $this->_errors,
584
        ));
585
    }
586
587
    public function __actionNew()
588
    {
589
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
590
            $fields = $_POST['fields'];
591
            $canCreate = Symphony::Author()->isDeveloper() || Symphony::Author()->isManager();
592
593
            if (!$canCreate) {
594
                Administration::instance()->throwCustomError(
595
                    __('You are not authorised to create authors.'),
596
                    __('Access Denied'),
597
                    Page::HTTP_STATUS_UNAUTHORIZED
598
                );
599
            }
600
601
            if (Symphony::Author()->isManager() && $fields['user_type'] !== 'author') {
602
                $this->_errors['user_type'] = __('The user type is invalid. You can only create Authors.');
603
            }
604
605
            $this->_Author = new Author();
606
            $this->_Author->set('user_type', $fields['user_type']);
607
            $this->_Author->set('primary', 'no');
608
            $this->_Author->set('email', $fields['email']);
609
            $this->_Author->set('username', General::sanitize($fields['username']));
610
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
611
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
612
            $this->_Author->set('last_seen', null);
613
            $this->_Author->set('password', (trim($fields['password']) == '' ? '' : Cryptography::hash($fields['password'])));
614
            $this->_Author->set('default_area', $fields['default_area']);
615
            if ($this->isRemoteLoginActionChecked() && !$this->_Author->isTokenActive()) {
616
                $this->_Author->set('auth_token', Cryptography::randomBytes());
617
            } elseif (!$this->isRemoteLoginActionChecked()) {
618
                $this->_Author->set('auth_token', null);
619
            }
620
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
621
622
            /**
623
             * Creation of a new Author. The Author object is provided as read
624
             * only through this delegate.
625
             *
626
             * @delegate AuthorPreCreate
627
             * @since Symphony 2.7.0
628
             * @param string $context
629
             * '/system/authors/'
630
             * @param Author $author
631
             *  The Author object that has just been created, but not yet committed, nor validated
632
             * @param array $fields
633
             *  The POST fields
634
             * @param array $errors
635
             *  The error array used to validate the Author, passed by reference.
636
             *  Extension should append to this array if they detect validation problems.
637
             */
638
            Symphony::ExtensionManager()->notifyMembers('AuthorPreCreate', '/system/authors/', array(
639
                'author' => $this->_Author,
640
                'field' => $fields,
641
                'errors' => &$this->_errors,
642
            ));
643
644
            if (empty($this->_errors) && $this->_Author->validate($this->_errors)) {
645
                if ($fields['password'] != $fields['password-confirmation']) {
646
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
647
                } elseif ($author_id = $this->_Author->commit()) {
648
                    /**
649
                     * Creation of a new Author. The Author object is provided as read
650
                     * only through this delegate.
651
                     *
652
                     * @delegate AuthorPostCreate
653
                     * @since Symphony 2.2
654
                     * @param string $context
655
                     * '/system/authors/'
656
                     * @param Author $author
657
                     *  The Author object that has just been created
658
                     * @param integer $author_id
659
                     *  The ID of Author ID that was just created
660
                     * @param array $fields
661
                     *  The POST fields
662
                     *  This parameter is available @since Symphony 2.7.0
663
                     * @param array $errors
664
                     *  The error array used to validate the Author, passed by reference.
665
                     *  Extension should append to this array if they detect saving problems.
666
                     *  This parameter is available @since Symphony 2.7.0
667
                     */
668
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostCreate', '/system/authors/', array(
669
                        'author' => $this->_Author,
670
                        'author_id' => $author_id,
671
                        'field' => $fields,
672
                        'errors' => &$this->_errors,
673
                    ));
674
675
                    if (empty($this->_errors)) {
676
                        redirect(SYMPHONY_URL . "/system/authors/edit/$author_id/created/");
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
677
                    }
678
                }
679
            }
680
681
            if (is_array($this->_errors) && !empty($this->_errors)) {
682
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
683
            } else {
684
                $this->pageAlert(
685
                    __('Unknown errors occurred while attempting to save.')
686
                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
687
                    . __('Check your activity log')
688
                    . '</a>.',
689
                    Alert::ERROR
690
                );
691
            }
692
        }
693
    }
694
695
    public function __actionEdit()
696
    {
697
        if (!$author_id = (int)$this->_context[1]) {
698
            redirect(SYMPHONY_URL . '/system/authors/');
0 ignored issues
show
Bug introduced by
The constant SYMPHONY_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
699
        }
700
701
        $isOwner = ($author_id == Symphony::Author()->get('id'));
702
        $fields = $_POST['fields'];
703
        $this->_Author = AuthorManager::fetchByID($author_id);
704
705
        $canEdit = // Managers can edit all Authors, and their own.
706
                (Symphony::Author()->isManager() && $this->_Author->isAuthor())
0 ignored issues
show
Bug introduced by
The method isAuthor() does not exist on null. ( Ignorable by Annotation )

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

706
                (Symphony::Author()->isManager() && $this->_Author->/** @scrutinizer ignore-call */ isAuthor())

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
707
                // Primary account can edit all accounts.
708
                || Symphony::Author()->isPrimaryAccount()
709
                // Developers can edit all developers, managers and authors, and their own,
710
                // but not the primary account
711
                || (Symphony::Author()->isDeveloper() && $this->_Author->isPrimaryAccount() === false);
712
713
        if (!$isOwner && !$canEdit) {
714
            Administration::instance()->throwCustomError(
715
                __('You are not authorised to modify this author.'),
716
                __('Access Denied'),
717
                Page::HTTP_STATUS_UNAUTHORIZED
718
            );
719
        }
720
721
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
722
            $authenticated = $changing_password = $changing_email = false;
723
724
            if ($fields['email'] != $this->_Author->get('email')) {
725
                $changing_email = true;
726
            }
727
728
            // Check the old password was correct
729
            if (isset($fields['old-password']) && strlen(trim($fields['old-password'])) > 0 && Cryptography::compare(trim($fields['old-password']), $this->_Author->get('password'))) {
730
                $authenticated = true;
731
732
                // Developers don't need to specify the old password, unless it's their own account
733
            } elseif (
734
                // All accounts can edit their own
735
                $isOwner ||
736
                // Is allowed to edit?
737
                $canEdit
738
            ) {
739
                $authenticated = true;
740
            }
741
742
            $this->_Author->set('id', $author_id);
743
744
            if ($this->_Author->isPrimaryAccount() || ($isOwner && Symphony::Author()->isDeveloper())) {
745
                $this->_Author->set('user_type', 'developer'); // Primary accounts are always developer, Developers can't lower their level
746
            } elseif (Symphony::Author()->isManager() && isset($fields['user_type'])) { // Manager can only change user type for author and managers
747
                if ($fields['user_type'] !== 'author' && $fields['user_type'] !== 'manager') {
748
                    $this->_errors['user_type'] = __('The user type is invalid. You can only create Authors.');
749
                } else {
750
                    $this->_Author->set('user_type', $fields['user_type']);
751
                }
752
            } elseif (Symphony::Author()->isDeveloper() && isset($fields['user_type'])) {
753
                $this->_Author->set('user_type', $fields['user_type']); // Only developer can change user type
754
            }
755
756
            $this->_Author->set('email', $fields['email']);
757
            $this->_Author->set('username', General::sanitize($fields['username']));
758
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
759
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
760
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
761
762
            if (trim($fields['password']) != '') {
763
                $this->_Author->set('password', Cryptography::hash($fields['password']));
764
                $changing_password = true;
765
            }
766
767
            // Don't allow authors to set the Section Index as a default area
768
            // If they had it previously set, just save `null` which will redirect
769
            // the Author (when logging in) to their own Author record
770
            if (
771
                $this->_Author->get('user_type') == 'author'
772
                && $fields['default_area'] == '/blueprints/sections/'
773
            ) {
774
                $this->_Author->set('default_area', null);
775
            } else {
776
                $this->_Author->set('default_area', $fields['default_area']);
777
            }
778
779
            if ($authenticated && $this->isRemoteLoginActionChecked() && !$this->_Author->isTokenActive()) {
780
                $this->_Author->set('auth_token', Cryptography::randomBytes());
781
            } elseif (!$this->isRemoteLoginActionChecked()) {
782
                $this->_Author->set('auth_token', null);
783
            }
784
785
            /**
786
             * Before editing an author, provided with the Author object
787
             *
788
             * @delegate AuthorPreEdit
789
             * @since Symphony 2.7.0
790
             * @param string $context
791
             * '/system/authors/'
792
             * @param Author $author
793
             * An Author object not yet committed, nor validated
794
             * @param array $fields
795
             *  The POST fields
796
             * @param array $errors
797
             *  The error array used to validate the Author, passed by reference.
798
             *  Extension should append to this array if they detect validation problems.
799
             * @param bool $changing_email
800
             *  @since Symphony 3.0.0
801
             *  The changing email flag, so extension can act only if the email changes.
802
             * @param bool $changing_password
803
             *  @since Symphony 3.0.0
804
             *  The changing password flag, so extension can act only if the password changes.
805
             */
806
            Symphony::ExtensionManager()->notifyMembers('AuthorPreEdit', '/system/authors/', array(
807
                'author' => $this->_Author,
808
                'field' => $fields,
809
                'errors' => &$this->_errors,
810
                'changing_email' => $changing_email,
811
                'changing_password' => $changing_password,
812
            ));
813
814
            if (empty($this->_errors) && $this->_Author->validate($this->_errors)) {
815
                // Admin changing another profile
816
                if (!$isOwner) {
817
                    $entered_password = $fields['confirm-change-password'];
818
819
                    if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
820
                        $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
821
                    } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
822
                        $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
823
                    }
824
                }
825
826
                // Author is changing their password
827
                if (!$authenticated && ($changing_password || $changing_email)) {
828
                    if ($changing_password) {
829
                        $this->_errors['old-password'] = __('Wrong password. Enter old password to change it.');
830
                    } elseif ($changing_email) {
831
                        $this->_errors['old-password'] = __('Wrong password. Enter old one to change email address.');
832
                    }
833
834
                    // Passwords provided, but doesn't match.
835
                } elseif (($fields['password'] != '' || $fields['password-confirmation'] != '') && $fields['password'] != $fields['password-confirmation']) {
836
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
837
                }
838
839
                // All good, let's save the Author
840
                if (is_array($this->_errors) && empty($this->_errors) && $this->_Author->commit()) {
841
                    Symphony::Database()
0 ignored issues
show
Deprecated Code introduced by
The function Database::delete() has been deprecated: Symphony 3.0.0 This parameter is deprecated and will be removed. Use DatabaseDelete::where() ( Ignorable by Annotation )

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

841
                    /** @scrutinizer ignore-deprecated */ Symphony::Database()

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...
842
                        ->delete('tbl_forgotpass')
843
                        ->where(['or' => [
844
                            'expiry' => ['<' => DateTimeObj::getGMT('c')],
845
                            'author_id' => $author_id,
846
                        ]])
847
                        ->execute();
848
849
                    if ($isOwner) {
850
                        Administration::instance()->login($this->_Author->get('username'), $this->_Author->get('password'), true);
851
                    }
852
853
                    /**
854
                     * After editing an author, provided with the Author object
855
                     *
856
                     * @delegate AuthorPostEdit
857
                     * @since Symphony 2.2
858
                     * @param string $context
859
                     * '/system/authors/'
860
                     * @param Author $author
861
                     * An Author object
862
                     * @param array $fields
863
                     *  The POST fields
864
                     *  This parameter is available @since Symphony 2.7.0
865
                     * @param array $errors
866
                     *  The error array used to validate the Author, passed by reference.
867
                     *  Extension should append to this array if they detect saving problems.
868
                     *  This parameter is available @since Symphony 2.7.0
869
                     * @param bool $changing_email
870
                     *  @since Symphony 3.0.0
871
                     *  The changing email flag, so extension can act only if the email changes.
872
                     * @param bool $changing_password
873
                     *  @since Symphony 3.0.0
874
                     *  The changing password flag, so extension can act only if the password changes.
875
                     */
876
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostEdit', '/system/authors/', array(
877
                        'author' => $this->_Author,
878
                        'field' => $fields,
879
                        'errors' => &$this->_errors,
880
                        'changing_email' => $changing_email,
881
                        'changing_password' => $changing_password,
882
                    ));
883
884
                    if (empty($this->_errors)) {
885
                        redirect(SYMPHONY_URL . '/system/authors/edit/' . $author_id . '/saved/');
886
                    }
887
888
                    // Problems.
889
                } else {
890
                    $this->pageAlert(
891
                        __('Unknown errors occurred while attempting to save.')
892
                        . '<a href="' . SYMPHONY_URL . '/system/log/">'
893
                        . __('Check your activity log')
894
                        . '</a>.',
895
                        Alert::ERROR
896
                    );
897
                }
898
            }
899
900
            // Author doesn't have valid data, throw back.
901
            if (is_array($this->_errors) && !empty($this->_errors)) {
902
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
903
            }
904
        } elseif (@array_key_exists('delete', $_POST['action'])) {
905
            // Validate rights
906
            if (!$canEdit) {
907
                $this->pageAlert(__('You are not allowed to delete this author.'), Alert::ERROR);
908
                return;
909
            }
910
            // Admin changing another profile
911
            if (!$isOwner) {
912
                $entered_password = $fields['confirm-change-password'];
913
914
                if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
915
                    $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
916
                } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
917
                    $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
918
                }
919
            }
920
            if (is_array($this->_errors) && !empty($this->_errors)) {
921
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
922
                return;
923
            }
924
925
            $this->_Author = AuthorManager::fetchByID($author_id);
926
927
            /**
928
             * Prior to deleting an author, provided with the Author ID.
929
             *
930
             * @delegate AuthorPreDelete
931
             * @since Symphony 2.2
932
             * @param string $context
933
             * '/system/authors/'
934
             * @param integer $author_id
935
             *  The ID of Author ID that is about to be deleted
936
             * @param Author $author
937
             *  The Author object.
938
             *  This parameter is available @since Symphony 2.7.0
939
             */
940
            Symphony::ExtensionManager()->notifyMembers('AuthorPreDelete', '/system/authors/', array(
941
                'author_id' => $author_id,
942
                'author' => $this->_Author,
943
            ));
944
945
            if (!$isOwner) {
946
                $result = AuthorManager::delete($author_id);
947
948
                /**
949
                 * After deleting an author, provided with the Author ID.
950
                 *
951
                 * @delegate AuthorPostDelete
952
                 * @since Symphony 2.7.0
953
                 * @param string $context
954
                 * '/system/authors/'
955
                 * @param integer $author_id
956
                 *  The ID of Author ID that is about to be deleted
957
                 * @param Author $author
958
                 *  The Author object.
959
                 * @param integer $result
960
                 *  The result of the delete statement
961
                 */
962
                Symphony::ExtensionManager()->notifyMembers('AuthorPostDelete', '/system/authors/', array(
963
                    'author_id' => $author_id,
964
                    'author' => $this->_Author,
965
                    'result' => $result
966
                ));
967
968
                redirect(SYMPHONY_URL . '/system/authors/');
969
            } else {
970
                $this->pageAlert(__('You cannot remove yourself as you are the active Author.'), Alert::ERROR);
971
            }
972
        }
973
    }
974
}
975