Completed
Push — master ( b7ce29...3026ce )
by Andrii
04:29
created

ServerController   B

Complexity

Total Complexity 24

Size/Duplication

Total Lines 409
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 18

Test Coverage

Coverage 85.48%

Importance

Changes 36
Bugs 6 Features 11
Metric Value
wmc 24
c 36
b 6
f 11
lcom 0
cbo 18
dl 0
loc 409
ccs 106
cts 124
cp 0.8548
rs 7.3333

6 Methods

Rating   Name   Duplication   Size   Complexity  
A actionDrawChart() 0 21 2
C actions() 0 323 12
A getVNCInfo() 0 10 4
A getOsimages() 0 16 3
A getOsimagesLiveCd() 0 12 2
A getPanelTypes() 0 4 1
1
<?php
2
3
/*
4
 * Server module for HiPanel
5
 *
6
 * @link      https://github.com/hiqdev/hipanel-module-server
7
 * @package   hipanel-module-server
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hipanel\modules\server\controllers;
13
14
use hipanel\actions\Action;
15
use hipanel\actions\IndexAction;
16
use hipanel\actions\OrientationAction;
17
use hipanel\actions\PrepareBulkAction;
18
use hipanel\actions\ProxyAction;
19
use hipanel\actions\RedirectAction;
20
use hipanel\actions\RenderAction;
21
use hipanel\actions\RenderJsonAction;
22
use hipanel\actions\RequestStateAction;
23
use hipanel\actions\SearchAction;
24
use hipanel\actions\SmartDeleteAction;
25
use hipanel\actions\SmartUpdateAction;
26
use hipanel\actions\ValidateFormAction;
27
use hipanel\actions\ViewAction;
28
use hipanel\base\CrudController;
29
use hipanel\models\Ref;
30
use hipanel\modules\finance\models\Tariff;
31
use hipanel\modules\server\cart\ServerRenewProduct;
32
use hipanel\modules\server\helpers\ServerHelper;
33
use hipanel\modules\server\models\Osimage;
34
use hipanel\modules\server\models\Server;
35
use hipanel\modules\server\models\ServerUseSearch;
36
use hiqdev\yii2\cart\actions\AddToCartAction;
37
use Yii;
38
use yii\base\Event;
39
use yii\helpers\ArrayHelper;
40
use yii\web\NotFoundHttpException;
41
42
class ServerController extends CrudController
43
{
44 1
    public function actions()
45
    {
46
        return [
47
            'index' => [
48 1
                'class' => IndexAction::class,
49 1
                'findOptions' => ['with_requests' => true, 'with_discounts' => true],
50
                'on beforePerform' => function (Event $event) {
51
                    /** @var \hipanel\actions\SearchAction $action */
52
                    $action = $event->sender;
53
                    $dataProvider = $action->getDataProvider();
54
                    $dataProvider->query->joinWith('ips');
55
56
                    $dataProvider->query
57
                        ->andWhere(['with_ips' => 1])
58
                        ->andWhere(['with_switches' => 1])
59
                        ->andWhere(['with_requests' => 1])
60
                        ->andWhere(['with_discounts' => 1])
61
                        ->select(['*']);
62 1
                },
63
                'filterStorageMap' => [
64
                    'name_like' => 'server.server.name',
65
                    'ips' => 'hosting.ip.ip_in',
66
                    'state' => 'server.server.state',
67
                    'client_id' => 'client.client.id',
68
                    'seller_id' => 'client.client.seller_id',
69 1
                ],
70 1
            ],
71
            'search' => [
72
                'class' => SearchAction::class,
73 1
            ],
74
            'view' => [
75 1
                'class' => ViewAction::class,
76
                'on beforePerform' => function (Event $event) {
77
                    /** @var \hipanel\actions\SearchAction $action */
78
                    $action = $event->sender;
79
                    $dataProvider = $action->getDataProvider();
80
                    $dataProvider->query->joinWith('uses');
81
                    $dataProvider->query->joinWith('ips');
82
83
                    // TODO: ipModule is not wise yet. Redo
84
                    $dataProvider->query
85
                        ->andWhere(['with_requests' => 1])
86
                        ->andWhere(['show_deleted' => 1])
87
                        ->andWhere(['with_discounts' => 1])
88
                        ->andWhere(['with_uses' => 1])
89
                        ->andWhere(['with_ips' => 1])
90
                        ->select(['*']);
91 1
                },
92
                'data' => function ($action) {
93
                    /**
94
                     * @var
95
                     * @var $model Server
96
                     */
97
                    $controller = $action->controller;
98
                    $model = $action->getModel();
99
                    $model->vnc = $controller->getVNCInfo($model);
100
101
                    $panels = $controller->getPanelTypes();
102
103
                    $tariff = Yii::$app->cache->getAuthTimeCached(3600, [$model->tariff_id], function ($tariff_id) {
104
                        return Tariff::find()->where([
105
                            'id' => $tariff_id,
106
                            'show_final' => true,
107
                            'show_deleted' => true,
108
                            'with_resources' => true,
109
                        ])->joinWith('resources')->one();
110
                    });
111
112
                    $ispSupported = false;
113
                    if ($tariff !== null) {
114
                        foreach ($tariff->getResources() as $resource) {
115
                            if ($resource->type === 'isp' && $resource->quantity > 0) {
116
                                $ispSupported = true;
117
                            }
118
                        }
119
                    }
120
121
                    $osimages = $controller->getOsimages($model);
122
                    $groupedOsimages = ServerHelper::groupOsimages($osimages, $ispSupported);
123
124
                    if ($model->isLiveCDSupported()) {
125
                        $osimageslivecd = $controller->getOsimagesLiveCd();
126
                    }
127
128
                    $blockReasons = $controller->getBlockReasons();
129
130
                    return compact([
131
                        'model',
132
                        'osimages',
133
                        'osimageslivecd',
134
                        'groupedOsimages',
135
                        'panels',
136
                        'blockReasons',
137
                    ]);
138 1
                },
139 1
            ],
