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 — master (#2835)
by
unknown
06:01
created

contentSystemAuthors::__actionEdit()   F

Complexity

Conditions 64
Paths > 20000

Size

Total Lines 276
Code Lines 124

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
cc 64
eloc 124
c 7
b 0
f 0
nc 2036552
nop 0
dl 0
loc 276
rs 2

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 is_array($_POST['action']) &&
35
            array_key_exists('remote_login', $_POST['action']) &&
36
            $_POST['action']['remote_login'] === 'yes';
37
    }
38
39
    public function __viewIndex()
40
    {
41
        $this->setPageType('table');
42
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Authors'), __('Symphony'))));
43
44
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
45
            $this->appendSubheading(__('Authors'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new author'), 'create button', null, array('accesskey' => 'c')));
46
        } else {
47
            $this->appendSubheading(__('Authors'));
48
        }
49
50
        Sortable::initialize($this, $authors, $sort, $order);
51
52
        $columns = array(
53
            array(
54
                'label' => __('Name'),
55
                'sortable' => true,
56
                'handle' => 'name'
57
            ),
58
            array(
59
                'label' => __('Email Address'),
60
                'sortable' => true,
61
                'handle' => 'email'
62
            ),
63
            array(
64
                'label' => __('Last Seen'),
65
                'sortable' => true,
66
                'handle' => 'last_seen'
67
            )
68
        );
69
70
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
71
            $columns = array_merge($columns, array(
72
                array(
73
                    'label' => __('User Type'),
74
                    'sortable' => true,
75
                    'handle' => 'user_type'
76
                ),
77
                array(
78
                    'label' => __('Language'),
79
                    'sortable' => true,
80
                    'handle' => 'language'
81
                )
82
            ));
83
        }
84
85
        /**
86
         * Allows the creation of custom table columns for each author. Called
87
         * after all the table headers columns have been added.
88
         *
89
         * @delegate AddCustomAuthorColumn
90
         * @since Symphony 2.7.0
91
         * @param string $context
92
         * '/system/authors/'
93
         * @param array $columns
94
         * An array of the current columns, passed by reference
95
         * @param string $sort
96
         *  @since Symphony 3.0.0
97
         *  The sort field
98
         * @param string $order
99
         *  @since Symphony 3.0.0
100
         *  The sort order
101
         */
102
        Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumn', '/system/authors/', array(
103
            'columns' => &$columns,
104
            'sort' => $sort,
105
            'order' => $order,
106
        ));
107
108
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
109
110
        $aTableBody = array();
111
112
        if (!is_array($authors) || empty($authors)) {
113
            $aTableBody = array(
114
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
115
            );
116
        } else {
117
            foreach ($authors as $a) {
118
                // Setup each cell
119
                if (
120
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper() && !$a->isManager()))
121
                    || Symphony::Author()->get('id') == $a->get('id')
122
                ) {
123
                    $td1 = Widget::TableData(
124
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
125
                    );
126
                } else {
127
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
128
                }
129
130
                // Can this Author be edited by the current Author?
131
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
132
                    if ($a->get('id') != Symphony::Author()->get('id')) {
133
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
134
                            'for' => 'author-' . $a->get('id')
135
                        )));
136
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
137
                            'id' => 'author-' . $a->get('id')
138
                        )));
139
                    }
140
                }
141
142
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
143
144
                if (!is_null($a->get('last_seen'))) {
145
                    $td3 = Widget::TableData(
146
                        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

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

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

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