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
Push — 3.0.x ( 74e535...484b00 )
by Nicolas
03:47
created

contentSystemAuthors::__actionNew()   F

Complexity

Conditions 19
Paths 241

Size

Total Lines 103
Code Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 19
eloc 49
nc 241
nop 0
dl 0
loc 103
rs 3.8011
c 2
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 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
         */
96
        Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumn', '/system/authors/', array(
97
            'columns' => &$columns,
98
        ));
99
100
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
101
102
        $aTableBody = array();
103
104
        if (!is_array($authors) || empty($authors)) {
105
            $aTableBody = array(
106
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
107
            );
108
        } else {
109
            foreach ($authors as $a) {
110
                // Setup each cell
111
                if (
112
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper() && !$a->isManager()))
113
                    || Symphony::Author()->get('id') == $a->get('id')
114
                ) {
115
                    $td1 = Widget::TableData(
116
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
117
                    );
118
                } else {
119
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
120
                }
121
122
                // Can this Author be edited by the current Author?
123
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
124
                    if ($a->get('id') != Symphony::Author()->get('id')) {
125
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
126
                            'for' => 'author-' . $a->get('id')
127
                        )));
128
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
129
                            'id' => 'author-' . $a->get('id')
130
                        )));
131
                    }
132
                }
133
134
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
135
136
                if (!is_null($a->get('last_seen'))) {
137
                    $td3 = Widget::TableData(
138
                        DateTimeObj::format($a->get('last_seen'), __SYM_DATETIME_FORMAT__)
0 ignored issues
show
Bug introduced by
The constant __SYM_DATETIME_FORMAT__ was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
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

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

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

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