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.
Completed
Push — master ( 4ccb09...2f9dc2 )
by Nicolas
03:16
created

contentSystemAuthors::__actionIndex()   C

Complexity

Conditions 8
Paths 10

Size

Total Lines 47
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 12
c 0
b 0
f 0
nc 10
nop 0
dl 0
loc 47
rs 5.7377

1 Method

Rating   Name   Duplication   Size   Complexity  
A contentSystemAuthors::__viewNew() 0 4 1
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)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
19
    {
20
        if (is_null($sort) || $sort == 'name') {
21
            return AuthorManager::fetch("first_name $order,  last_name", $order);
22
        } else {
23
            $sort = General::sanitize($sort);
24
        }
25
26
        return AuthorManager::fetch($sort, $order);
27
    }
28
29
    public function __viewIndex()
30
    {
31
        $this->setPageType('table');
32
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Authors'), __('Symphony'))));
33
34
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
35
            $this->appendSubheading(__('Authors'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new author'), 'create button', null, array('accesskey' => 'c')));
36
        } else {
37
            $this->appendSubheading(__('Authors'));
38
        }
39
40
        Sortable::initialize($this, $authors, $sort, $order);
41
42
        $columns = array(
43
            array(
44
                'label' => __('Name'),
45
                'sortable' => true,
46
                'handle' => 'name'
47
            ),
48
            array(
49
                'label' => __('Email Address'),
50
                'sortable' => true,
51
                'handle' => 'email'
52
            ),
53
            array(
54
                'label' => __('Last Seen'),
55
                'sortable' => true,
56
                'handle' => 'last_seen'
57
            )
58
        );
59
60
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
61
            $columns = array_merge($columns, array(
62
                array(
63
                    'label' => __('User Type'),
64
                    'sortable' => true,
65
                    'handle' => 'user_type'
66
                ),
67
                array(
68
                    'label' => __('Language'),
69
                    'sortable' => true,
70
                    'handle' => 'language'
71
                )
72
            ));
73
        }
74
75
        /**
76
         * Allows the creation of custom table columns for each author. Called
77
         * after all the table headers columns have been added.
78
         *
79
         * @delegate AddCustomAuthorColumn
80
         * @since Symphony 2.7.0
81
         * @param string $context
82
         * '/system/authors/'
83
         * @param array $columns
84
         * An array of the current columns, passed by reference
85
         */
86
        Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumn', '/system/authors/', array(
87
            'columns' => &$columns,
88
        ));
89
90
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
91
92
        $aTableBody = array();
93
94
        if (!is_array($authors) || empty($authors)) {
95
            $aTableBody = array(
96
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
97
            );
98
        } else {
99
            foreach ($authors as $a) {
100
                // Setup each cell
101
                if (
102
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper()))
103
                    || Symphony::Author()->get('id') == $a->get('id')
104
                ) {
105
                    $td1 = Widget::TableData(
106
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
107
                    );
108
                } else {
109
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
110
                }
111
112
                // Can this Author be edited by the current Author?
113
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
114
                    if ($a->get('id') != Symphony::Author()->get('id')) {
115
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
116
                            'for' => 'author-' . $a->get('id')
117
                        )));
118
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
119
                            'id' => 'author-' . $a->get('id')
120
                        )));
121
                    }
122
                }
123
124
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
125
126
                if (!is_null($a->get('last_seen'))) {
127
                    $td3 = Widget::TableData(
128
                        DateTimeObj::format($a->get('last_seen'), __SYM_DATETIME_FORMAT__)
0 ignored issues
show
Security Bug introduced by
It seems like \DateTimeObj::format($a-..._SYM_DATETIME_FORMAT__) targeting DateTimeObj::format() can also be of type false; however, Widget::TableData() does only seem to accept object<XMLElement>|string, did you maybe forget to handle an error condition?
Loading history...
129
                    );
130
                } else {
131
                    $td3 = Widget::TableData(__('Unknown'), 'inactive');
132
                }
133
134
                if ($a->isDeveloper()) {
135
                    $type = 'Developer';
136
                } elseif ($a->isManager()) {
137
                    $type = 'Manager';
138
                } else {
139
                    $type = 'Author';
140
                }