140
            'requests-state' => [
141
                'class' => RequestStateAction::class,
142
                'model' => Server::class,
143 1
            ],
144
            'set-note' => [
145 1
                'class' => SmartUpdateAction::class,
146 1
                'success' => Yii::t('hipanel/server', 'Note changed'),
147 1
                'error' => Yii::t('hipanel/server', 'Failed to change note'),
148
            ],
149
            'set-label' => [
150 1
                'class' => SmartUpdateAction::class,
151 1
                'success' => Yii::t('hipanel/server', 'Internal note changed'),
152 1
                'error' => Yii::t('hipanel/server', 'Failed to change internal note'),
153
            ],
154
            'set-lock' => [
155 1
                'class' => RenderAction::class,
156 1
                'success' => Yii::t('hipanel/server', 'Record was changed'),
157 1
                'error' => Yii::t('hipanel/server', 'Error occurred'),
158
                'POST pjax' => [
159
                    'save' => true,
160
                    'success' => [
161
                        'class' => ProxyAction::class,
162
                        'action' => 'index',
163
                    ],
164 1
                ],
165
                'POST' => [
166 1
                    'save' => true,
167
                    'success' => [
168 1
                        'class' => RenderJsonAction::class,
169
                        'return' => function ($action) {
170
                            /** @var \hipanel\actions\Action $action */
171
                            return $action->collection->models;
172 1
                        },
173 1
                    ],
174 1
                ],
175
            ],
176
            'sale' => [
177 1
                'class' => SmartUpdateAction::class,
178 1
                'view' => '_saleModal',
179
                'POST' => [
180 1
                    'save' => true,
181
                    'success' => [
182 1
                        'class' => RenderJsonAction::class,
183
                        'return' => function ($action) {
184
                            return ['success' => !$action->collection->hasErrors()];
185 1
                        },
186 1
                    ],
187 1
                ],
188 1
            ],
189
            'enable-vnc' => [
190 1
                'class' => ViewAction::class,
191 1
                'view' => '_vnc',
192
                'data' => function ($action) {
193
                    $model = $action->getModel();
194
                    $model->checkOperable();
195
                    $model->vnc = $action->controller->getVNCInfo($model, true);
196
                    return [];
197 1
                },
198 1
            ],
199
            'reboot' => [
200 1
                'class' => SmartUpdateAction::class,
201 1
                'success' => Yii::t('hipanel/server', 'Reboot task has been successfully added to queue'),
202 1
                'error' => Yii::t('hipanel/server', 'Error during the rebooting'),
203
            ],
204
            'reset' => [
205 1
                'class' => SmartUpdateAction::class,
206 1
                'success' => Yii::t('hipanel/server', 'Reset task has been successfully added to queue'),
207 1
                'error' => Yii::t('hipanel/server', 'Error during the resetting'),
208
            ],
209
            'shutdown' => [
210 1
                'class' => SmartUpdateAction::class,
211 1
                'success' => Yii::t('hipanel/server', 'Shutdown task has been successfully added to queue'),
212 1
                'error' => Yii::t('hipanel/server', 'Error during the shutting down'),
213
            ],
214
            'power-off' => [
215 1
                'class' => SmartUpdateAction::class,
216 1
                'success' => Yii::t('hipanel/server', 'Power off task has been successfully added to queue'),
217 1
                'error' => Yii::t('hipanel/server', 'Error during the turning power off'),
218
            ],
219
            'power-on' => [
220 1
                'class' => SmartUpdateAction::class,
221 1
                'success' => Yii::t('hipanel/server', 'Power on task has been successfully added to queue'),
222 1
                'error' => Yii::t('hipanel/server', 'Error during the turning power on'),
223
            ],
