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
Pull Request — master (#2606)
by
unknown
05:01
created

contentSystemAuthors::sort()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 10
rs 9.4285
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
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
76
77
        $aTableBody = array();
78
79
        if (!is_array($authors) || empty($authors)) {
80
            $aTableBody = array(
81
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
82
            );
83
        } else {
84
            foreach ($authors as $a) {
85
                // Setup each cell
86
                if (
87
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper()))
88
                    || Symphony::Author()->get('id') == $a->get('id')
89
                ) {
90
                    $td1 = Widget::TableData(
91
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
92
                    );
93
                } else {
94
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
95
                }
96
97
                // Can this Author be edited by the current Author?
98
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
99
                    if ($a->get('id') != Symphony::Author()->get('id')) {
100
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
101
                            'for' => 'author-' . $a->get('id')
102
                        )));
103
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
104
                            'id' => 'author-' . $a->get('id')
105
                        )));
106
                    }
107
                }
108
109
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
110
111
                if (!is_null($a->get('last_seen'))) {
112
                    $td3 = Widget::TableData(
113
                        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...
114
                    );
115
                } else {
116
                    $td3 = Widget::TableData(__('Unknown'), 'inactive');
117
                }
118
119
                if ($a->isDeveloper()) {
120
                    $type = 'Developer';
121
                } elseif ($a->isManager()) {
122
                    $type = 'Manager';
123
                } else {
124
                    $type = 'Author';
125
                }
126
127
                $td4 = Widget::TableData(__($type));
128
129
                $languages = Lang::getAvailableLanguages();
130
131
                $td5 = Widget::TableData($a->get("language") == null ? __("System Default") : $languages[$a->get("language")]);
132
133
                // Add a row to the body array, assigning each cell to the row
134
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
135
                    $aTableBody[] = Widget::TableRow(array($td1, $td2, $td3, $td4, $td5));
136
                } else {
137
                    $aTableBody[] = Widget::TableRow(array($td1, $td2, $td3));
138
                }
139
            }
140
        }
141
142
        $table = Widget::Table(
143
            Widget::TableHead($aTableHead),
144
            null,
145
            Widget::TableBody($aTableBody),
146
            'selectable',
147
            null,
148
            array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading')
149
        );
150
151
        $this->Form->appendChild($table);
152
153
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
154
            'id' => 'version'
155
        ));
156
157
        $this->Form->appendChild($version);
158
    }
159
160
    // Both the Edit and New pages need the same form
161
    public function __viewNew()
162
    {
163
        $this->__form();
164
    }
165
166
    public function __viewEdit()
167
    {
168
        $this->__form();
169
    }
170
171
    public function __form()