141
142
                $td4 = Widget::TableData(__($type));
143
144
                $languages = Lang::getAvailableLanguages();
145
146
                $td5 = Widget::TableData($a->get("language") == null ? __("System Default") : $languages[$a->get("language")]);
147
148
                $tableData = array();
0 ignored issues
show
Unused Code introduced by
$tableData is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
149
                // Add a row to the body array, assigning each cell to the row
150
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
151
                    $tableData = array($td1, $td2, $td3, $td4, $td5);
152
                } else {
153
                    $tableData = array($td1, $td2, $td3);
154
                }
155
156
                /**
157
                 * Allows Extensions to inject custom table data for each Author
158
                 * into the Authors Index
159
                 *
160
                 * @delegate AddCustomAuthorColumnData
161
                 * @since Symphony 2.7.0
162
                 * @param string $context
163
                 * '/system/authors/'
164
                 * @param array $tableData
165
                 *  An array of `Widget::TableData`, passed by reference
166
                 * @param array $columns
167
                 * An array of the current columns
168
                 * @param Author $author
169
                 *  The Author object.
170
                 */
171
                Symphony::ExtensionManager()->notifyMembers('AddCustomAuthorColumnData', '/system/authors/', array(
172
                    'tableData' => &$tableData,
173
                    'columns' => $columns,
174
                    'author' => $a,
175
                ));
176
177
                $aTableBody[] = Widget::TableRow($tableData);
178
            }
179
        }
180
181
        $table = Widget::Table(
182
            Widget::TableHead($aTableHead),
183
            null,
184
            Widget::TableBody($aTableBody),
185
            'selectable',
186
            null,
187
            array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading')
188
        );
189
190
        $this->Form->appendChild($table);
191
192
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
193
            'id' => 'version'
194
        ));
195
196
        $this->Form->appendChild($version);
197
    }
198
199
    // Both the Edit and New pages need the same form
200
    public function __viewNew()
201
    {
202
        $this->__form();
203
    }
204
205
    public function __viewEdit()
206
    {
207
        $this->__form();
208
    }
209
210
    public function __form()
211
    {
212
        // Handle unknown context
213
        if (!in_array($this->_context[0], array('new', 'edit'))) {
214
            Administration::instance()->errorPageNotFound();
215
        }
216
217
        if ($this->_context[0] == 'new' && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
218
            Administration::instance()->throwCustomError(
219
                __('You are not authorised to access this page.'),
220
                __('Access Denied'),
221
                Page::HTTP_STATUS_UNAUTHORIZED
222
            );
223
        }
224
225
        if (isset($this->_context[2])) {
226
            $time = Widget::Time();
227
228
            switch ($this->_context[2]) {
229
                case 'saved':
230
                    $message = __('Author updated at %s.', array($time->generate()));
231
                    break;
232
                case 'created':
233
                    $message = __('Author created at %s.', array($time->generate()));
234
            }
235
236
            $this->pageAlert(
237
                $message
0 ignored issues
show
Bug introduced by
The variable $message does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
238
                . ' <a href="' . SYMPHONY_URL . '/system/authors/new/" accesskey="c">'
239
                . __('Create another?')
240
                . '</a> <a href="' . SYMPHONY_URL . '/system/authors/" accesskey="a">'
241
                . __('View all Authors')
242
                . '</a>',
243
                Alert::SUCCESS
244
            );
245
        }
246
247
        $this->setPageType('form');
248
        $isOwner = false;
249
        $isEditing = ($this->_context[0] == 'edit');
250
        $canonical_link = null;
251
252
        if (isset($_POST['fields'])) {
253
            $author = $this->_Author;
254
        } elseif ($this->_context[0] == 'edit') {
255
            if (!$author_id = (int)$this->_context[1]) {
256
                redirect(SYMPHONY_URL . '/system/authors/');
257
            }
258
259
            if (!$author = AuthorManager::fetchByID($author_id)) {
260
                Administration::instance()->throwCustomError(
261
                    __('The author profile you requested does not exist.'),
262
                    __('Author not found'),
263
                    Page::HTTP_STATUS_NOT_FOUND
264
                );
265
            }
266
            $canonical_link = '/system/authors/edit/' . $author_id . '/';
267
        } else {
268
            $author = new Author();
269
        }
270
271
        if ($isEditing && $author->get('id') == Symphony::Author()->get('id')) {
272
            $isOwner = true;
273
        }
274
275
        if ($isEditing && !$isOwner && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
276
            Administration::instance()->throwCustomError(
277
                __('You are not authorised to edit other authors.'),
278
                __('Access Denied'),
279
                Page::HTTP_STATUS_FORBIDDEN
280
            );
281
        }
282
283
        $this->setTitle(__(($this->_context[0] == 'new' ? '%2$s &ndash; %3$s' : '%1$s &ndash; %2$s &ndash; %3$s'), array($author->getFullName(), __('Authors'), __('Symphony'))));
284 View Code Duplication
        if ($canonical_link) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $canonical_link of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
285
            $this->addElementToHead(new XMLElement('link', null, array(
286
                'rel' => 'canonical',
287
                'href' => SYMPHONY_URL . $canonical_link,
288
            )));
289
        }