224
            'reset-password' => [
225 1
                'class' => SmartUpdateAction::class,
226 1
                'success' => Yii::t('hipanel/server', 'Root password reset task has been successfully added to queue'),
227 1
                'error' => Yii::t('hipanel/server', 'Error during the resetting root password'),
228
            ],
229
            'enable-block' => [
230 1
                'class' => SmartUpdateAction::class,
231 1
                'success' => Yii::t('hipanel/server', 'Server was blocked successfully'),
232 1
                'error' => Yii::t('hipanel/server', 'Error during the server blocking'),
233
            ],
234
            'disable-block' => [
235 1
                'class' => SmartUpdateAction::class,
236 1
                'success' => Yii::t('hipanel/server', 'Server was unblocked successfully'),
237 1
                'error' => Yii::t('hipanel/server', 'Error during the server unblocking'),
238
            ],
239
            'refuse' => [
240 1
                'class' => SmartUpdateAction::class,
241 1
                'success' => Yii::t('hipanel/server', 'You have refused the service'),
242 1
                'error' => Yii::t('hipanel/server', 'Error during the refusing the service'),
243
            ],
244
            'enable-autorenewal' => [
245 1
                'class' => SmartUpdateAction::class,
246 1
                'success' => Yii::t('hipanel/server', 'Server renewal enabled successfully'),
247 1
                'error' => Yii::t('hipanel/server', 'Error during the renewing the service'),
248
            ],
249
            'reinstall' => [
250 1
                'class' => SmartUpdateAction::class,
251
                'on beforeSave' => function (Event $event) {
252
                    /** @var Action $action */
253
                    $action = $event->sender;
254
                    foreach ($action->collection->models as $model) {
255
                        $model->osimage = Yii::$app->request->post('osimage');
256
                        $model->panel = Yii::$app->request->post('panel');
257
                    }
258 1
                },
259 1
                'success' => Yii::t('hipanel/server', 'Server reinstalling task has been successfully added to queue'),
260 1
                'error' => Yii::t('hipanel/server', 'Error during the server reinstalling'),
261
            ],
262
            'boot-live' => [
263 1
                'class' => SmartUpdateAction::class,
264
                'on beforeSave' => function (Event $event) {
265
                    /** @var Action $action */
266
                    $action = $event->sender;
267
                    foreach ($action->collection->models as $model) {
268
                        $model->osimage = Yii::$app->request->post('osimage');
269
                    }
270 1
                },
271 1
                'success' => Yii::t('hipanel/server', 'Live CD booting task has been successfully added to queue'),
272 1
                'error' => Yii::t('hipanel/server', 'Error during the booting live CD'),
273
            ],
274
            'validate-form' => [
275
                'class' => ValidateFormAction::class,
276 1
            ],
277
            'buy' => [
278 1
                'class' => RedirectAction::class,
279 1
                'url' => Yii::$app->params['orgUrl'],
280 1
            ],
281
            'add-to-cart-renewal' => [
282
                'class' => AddToCartAction::class,
283
                'productClass' => ServerRenewProduct::class,
284 1
            ],
285
            'delete' => [
286 1
                'class' => SmartDeleteAction::class,
287 1
                'success' => Yii::t('hipanel/server', 'Server was deleted successfully'),
288 1
                'error' => Yii::t('hipanel/server', 'Failed to delete server'),
289
            ],
290
            'bulk-delete-modal' => [
291
                'class' => PrepareBulkAction::class,
292
                'scenario' => 'delete',
293
                'view' => '_bulkDelete',
294 1
            ],
295
            'bulk-enable-block' => [
296 1
                'class' => SmartUpdateAction::class,
297 1
                'scenario' => 'enable-block',
298 1
                'success' => Yii::t('hipanel/server', 'Servers were blocked successfully'),
299 1
                'error' => Yii::t('hipanel/server', 'Error during the servers blocking'),
300
                'POST html' => [
301
                    'save'    => true,
302
                    'success' => [
303
                        'class' => RedirectAction::class,
304
                    ],
305 1
                ],
306
                'on beforeSave' => function (Event $event) {
307
                    /** @var \hipanel\actions\Action $action */
308
                    $action = $event->sender;
309
                    $type = Yii::$app->request->post('type');
310
                    $comment = Yii::$app->request->post('comment');
311
                    if (!empty($type)) {
312
                        foreach ($action->collection->models as $model) {
313
                            $model->setAttributes([
314
                                'type' => $type,
315
                                'comment' => $comment,
316
                            ]);
317
                        }
318
                    }
319 1
                },
320
            ],