0 ignored issues
show
Coding Style introduced by
__form uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
172
    {
173
        // Handle unknown context
174
        if (!in_array($this->_context[0], array('new', 'edit'))) {
175
            Administration::instance()->errorPageNotFound();
176
        }
177
178
        if ($this->_context[0] == 'new' && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
179
            Administration::instance()->throwCustomError(
180
                __('You are not authorised to access this page.'),
181
                __('Access Denied'),
182
                Page::HTTP_STATUS_UNAUTHORIZED
183
            );
184
        }
185
186
        if (isset($this->_context[2])) {
187
            $time = Widget::Time();
188
189
            switch ($this->_context[2]) {
190
                case 'saved':
191
                    $message = __('Author updated at %s.', array($time->generate()));
192
                    break;
193
                case 'created':
194
                    $message = __('Author created at %s.', array($time->generate()));
195
            }
196
197
            $this->pageAlert(
198
                $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...
199
                . ' <a href="' . SYMPHONY_URL . '/system/authors/new/" accesskey="c">'
200
                . __('Create another?')
201
                . '</a> <a href="' . SYMPHONY_URL . '/system/authors/" accesskey="a">'
202
                . __('View all Authors')
203
                . '</a>',
204
                Alert::SUCCESS
205
            );
206
        }
207
208
        $this->setPageType('form');
209
        $isOwner = false;
210
        $isEditing = ($this->_context[0] == 'edit');
211
212
        if (isset($_POST['fields'])) {
213
            $author = $this->_Author;
214
        } elseif ($this->_context[0] == 'edit') {
215
            if (!$author_id = (int)$this->_context[1]) {
216
                redirect(SYMPHONY_URL . '/system/authors/');
217
            }
218
219
            if (!$author = AuthorManager::fetchByID($author_id)) {
220
                Administration::instance()->throwCustomError(
221
                    __('The author profile you requested does not exist.'),
222
                    __('Author not found'),
223
                    Page::HTTP_STATUS_NOT_FOUND
224
                );
225
            }
226
        } else {
227
            $author = new Author;
228
        }
229
230
        if ($isEditing && $author->get('id') == Symphony::Author()->get('id')) {
231
            $isOwner = true;
232
        }
233
234
        if ($isEditing && !$isOwner && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
235
            Administration::instance()->throwCustomError(
236
                __('You are not authorised to edit other authors.'),
237
                __('Access Denied'),
238
                Page::HTTP_STATUS_FORBIDDEN
239
            );
240
        }
241
242
        $this->setTitle(__(($this->_context[0] == 'new' ? '%2$s &ndash; %3$s' : '%1$s &ndash; %2$s &ndash; %3$s'), array($author->getFullName(), __('Authors'), __('Symphony'))));
243
        $this->appendSubheading(($this->_context[0] == 'new' ? __('Untitled') : $author->getFullName()));
244
        $this->insertBreadcrumbs(array(
245
            Widget::Anchor(__('Authors'), SYMPHONY_URL . '/system/authors/'),
246
        ));
247
248
        // Essentials
249
        $group = new XMLElement('fieldset');
250
        $group->setAttribute('class', 'settings');
251
        $group->appendChild(new XMLElement('legend', __('Essentials')));
252
253
        $div = new XMLElement('div');
254
        $div->setAttribute('class', 'two columns');
255
256
        $label = Widget::Label(__('First Name'), null, 'column');
257
        $label->appendChild(Widget::Input('fields[first_name]', $author->get('first_name')));
258
        $div->appendChild((isset($this->_errors['first_name']) ? Widget::Error($label, $this->_errors['first_name']) : $label));
259
260
261
        $label = Widget::Label(__('Last Name'), null, 'column');
262
        $label->appendChild(Widget::Input('fields[last_name]', $author->get('last_name')));
263
        $div->appendChild((isset($this->_errors['last_name']) ? Widget::Error($label, $this->_errors['last_name']) : $label));
264
265
        $group->appendChild($div);
266
267
        $label = Widget::Label(__('Email Address'));
268
        $label->appendChild(Widget::Input('fields[email]', $author->get('email'), 'text', array('autocomplete' => 'off')));
269
        $group->appendChild((isset($this->_errors['email']) ? Widget::Error($label, $this->_errors['email']) : $label));
270
271
        $this->Form->appendChild($group);
272
273
        // Login Details
274
        $group = new XMLElement('fieldset');
275
        $group->setAttribute('class', 'settings');
276
        $group->appendChild(new XMLElement('legend', __('Login Details')));
277
278
        $div = new XMLElement('div');
279
280
        $label = Widget::Label(__('Username'));
281
        $label->appendChild(Widget::Input('fields[username]', $author->get('username'), 'text', array('autocomplete' => 'off')));
282
        $div->appendChild((isset($this->_errors['username']) ? Widget::Error($label, $this->_errors['username']) : $label));
283
284
        // Only developers can change the user type. Primary account should NOT be able to change this
285
        if ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && !$author->isPrimaryAccount()) {
286
287
            // Create columns
288
            $div->setAttribute('class', 'two columns');
289
            $label->setAttribute('class', 'column');
290
291
            // User type
292
            $label = Widget::Label(__('User Type'), null, 'column');
293
294
            $options = array(
295
                array('author', false, __('Author')),
296
                array('manager', $author->isManager(), __('Manager'))
297
            );
298
299
            if (Symphony::Author()->isDeveloper()) {
300
                $options[] = array('developer', $author->isDeveloper(), __('Developer'));
301
            }
302
303
            $label->appendChild(Widget::Select('fields[user_type]', $options));
304
            $div->appendChild($label);
305
        }