290
        $this->appendSubheading(($this->_context[0] == 'new' ? __('Untitled') : $author->getFullName()));
291
        $this->insertBreadcrumbs(array(
292
            Widget::Anchor(__('Authors'), SYMPHONY_URL . '/system/authors/'),
293
        ));
294
295
        // Essentials
296
        $group = new XMLElement('fieldset');
297
        $group->setAttribute('class', 'settings');
298
        $group->appendChild(new XMLElement('legend', __('Essentials')));
299
300
        $div = new XMLElement('div');
301
        $div->setAttribute('class', 'two columns');
302
303
        $label = Widget::Label(__('First Name'), null, 'column');
304
        $label->appendChild(Widget::Input('fields[first_name]', $author->get('first_name')));
305
        $div->appendChild((isset($this->_errors['first_name']) ? Widget::Error($label, $this->_errors['first_name']) : $label));
306
307
308
        $label = Widget::Label(__('Last Name'), null, 'column');
309
        $label->appendChild(Widget::Input('fields[last_name]', $author->get('last_name')));
310
        $div->appendChild((isset($this->_errors['last_name']) ? Widget::Error($label, $this->_errors['last_name']) : $label));
311
312
        $group->appendChild($div);
313
314
        $label = Widget::Label(__('Email Address'));
315
        $label->appendChild(Widget::Input('fields[email]', $author->get('email'), 'text', array('autocomplete' => 'off')));
316
        $group->appendChild((isset($this->_errors['email']) ? Widget::Error($label, $this->_errors['email']) : $label));
317
318
        $this->Form->appendChild($group);
319
320
        // Login Details
321
        $group = new XMLElement('fieldset');
322
        $group->setAttribute('class', 'settings');
323
        $group->appendChild(new XMLElement('legend', __('Login Details')));
324
325
        $div = new XMLElement('div');
326
327
        $label = Widget::Label(__('Username'));
328
        $label->appendChild(Widget::Input('fields[username]', $author->get('username'), 'text', array('autocomplete' => 'off')));
329
        $div->appendChild((isset($this->_errors['username']) ? Widget::Error($label, $this->_errors['username']) : $label));
330
331
        // Only developers can change the user type. Primary account should NOT be able to change this
332
        if ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && !$author->isPrimaryAccount()) {
333
334
            // Create columns
335
            $div->setAttribute('class', 'two columns');
336
            $label->setAttribute('class', 'column');
337
338
            // User type
339
            $label = Widget::Label(__('User Type'), null, 'column');
340
341
            $options = array(
342
                array('author', false, __('Author')),
343
                array('manager', $author->isManager(), __('Manager'))
344
            );
345
346
            if (Symphony::Author()->isDeveloper()) {
347
                $options[] = array('developer', $author->isDeveloper(), __('Developer'));
348
            }
349
350
            $label->appendChild(Widget::Select('fields[user_type]', $options));
351
            $div->appendChild($label);
352
        }
353
354
        $group->appendChild($div);
355
356
        // Password
357
        $fieldset = new XMLElement('fieldset', null, array('class' => 'two columns', 'id' => 'password'));