321
            'bulk-enable-block-modal' => [
322 1
                'class' => PrepareBulkAction::class,
323 1
                'scenario' => 'enable-block',
324 1
                'view' => '_bulkEnableBlock',
325
                'data' => function ($action, $data) {
326
                    return array_merge($data, [
327
                        'blockReasons' => $this->getBlockReasons(),
328
                    ]);
329 1
                },
330 1
            ],
331
            'bulk-disable-block' => [
332 1
                'class' => SmartUpdateAction::class,
333 1
                'scenario' => 'disable-block',
334 1
                'success' => Yii::t('hipanel/server', 'Servers were unblocked successfully'),
335 1
                'error' => Yii::t('hipanel/server', 'Error during the servers unblocking'),
336
                'POST html' => [
337
                    'save'    => true,
338
                    'success' => [
339
                        'class' => RedirectAction::class,
340
                    ],
341 1
                ],
342
                'on beforeSave' => function (Event $event) {
343
                    /** @var \hipanel\actions\Action $action */
344
                    $action = $event->sender;
345
                    $comment = Yii::$app->request->post('comment');
346
                    if (!empty($type)) {
0 ignored issues
show
Bug introduced by
The variable $type seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
347
                        foreach ($action->collection->models as $model) {
348
                            $model->setAttribute('comment', $comment);
349
                        }
350
                    }
351 1
                },
352
            ],
353
            'bulk-disable-block-modal' => [
354
                'class' => PrepareBulkAction::class,
355
                'scenario' => 'disable-block',
356
                'view' => '_bulkDisableBlock',
357 1
            ],
358
            'set-orientation' => [
359
                'class' => OrientationAction::class,
360
                'allowedRoutes' => [
361
                    '@server/index'
362
                ]
363 1
            ]
364
365 1
        ];
366
    }
367
368
    /**
369
     * Gets info of VNC on the server.
370
     *
371
     * @param Server $model
372
     * @param bool $enable
373
     *
374
     * @return array
375
     */
376
    public function getVNCInfo($model, $enable = false)
377
    {
378
        $vnc['endTime'] = strtotime('+8 hours', strtotime($model->statuses['serverEnableVNC']));
0 ignored issues
show
Documentation introduced by
The property statuses does not exist on object<hipanel\modules\server\models\Server>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Coding Style Comprehensibility introduced by
$vnc was never initialized. Although not strictly required by PHP, it is generally a good practice to add $vnc = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
379
        if (($vnc['endTime'] > time() || $enable) && $model->isOperable()) {
380
            $vnc['enabled'] = true;
381
            $vnc = ArrayHelper::merge($vnc, Server::perform('EnableVNC', ['id' => $model->id]));
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<hipanel\modules\server\models\Server>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
382
        }
383
384
        return $vnc;
385
    }
386
387
    public function actionDrawChart()
388
    {
389
        $post = Yii::$app->request->post();
390
        if (!in_array($post['type'], ['traffic', 'bandwidth'], true)) {
391
            throw new NotFoundHttpException();
392
        }
393
394
        $searchModel = new ServerUseSearch();
395
        $dataProvider = $searchModel->search([]);
396
        $dataProvider->pagination = false;
397
        $dataProvider->query->options = ['scenario' => 'get-uses'];
0 ignored issues
show
Bug introduced by
Accessing options on the interface yii\db\QueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
398
        $dataProvider->query->andWhere($post);
399
        $models = $dataProvider->getModels();
400
401
        list($labels, $data) = ServerHelper::groupUsesForChart($models);
0 ignored issues
show
Documentation introduced by
$models is of type array|null, but the function expects a array<integer,object<hip...rver\models\ServerUse>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
402
403
        return $this->renderAjax('_' . $post['type'] . '_consumption', [
404
            'labels' => $labels,
405
            'data' => $data,
406
        ]);
407
    }
408
409
    /**
410
     * Gets OS images.
411
     *
412
     * @param Server $model
413
     * @throws NotFoundHttpException
414
     * @return array
415
     */
416
    protected function getOsimages(Server $model = null)
417
    {
418
        if ($model !== null) {
419
            $type = $model->type;
0 ignored issues
show
Documentation introduced by
The property type does not exist on object<hipanel\modules\server\models\Server>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
420
        } else {
421
            $type = null;
422
        }
423
424
        $models = ServerHelper::getOsimages($type);
425
426
        if ($models === null) {
427
            throw new NotFoundHttpException('The requested page does not exist.');
428
        }
429
430
        return $models;
431
    }
432
433
    protected function getOsimagesLiveCd()
434
    {
435
        $models = Yii::$app->cache->getTimeCached(3600, [true], function ($livecd) {
436
            return Osimage::findAll(['livecd' => $livecd]);
437
        });
438
439
        if ($models !== null) {
440
            return $models;
441
        }
442
443
        throw new NotFoundHttpException('The requested page does not exist.');
444
    }
445
446
    protected function getPanelTypes()
447
    {
448
        return ServerHelper::getPanels();
449
    }
450
}
451