306
307
        $group->appendChild($div);
308
309
        // Password
310
        $fieldset = new XMLElement('fieldset', null, array('class' => 'two columns', 'id' => 'password'));
311
        $legend = new XMLElement('legend', __('Password'));
312
        $help = new XMLElement('i', __('Leave password fields blank to keep the current password'));
313
        $fieldset->appendChild($legend);
314
        $fieldset->appendChild($help);
315
316
        /*
317
            Password reset rules:
318
            - Primary account can edit all accounts.
319
            - Developers can edit all developers, managers and authors, and their own.
320
            - Managers can edit all Authors, and their own.
321
            - Authors can edit their own.
322
        */
323
        if ($isEditing && !(
324
            // All accounts can edit their own
325
            $isOwner
326
            // Managers can edit all Authors, and their own.
327
            || (Symphony::Author()->isManager() && $author->isAuthor())
328
            // Primary account can edit all accounts.
329
            || Symphony::Author()->isPrimaryAccount()
330
            // Developers can edit all developers, managers and authors, and their own.
331
            || Symphony::Author()->isDeveloper() && $author->isPrimaryAccount() === false
332
        )) {
333
            $fieldset->setAttribute('class', 'three columns');
334
335
            $label = Widget::Label(null, null, 'column');
336
            $label->appendChild(Widget::Input('fields[old-password]', null, 'password', array('placeholder' => __('Old Password'), 'autocomplete' => 'off')));
337
            $fieldset->appendChild((isset($this->_errors['old-password']) ? Widget::Error($label, $this->_errors['old-password']) : $label));
338
        }
339
340
        // New password
341
        $placeholder = ($isEditing ? __('New Password') : __('Password'));
342
        $label = Widget::Label(null, null, 'column');
343
        $label->appendChild(Widget::Input('fields[password]', null, 'password', array('placeholder' => $placeholder, 'autocomplete' => 'off')));
344
        $fieldset->appendChild((isset($this->_errors['password']) ? Widget::Error($label, $this->_errors['password']) : $label));
345
346
        // Confirm password
347
        $label = Widget::Label(null, null, 'column');
348
        $label->appendChild(Widget::Input('fields[password-confirmation]', null, 'password', array('placeholder' => __('Confirm Password'), 'autocomplete' => 'off')));
349
        $fieldset->appendChild((isset($this->_errors['password-confirmation']) ? Widget::Error($label, $this->_errors['password']) : $label));
350
351
        $group->appendChild($fieldset);
352
353
        // Auth token
354
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
355
            $label = Widget::Label();
356
            $group->appendChild(Widget::Input('fields[auth_token_active]', 'no', 'hidden'));
357
            $input = Widget::Input('fields[auth_token_active]', 'yes', 'checkbox');
358
359
            if ($author->isTokenActive()) {
360
                $input->setAttribute('checked', 'checked');
361
            }
362
363
            $temp = SYMPHONY_URL . '/login/' . $author->createAuthToken() . '/';
364
            $label->setValue(__('%s Allow remote login via', array($input->generate())) . ' <a href="' . $temp . '">' . $temp . '</a>');
365
            $group->appendChild($label);
366
        }
367
368
        $label = Widget::Label(__('Default Area'));
369
370
        $sections = SectionManager::fetch(null, 'ASC', 'sortorder');
371
372
        $options = array();
373
374
        // If the Author is the Developer, allow them to set the Default Area to
375
        // be the Sections Index.
376
        if ($author->isDeveloper()) {
377
            $options[] = array('/blueprints/sections/', $author->get('default_area') == '/blueprints/sections/', __('Sections Index'));
378
        }
379
380
        if (is_array($sections) && !empty($sections)) {
381
            foreach ($sections as $s) {
382
                $options[] = array($s->get('id'), $author->get('default_area') == $s->get('id'), $s->get('name'));
383
            }
384
        }