358
        $legend = new XMLElement('legend', __('Password'));
359
        $help = new XMLElement('i', __('Leave password fields blank to keep the current password'));
360
        $fieldset->appendChild($legend);
361
        $fieldset->appendChild($help);
362
363
        /*
364
            Password reset rules:
365
            - Primary account can edit all accounts.
366
            - Developers can edit all developers, managers and authors, and their own.
367
            - Managers can edit all Authors, and their own.
368
            - Authors can edit their own.
369
        */
370
        if ($isEditing && !(
371
            // All accounts can edit their own
372
            $isOwner
373
            // Managers can edit all Authors, and their own.
374
            || (Symphony::Author()->isManager() && $author->isAuthor())
375
            // Primary account can edit all accounts.
376
            || Symphony::Author()->isPrimaryAccount()
377
            // Developers can edit all developers, managers and authors, and their own.
378
            || Symphony::Author()->isDeveloper() && $author->isPrimaryAccount() === false
379
        )) {
380
            $fieldset->setAttribute('class', 'three columns');
381
382
            $label = Widget::Label(null, null, 'column');
383
            $label->appendChild(Widget::Input('fields[old-password]', null, 'password', array('placeholder' => __('Old Password'), 'autocomplete' => 'off')));
384
            $fieldset->appendChild((isset($this->_errors['old-password']) ? Widget::Error($label, $this->_errors['old-password']) : $label));
385
        }
386
387
        // New password
388
        $placeholder = ($isEditing ? __('New Password') : __('Password'));
389
        $label = Widget::Label(null, null, 'column');
390
        $label->appendChild(Widget::Input('fields[password]', null, 'password', array('placeholder' => $placeholder, 'autocomplete' => 'off')));
391
        $fieldset->appendChild((isset($this->_errors['password']) ? Widget::Error($label, $this->_errors['password']) : $label));
392
393
        // Confirm password
394
        $label = Widget::Label(null, null, 'column');
395
        $label->appendChild(Widget::Input('fields[password-confirmation]', null, 'password', array('placeholder' => __('Confirm Password'), 'autocomplete' => 'off')));
396
        $fieldset->appendChild((isset($this->_errors['password-confirmation']) ? Widget::Error($label, $this->_errors['password']) : $label));
397
398
        $group->appendChild($fieldset);
399
400
        // Auth token
401
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
402
            $label = Widget::Label();
403
            $group->appendChild(Widget::Input('fields[auth_token_active]', 'no', 'hidden'));
404
            $input = Widget::Input('fields[auth_token_active]', 'yes', 'checkbox');
405
406
            if ($author->isTokenActive()) {
407
                $input->setAttribute('checked', 'checked');
408
            }
409
410
            $temp = SYMPHONY_URL . '/login/' . $author->createAuthToken() . '/';
411
            $label->setValue(__('%s Allow remote login via', array($input->generate())) . ' <a href="' . $temp . '">' . $temp . '</a>');
412
            $group->appendChild($label);
413
        }
414
415
        $label = Widget::Label(__('Default Area'));
416
417
        $sections = SectionManager::fetch(null, 'ASC', 'sortorder');
418
419
        $options = array();
420
421
        // If the Author is the Developer, allow them to set the Default Area to
422
        // be the Sections Index.
423
        if ($author->isDeveloper()) {
424
            $options[] = array(
425
                '/blueprints/sections/',
426
                $author->get('default_area') == '/blueprints/sections/',
427
                __('Sections Index')
428
            );
429
        }
430
431
        if (is_array($sections) && !empty($sections)) {
432 View Code Duplication
            foreach ($sections as $s) {
433
                $options[] = array(
434
                    $s->get('id'),
435
                    $author->get('default_area') == $s->get('id'),
436
                    General::sanitize($s->get('name'))
437
                );
438
            }
439
        }
440
441
        /**
442
        * Allows injection or manipulation of the Default Area dropdown for an Author.
443
        * Take care with adding in options that are only valid for Developers, as if a
444
        * normal Author is set to that option, they will be redirected to their own
445
        * Author record.
446
        *
447
        *
448
        * @delegate AddDefaultAuthorAreas
449
        * @since Symphony 2.2
450
        * @param string $context
451
        * '/system/authors/'
452
        * @param array $options
453
        * An associative array of options, suitable for use for the Widget::Select
454
        * function. By default this will be an array of the Sections in the current
455
        * installation. New options should be the path to the page after the `SYMPHONY_URL`
456
        * constant.
457
        * @param string $default_area
458
        * The current `default_area` for this Author.
459
        * @param Author $author
460
        *  The Author object.
461
        *  This parameter is available @since Symphony 2.7.0
462
        */
463
        Symphony::ExtensionManager()->notifyMembers('AddDefaultAuthorAreas', '/system/authors/', array(
464
            'options' => &$options,
465
            'default_area' => $author->get('default_area'),
466
            'author' => $author,
467
        ));
468
469
        $label->appendChild(Widget::Select('fields[default_area]', $options));
470
        $group->appendChild($label);
471
472
        $this->Form->appendChild($group);
473
474
        // Custom Language Selection
475
        $languages = Lang::getAvailableLanguages();
476
        if (count($languages) > 1) {
477
            // Get language names
478
            asort($languages);
479
480
            $group = new XMLElement('fieldset');
481
            $group->setAttribute('class', 'settings');
482
            $group->appendChild(new XMLElement('legend', __('Custom Preferences')));
483
484
            $label = Widget::Label(__('Language'));
485
486
            $options = array(
487
                array(null, is_null($author->get('language')), __('System Default'))
488
            );
489
490
            foreach ($languages as $code => $name) {
491
                $options[] = array($code, $code == $author->get('language'), $name);
492
            }
493
            $select = Widget::Select('fields[language]', $options);
494
            $label->appendChild($select);
495
            $group->appendChild($label);
496
497
            $this->Form->appendChild($group);
498
        }
499
500
        // Administration password double check
501
        if ($isEditing && !$isOwner) {
502
            $group = new XMLElement('fieldset');
503
            $group->setAttribute('class', 'settings');
504
            $group->setAttribute('id', 'confirmation');
505
            $group->appendChild(new XMLElement('legend', __('Confirmation')));
506
            $group->appendChild(new XMLELement('p', __('Please confirm changes to this author with your password.'), array('class' => 'help')));
507
508
            $label = Widget::Label(__('Password'));
509
            $label->appendChild(Widget::Input('fields[confirm-change-password]', null, 'password', array(
510
                'autocomplete' => 'off',
511
                'placeholder' => __('Your Password')
512
            )));
513
            $group->appendChild(
514
                isset($this->_errors['confirm-change-password']) ? Widget::Error($label, $this->_errors['confirm-change-password']) : $label
515
            );
516
517
            $this->Form->appendChild($group);
518
        }
519
520
        // Actions
521
        $div = new XMLElement('div');
522
        $div->setAttribute('class', 'actions');
523
524
        $div->appendChild(Widget::Input('action[save]', ($this->_context[0] == 'edit' ? __('Save Changes') : __('Create Author')), 'submit', array('accesskey' => 's')));
525
526
        if ($isEditing && !$isOwner && !$author->isPrimaryAccount()) {
527
            $button = new XMLElement('button', __('Delete'));
528
            $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?')));
529
            $div->appendChild($button);
530
        }
531
532
        $this->Form->appendChild($div);
533
534
        /**
535
        * Allows the injection of custom form fields given the current `$this->Form`
536
        * object. Please note that this custom data should be saved in own extension
537
        * tables and that modifying `tbl_authors` to house your data is highly discouraged.
538
        *
539
        * @delegate AddElementstoAuthorForm
540
        * @since Symphony 2.2
541
        * @param string $context
542
        * '/system/authors/'
543
        * @param XMLElement $form
544
        * The contents of `$this->Form` after all the default form elements have been appended.
545
        * @param Author $author
546
        * The current Author object that is being edited
547
        * @param array $fields
548
        *  The POST fields
549
        *  This parameter is available @since Symphony 2.7.0
550
        * @param array $errors
551
        *  The error array used to validate the Author.
552
        *  Extension should register their own errors elsewhere and used the value
553
        *  to modify the UI accordingly.
554
        *  This parameter is available @since Symphony 2.7.0
555
        */