385
386
        /**
387
        * Allows injection or manipulation of the Default Area dropdown for an Author.
388
        * Take care with adding in options that are only valid for Developers, as if a
389
        * normal Author is set to that option, they will be redirected to their own
390
        * Author record.
391
        *
392
        *
393
        * @delegate AddDefaultAuthorAreas
394
        * @since Symphony 2.2
395
        * @param string $context
396
        * '/system/authors/'
397
        * @param array $options
398
        * An associative array of options, suitable for use for the Widget::Select
399
        * function. By default this will be an array of the Sections in the current
400
        * installation. New options should be the path to the page after the `SYMPHONY_URL`
401
        * constant.
402
        * @param string $default_area
403
        * The current `default_area` for this Author.
404
        */
405
        Symphony::ExtensionManager()->notifyMembers('AddDefaultAuthorAreas', '/system/authors/', array(
406
            'options' => &$options,
407
            'default_area' => $author->get('default_area')
408
        ));
409
410
        $label->appendChild(Widget::Select('fields[default_area]', $options));
411
        $group->appendChild($label);
412
413
        $this->Form->appendChild($group);
414
415
        // Custom Language Selection
416
        $languages = Lang::getAvailableLanguages();
417
        if (count($languages) > 1) {
418
            // Get language names
419
            asort($languages);
420
421
            $group = new XMLElement('fieldset');
422
            $group->setAttribute('class', 'settings');
423
            $group->appendChild(new XMLElement('legend', __('Custom Preferences')));
424
425
            $label = Widget::Label(__('Language'));
426
427
            $options = array(
428
                array(null, is_null($author->get('language')), __('System Default'))
429
            );
430
431
            foreach ($languages as $code => $name) {
432
                $options[] = array($code, $code == $author->get('language'), $name);
433
            }
434
            $select = Widget::Select('fields[language]', $options);
435
            $label->appendChild($select);
436
            $group->appendChild($label);
437
438
            $this->Form->appendChild($group);
439
        }
440
441
        // Administration password double check
442
        if ($isEditing && !$isOwner) {
443
            $group = new XMLElement('fieldset');
444
            $group->setAttribute('class', 'settings');
445
            $group->setAttribute('id', 'confirmation');
446
            $group->appendChild(new XMLElement('legend', __('Confirmation')));
447
            $group->appendChild(new XMLELement('p', __('Please confirm changes to this author with your password.'), array('class' => 'help')));
448
449
            $label = Widget::Label(__('Password'));
450
            $label->appendChild(Widget::Input('fields[confirm-change-password]', null, 'password', array(
451
                'autocomplete' => 'off',
452
                'placeholder' => __('Your Password')
453
            )));
454
            $group->appendChild(
455
                isset($this->_errors['confirm-change-password']) ? Widget::Error($label, $this->_errors['confirm-change-password']) : $label
456
            );
457
458
            $this->Form->appendChild($group);
459
        }
460
461
        // Actions
462
        $div = new XMLElement('div');
463
        $div->setAttribute('class', 'actions');
464
465
        $div->appendChild(Widget::Input('action[save]', ($this->_context[0] == 'edit' ? __('Save Changes') : __('Create Author')), 'submit', array('accesskey' => 's')));
466
467
        if ($isEditing && !$isOwner && !$author->isPrimaryAccount()) {
468
            $button = new XMLElement('button', __('Delete'));
469
            $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?')));
470
            $div->appendChild($button);
471
        }
472
473
        $this->Form->appendChild($div);
474
475
        /**
476
        * Allows the injection of custom form fields given the current `$this->Form`
477
        * object. Please note that this custom data should be saved in own extension
478
        * tables and that modifying `tbl_authors` to house your data is highly discouraged.
479
        *
480
        * @delegate AddElementstoAuthorForm
481
        * @since Symphony 2.2
482
        * @param string $context
483
        * '/system/authors/'
484
        * @param XMLElement $form
485
        * The contents of `$this->Form` after all the default form elements have been appended.
486
        * @param Author $author
487
        * The current Author object that is being edited
488
        */
489
        Symphony::ExtensionManager()->notifyMembers('AddElementstoAuthorForm', '/system/authors/', array(
490
            'form' => &$this->Form,
491
            'author' => $author
492
        ));
493
    }
494
495
    public function __actionNew()
0 ignored issues
show
Coding Style introduced by
__actionNew uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
496
    {
497
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
498
            $fields = $_POST['fields'];
499
500
            $this->_Author = new Author;
501
            $this->_Author->set('user_type', $fields['user_type']);
502
            $this->_Author->set('primary', 'no');
503
            $this->_Author->set('email', $fields['email']);
504
            $this->_Author->set('username', General::sanitize($fields['username']));
505
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
506
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
507
            $this->_Author->set('last_seen', null);
508
            $this->_Author->set('password', (trim($fields['password']) == '' ? '' : Cryptography::hash(Symphony::Database()->cleanValue($fields['password']))));
509
            $this->_Author->set('default_area', $fields['default_area']);
510
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
511
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
512
513
            if ($this->_Author->validate($this->_errors)) {
514
                if ($fields['password'] != $fields['password-confirmation']) {
515
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
516
                } elseif ($author_id = $this->_Author->commit()) {
517
                    /**
518
                     * Creation of a new Author. The Author object is provided as read
519
                     * only through this delegate.
520
                     *
521
                     * @delegate AuthorPostCreate
522
                     * @since Symphony 2.2
523
                     * @param string $context
524
                     * '/system/authors/'
525
                     * @param Author $author
526
                     *  The Author object that has just been created
527
                     */
528
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostCreate', '/system/authors/', array('author' => $this->_Author));
529
530
                    redirect(SYMPHONY_URL . "/system/authors/edit/$author_id/created/");
531
                }
532
            }
533
534
            if (is_array($this->_errors) && !empty($this->_errors)) {
535
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
536 View Code Duplication
            } else {
537
                $this->pageAlert(
538
                    __('Unknown errors occurred while attempting to save.')
539
                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
540
                    . __('Check your activity log')
541
                    . '</a>.',
542
                    Alert::ERROR
543
                );
544
            }
545
        }
546
    }
547
548
    public function __actionEdit()
0 ignored issues
show
Coding Style introduced by
__actionEdit uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
549
    {
550
        if (!$author_id = (int)$this->_context[1]) {
551
            redirect(SYMPHONY_URL . '/system/authors/');
552
        }
553
554
        $isOwner = ($author_id == Symphony::Author()->get('id'));
555
        $fields = $_POST['fields'];
556
        $this->_Author = AuthorManager::fetchByID($author_id);
557
558
        $canEdit = // Managers can edit all Authors, and their own.
559
                (Symphony::Author()->isManager() && $this->_Author->isAuthor())
560
                // Primary account can edit all accounts.
561
                || Symphony::Author()->isPrimaryAccount()
562
                // Developers can edit all developers, managers and authors, and their own,
563
                // but not the primary account
564
                || (Symphony::Author()->isDeveloper() && $this->_Author->isPrimaryAccount() === false);
565
566
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
567
            $authenticated = false;
568
569
            if ($fields['email'] != $this->_Author->get('email')) {
570
                $changing_email = true;
571
            }
572
573
            // Check the old password was correct
574
            if (isset($fields['old-password']) && strlen(trim($fields['old-password'])) > 0 && Cryptography::compare(Symphony::Database()->cleanValue(trim($fields['old-password'])), $this->_Author->get('password'))) {
575
                $authenticated = true;
576
577
                // Developers don't need to specify the old password, unless it's their own account
578
            } elseif (
579
                // All accounts can edit their own
580
                $isOwner ||
581
                // Is allowed to edit?
582
                $canEdit
583
            ) {
584
                $authenticated = true;
585
            }
586
587
            $this->_Author->set('id', $author_id);
588
589
            if ($this->_Author->isPrimaryAccount() || ($isOwner && Symphony::Author()->isDeveloper())) {
590
                $this->_Author->set('user_type', 'developer'); // Primary accounts are always developer, Developers can't lower their level
591
            } elseif ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && isset($fields['user_type'])) {
592
                $this->_Author->set('user_type', $fields['user_type']); // Only developer can change user type
593
            }
594
595
            $this->_Author->set('email', $fields['email']);
596
            $this->_Author->set('username', General::sanitize($fields['username']));
597
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
598
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
599
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
600
601
            if (trim($fields['password']) != '') {
602
                $this->_Author->set('password', Cryptography::hash(Symphony::Database()->cleanValue($fields['password'])));
603
                $changing_password = true;
604
            }