556
        Symphony::ExtensionManager()->notifyMembers('AddElementstoAuthorForm', '/system/authors/', array(
557
            'form' => &$this->Form,
558
            'author' => $author,
559
            'fields' => $_POST['fields'],
560
            'errors' => $this->_errors,
561
        ));
562
    }
563
564
    public function __actionNew()
565
    {
566
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
567
            $fields = $_POST['fields'];
568
569
            $this->_Author = new Author();
570
            $this->_Author->set('user_type', $fields['user_type']);
571
            $this->_Author->set('primary', 'no');
572
            $this->_Author->set('email', $fields['email']);
573
            $this->_Author->set('username', General::sanitize($fields['username']));
574
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
575
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
576
            $this->_Author->set('last_seen', null);
577
            $this->_Author->set('password', (trim($fields['password']) == '' ? '' : Cryptography::hash(Symphony::Database()->cleanValue($fields['password']))));
578
            $this->_Author->set('default_area', $fields['default_area']);
579
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
580
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
581
582
            /**
583
             * Creation of a new Author. The Author object is provided as read
584
             * only through this delegate.
585
             *
586
             * @delegate AuthorPreCreate
587
             * @since Symphony 2.7.0
588
             * @param string $context
589
             * '/system/authors/'
590
             * @param Author $author
591
             *  The Author object that has just been created, but not yet committed, nor validated
592
             * @param array $fields
593
             *  The POST fields
594
             * @param array $errors
595
             *  The error array used to validate the Author, passed by reference.
596
             *  Extension should append to this array if they detect validation problems.
597
             */
598
            Symphony::ExtensionManager()->notifyMembers('AuthorPreCreate', '/system/authors/', array(
599
                'author' => $this->_Author,
600
                'field' => $fields,
601
                'errors' => &$this->_errors,
602
            ));
603
604
            if (empty($this->_errors) && $this->_Author->validate($this->_errors)) {
605
                if ($fields['password'] != $fields['password-confirmation']) {
606
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
607
                } elseif ($author_id = $this->_Author->commit()) {
608
                    /**
609
                     * Creation of a new Author. The Author object is provided as read
610
                     * only through this delegate.
611
                     *
612
                     * @delegate AuthorPostCreate
613
                     * @since Symphony 2.2
614
                     * @param string $context
615
                     * '/system/authors/'
616
                     * @param Author $author
617
                     *  The Author object that has just been created
618
                     * @param array $fields
619
                     *  The POST fields
620
                     *  This parameter is available @since Symphony 2.7.0
621
                     * @param array $errors
622
                     *  The error array used to validate the Author, passed by reference.
623
                     *  Extension should append to this array if they detect saving problems.
624
                     *  This parameter is available @since Symphony 2.7.0
625
                     */
626
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostCreate', '/system/authors/', array(
627
                        'author' => $this->_Author,
628
                        'field' => $fields,
629
                        'errors' => &$this->_errors,
630
                    ));
631
632
                    if (empty($this->_errors)) {
633
                        redirect(SYMPHONY_URL . "/system/authors/edit/$author_id/created/");
634
                    }
635
                }
636
            }
637
638
            if (is_array($this->_errors) && !empty($this->_errors)) {
639
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
640 View Code Duplication
            } else {
641
                $this->pageAlert(
642
                    __('Unknown errors occurred while attempting to save.')
643
                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
644
                    . __('Check your activity log')
645
                    . '</a>.',
646
                    Alert::ERROR
647
                );
648
            }
649
        }
650
    }
651
652
    public function __actionEdit()