605
606
            // Don't allow authors to set the Section Index as a default area
607
            // If they had it previously set, just save `null` which will redirect
608
            // the Author (when logging in) to their own Author record
609
            if (
610
                $this->_Author->get('user_type') == 'author'
611
                && $fields['default_area'] == '/blueprints/sections/'
612
            ) {
613
                $this->_Author->set('default_area', null);
614
            } else {
615
                $this->_Author->set('default_area', $fields['default_area']);
616
            }
617
618
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
619
620
            if ($this->_Author->validate($this->_errors)) {
621
                // Admin changing another profile
622 View Code Duplication
                if (!$isOwner) {
623
                    $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
624
625
                    if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
626
                        $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
627
                    } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
628
                        $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
629
                    }
630
                }
631
632
                // Author is changing their password
633
                if (!$authenticated && ($changing_password || $changing_email)) {
634
                    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...
635
                        $this->_errors['old-password'] = __('Wrong password. Enter old password to change it.');
636
                    } 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...
637
                        $this->_errors['old-password'] = __('Wrong password. Enter old one to change email address.');
638
                    }
639
640
                    // Passwords provided, but doesn't match.
641
                } elseif (($fields['password'] != '' || $fields['password-confirmation'] != '') && $fields['password'] != $fields['password-confirmation']) {
642
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
643
                }
644
645
                // All good, let's save the Author
646
                if (is_array($this->_errors) && empty($this->_errors) && $this->_Author->commit()) {
647
                    Symphony::Database()->delete('tbl_forgotpass', sprintf("
648
                        `expiry` < '%s' OR `author_id` = %d",
649
                        DateTimeObj::getGMT('c'),
650
                        $author_id
651
                    ));
652
653
                    if ($isOwner) {
654
                        Administration::instance()->login($this->_Author->get('username'), $this->_Author->get('password'), true);
655
                    }
656
657
                    /**
658
                     * After editing an author, provided with the Author object
659
                     *
660
                     * @delegate AuthorPostEdit
661
                     * @since Symphony 2.2
662
                     * @param string $context
663
                     * '/system/authors/'
664
                     * @param Author $author
665
                     * An Author object
666
                     */
667
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostEdit', '/system/authors/', array('author' => $this->_Author));
668
669
                    redirect(SYMPHONY_URL . '/system/authors/edit/' . $author_id . '/saved/');
670
671
                    // Problems.
672 View Code Duplication
                } else {
673
                    $this->pageAlert(
674
                        __('Unknown errors occurred while attempting to save.')
675
                        . '<a href="' . SYMPHONY_URL . '/system/log/">'
676
                        . __('Check your activity log')
677
                        . '</a>.',
678
                        Alert::ERROR
679
                    );
680
                }
681
            }
682
683
            // Author doesn't have valid data, throw back.
684 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
685
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
686
            }
687
        } elseif (@array_key_exists('delete', $_POST['action'])) {
688
            // Validate rights
689
            if (!$canEdit) {
690
                $this->pageAlert(__('You are not allowed to delete this author.'), Alert::ERROR);
691
                return;
692
            }
693
            // Admin changing another profile
694 View Code Duplication
            if (!$isOwner) {
695
                $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
696
697
                if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
698
                    $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
699
                } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
700
                    $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
701
                }
702
            }
703 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
704
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
705
                return;
706
            }
707
708
            /**
709
             * Prior to deleting an author, provided with the Author ID.
710
             *
711
             * @delegate AuthorPreDelete
712
             * @since Symphony 2.2
713
             * @param string $context
714
             * '/system/authors/'
715
             * @param integer $author_id
716
             *  The ID of Author ID that is about to be deleted
717
             */
718
            Symphony::ExtensionManager()->notifyMembers('AuthorPreDelete', '/system/authors/', array('author_id' => $author_id));
719
720
            if (!$isOwner) {
721
                AuthorManager::delete($author_id);
722
                redirect(SYMPHONY_URL . '/system/authors/');
723
            } else {
724
                $this->pageAlert(__('You cannot remove yourself as you are the active Author.'), Alert::ERROR);
725
            }
726
        }
727
    }
728
}
729