653
    {
654
        if (!$author_id = (int)$this->_context[1]) {
655
            redirect(SYMPHONY_URL . '/system/authors/');
656
        }
657
658
        $isOwner = ($author_id == Symphony::Author()->get('id'));
659
        $fields = $_POST['fields'];
660
        $this->_Author = AuthorManager::fetchByID($author_id);
661
662
        $canEdit = // Managers can edit all Authors, and their own.
663
                (Symphony::Author()->isManager() && $this->_Author->isAuthor())
664
                // Primary account can edit all accounts.
665
                || Symphony::Author()->isPrimaryAccount()
666
                // Developers can edit all developers, managers and authors, and their own,
667
                // but not the primary account
668
                || (Symphony::Author()->isDeveloper() && $this->_Author->isPrimaryAccount() === false);
669
670
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
671
            $authenticated = false;
672
673
            if ($fields['email'] != $this->_Author->get('email')) {
674
                $changing_email = true;
675
            }
676
677
            // Check the old password was correct
678
            if (isset($fields['old-password']) && strlen(trim($fields['old-password'])) > 0 && Cryptography::compare(Symphony::Database()->cleanValue(trim($fields['old-password'])), $this->_Author->get('password'))) {
679
                $authenticated = true;
680
681
                // Developers don't need to specify the old password, unless it's their own account
682
            } elseif (
683
                // All accounts can edit their own
684
                $isOwner ||
685
                // Is allowed to edit?
686
                $canEdit
687
            ) {
688
                $authenticated = true;
689
            }
690
691
            $this->_Author->set('id', $author_id);
692
693
            if ($this->_Author->isPrimaryAccount() || ($isOwner && Symphony::Author()->isDeveloper())) {
694
                $this->_Author->set('user_type', 'developer'); // Primary accounts are always developer, Developers can't lower their level
695
            } elseif ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && isset($fields['user_type'])) {
696
                $this->_Author->set('user_type', $fields['user_type']); // Only developer can change user type
697
            }
698
699
            $this->_Author->set('email', $fields['email']);
700
            $this->_Author->set('username', General::sanitize($fields['username']));
701
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
702
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
703
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
704
705
            if (trim($fields['password']) != '') {
706
                $this->_Author->set('password', Cryptography::hash(Symphony::Database()->cleanValue($fields['password'])));
707
                $changing_password = true;
708
            }
709
710
            // Don't allow authors to set the Section Index as a default area
711
            // If they had it previously set, just save `null` which will redirect
712
            // the Author (when logging in) to their own Author record
713
            if (
714
                $this->_Author->get('user_type') == 'author'
715
                && $fields['default_area'] == '/blueprints/sections/'
716
            ) {
717
                $this->_Author->set('default_area', null);
718
            } else {
719
                $this->_Author->set('default_area', $fields['default_area']);
720
            }
721
722
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
723
724
            /**
725
             * Before editing an author, provided with the Author object
726
             *
727
             * @delegate AuthorPreEdit
728
             * @since Symphony 2.7.0
729
             * @param string $context
730
             * '/system/authors/'
731
             * @param Author $author
732
             * An Author object not yet committed, nor validated
733
             * @param array $fields
734
             *  The POST fields
735
             * @param array $errors
736
             *  The error array used to validate the Author, passed by reference.
737
             *  Extension should append to this array if they detect validation problems.
738
             */
739
            Symphony::ExtensionManager()->notifyMembers('AuthorPreEdit', '/system/authors/', array(
740
                'author' => $this->_Author,
741
                'field' => $fields,
742
                'errors' => &$this->_errors,
743
            ));
744
745
            if (empty($this->_errors) && $this->_Author->validate($this->_errors)) {
746
                // Admin changing another profile
747 View Code Duplication
                if (!$isOwner) {
748
                    $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
749
750
                    if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
751
                        $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
752
                    } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
753
                        $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
754
                    }
755
                }
756
757
                // Author is changing their password
758
                if (!$authenticated && ($changing_password || $changing_email)) {
759
                    if ($changing_password) {
0 ignored issues
show
Bug introduced by
The variable $changing_password does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
760
                        $this->_errors['old-password'] = __('Wrong password. Enter old password to change it.');
761
                    } elseif ($changing_email) {
0 ignored issues
show
Bug introduced by
The variable $changing_email does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
762
                        $this->_errors['old-password'] = __('Wrong password. Enter old one to change email address.');
763
                    }
764
765
                    // Passwords provided, but doesn't match.
766
                } elseif (($fields['password'] != '' || $fields['password-confirmation'] != '') && $fields['password'] != $fields['password-confirmation']) {
767
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
768
                }
769
770
                // All good, let's save the Author
771
                if (is_array($this->_errors) && empty($this->_errors) && $this->_Author->commit()) {
772
                    Symphony::Database()->delete('tbl_forgotpass', sprintf("
773
                        `expiry` < '%s' OR `author_id` = %d",
774
                        DateTimeObj::getGMT('c'),
775
                        $author_id
776
                    ));
777
778
                    if ($isOwner) {
779
                        Administration::instance()->login($this->_Author->get('username'), $this->_Author->get('password'), true);
780
                    }
781
782
                    /**
783
                     * After editing an author, provided with the Author object
784
                     *
785
                     * @delegate AuthorPostEdit
786
                     * @since Symphony 2.2
787
                     * @param string $context
788
                     * '/system/authors/'
789
                     * @param Author $author
790
                     * An Author object
791
                     * @param array $fields
792
                     *  The POST fields
793
                     *  This parameter is available @since Symphony 2.7.0
794
                     * @param array $errors
795
                     *  The error array used to validate the Author, passed by reference.
796
                     *  Extension should append to this array if they detect saving problems.
797
                     *  This parameter is available @since Symphony 2.7.0
798
                     */
799
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostEdit', '/system/authors/', array(
800
                        'author' => $this->_Author,
801
                        'field' => $fields,
802
                        'errors' => &$this->_errors,
803
                    ));
804
805
                    if (empty($this->_errors)) {
806
                        redirect(SYMPHONY_URL . '/system/authors/edit/' . $author_id . '/saved/');
807
                    }
808
809
                    // Problems.
810 View Code Duplication
                } else {
811
                    $this->pageAlert(
812
                        __('Unknown errors occurred while attempting to save.')
813
                        . '<a href="' . SYMPHONY_URL . '/system/log/">'
814
                        . __('Check your activity log')
815
                        . '</a>.',
816
                        Alert::ERROR
817
                    );
818
                }
819
            }
820
821
            // Author doesn't have valid data, throw back.
822 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
823
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
824
            }
825
        } elseif (@array_key_exists('delete', $_POST['action'])) {
826
            // Validate rights
827
            if (!$canEdit) {
828
                $this->pageAlert(__('You are not allowed to delete this author.'), Alert::ERROR);
829
                return;
830
            }
831
            // Admin changing another profile
832 View Code Duplication
            if (!$isOwner) {
833
                $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
834
835
                if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
836
                    $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
837
                } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
838
                    $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
839
                }
840
            }
841 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
842
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
843
                return;
844
            }
845
846
            $this->_Author = AuthorManager::fetchByID($author_id);
847
848
            /**
849
             * Prior to deleting an author, provided with the Author ID.
850
             *
851
             * @delegate AuthorPreDelete
852
             * @since Symphony 2.2
853
             * @param string $context
854
             * '/system/authors/'
855
             * @param integer $author_id
856
             *  The ID of Author ID that is about to be deleted
857
             * @param Author $author
858
             *  The Author object.
859
             *  This parameter is available @since Symphony 2.7.0
860
             */
861
            Symphony::ExtensionManager()->notifyMembers('AuthorPreDelete', '/system/authors/', array(
862
                'author_id' => $author_id,
863
                'author' => $this->_Author,
864
            ));
865
866
            if (!$isOwner) {
867
                $result = AuthorManager::delete($author_id);
868
869
                /**
870
                 * After deleting an author, provided with the Author ID.
871
                 *
872
                 * @delegate AuthorPostDelete
873
                 * @since Symphony 2.7.0
874
                 * @param string $context
875
                 * '/system/authors/'
876
                 * @param integer $author_id
877
                 *  The ID of Author ID that is about to be deleted
878
                 * @param Author $author
879
                 *  The Author object.
880
                 * @param integer $result
881
                 *  The result of the delete statement
882
                 */
883
                Symphony::ExtensionManager()->notifyMembers('AuthorPostDelete', '/system/authors/', array(
884
                    'author_id' => $author_id,
885
                    'author' => $this->_Author,
886
                    'result' => $result
887
                ));
888
889
                redirect(SYMPHONY_URL . '/system/authors/');
890
            } else {
891
                $this->pageAlert(__('You cannot remove yourself as you are the active Author.'), Alert::ERROR);
892
            }
893
        }
894
    }
895
}
896