Passed
Push — develop ( 0715e6...fa87e0 )
by Nikolay
04:58
created

NetworkController::saveLanInterfaces()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 27
rs 9.4222
c 0
b 0
f 0
cc 5
nc 7
nop 1
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright © 2017-2023 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\AdminCabinet\Controllers;
21
22
use MikoPBX\AdminCabinet\Forms\NetworkEditForm;
23
use MikoPBX\Common\Models\LanInterfaces;
24
use MikoPBX\Common\Models\PbxSettings;
25
use MikoPBX\Common\Models\PbxSettingsConstants;
26
use MikoPBX\Core\System\Util;
27
28
class NetworkController extends BaseController
29
{
30
31
    /**
32
     * Lan cards settings form
33
     */
34
    public function modifyAction(): void
35
    {
36
        $networkInterfaces = LanInterfaces::find();
37
        foreach ($networkInterfaces as $record) {
38
            if ($record->disabled !== '1') {
39
                $arrEth[] = $record;
40
            }
41
        }
42
43
        $template = new LanInterfaces();
44
        $template->id = 0;
45
        $template->dhcp = '1';
46
        $template->vlanid = '4095';
47
48
        $arrEth[] = $template;
49
50
        $internetInterface = LanInterfaces::findFirstByInternet('1');
51
        if ($internetInterface === null) {
52
            $internetInterface = new LanInterfaces();
53
            $internetInterface->id = 1;
54
        }
55
56
        // We will find additional interfaces which we can delete
57
        $deletableInterfaces = [];
58
        $countInterfaces = LanInterfaces::count(['group' => 'interface']);
59
        foreach ($countInterfaces as $record) {
60
            if ($record->rowcount > 1) {
61
                $deletableInterfaces[] = $record->interface;
62
            }
63
        }
64
        $form = new NetworkEditForm($internetInterface, ['eths' => $arrEth]);
65
66
        $this->view->setVars(
1 ignored issue
show
Bug introduced by
The method setVars() does not exist on Phalcon\Mvc\ViewInterface. Did you maybe mean setVar()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
        $this->view->/** @scrutinizer ignore-call */ 
67
                     setVars(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
67
            [
68
                'SIP_PORT'=>PbxSettings::getValueByKey(PbxSettingsConstants::SIP_PORT),
69
                'EXTERNAL_SIP_PORT'=>PbxSettings::getValueByKey(PbxSettingsConstants::EXTERNAL_SIP_PORT),
70
                'TLS_PORT'=>PbxSettings::getValueByKey(PbxSettingsConstants::TLS_PORT),
71
                'EXTERNAL_TLS_PORT'=>PbxSettings::getValueByKey(PbxSettingsConstants::EXTERNAL_TLS_PORT),
72
                'RTP_PORT_FROM'=>PbxSettings::getValueByKey(PbxSettingsConstants::RTP_PORT_FROM),
73
                'RTP_PORT_TO'=>PbxSettings::getValueByKey(PbxSettingsConstants::RTP_PORT_TO),
74
                'form'=> $form,
75
                'eths'=>$arrEth,
76
                'deletableEths'=>$deletableInterfaces,
77
                'isDocker'=>Util::isDocker(),
78
                'submitMode'=>null,
79
            ]
80
        );
81
    }
82
83
    /**
84
     * Saves the lan cards settings
85
     */
86
    public function saveAction(): void
87
    {
88
        if (!$this->request->isPost()) {
89
            return;
90
        }
91
92
        $data = $this->request->getPost();
93
        $this->db->begin();
94
95
96
        list($result, $messages)=$this->saveLanInterfaces($data);
97
        if (!$result) {
98
            $this->flash->warning(implode('<br>', $messages));
99
            $this->view->success = false;
100
            $this->db->rollback();
101
            return;
102
        }
103
104
        list($result, $messages)=$this->saveNatSettings($data);
105
        if (!$result) {
106
            $this->flash->warning(implode('<br>', $messages));
107
            $this->view->success = false;
108
            $this->db->rollback();
109
            return;
110
        }
111
112
        $this->view->reload = 'network/modify';
113
        $this->flash->success($this->translation->_('ms_SuccessfulSaved'));
114
        $this->view->success = true;
115
        $this->db->commit();
116
    }
117
118
    /**
119
     * Fills network interface settings
120
     *
121
     * @param LanInterfaces $eth
122
     * @param array $data post data
123
     */
124
    private function fillEthStructure(LanInterfaces $eth, array $data): void
125
    {
126
        $isDocker = Util::isDocker();
127
        foreach ($eth as $name => $value) {
128
            $itIsInternetInterfce = $eth->id === $data['internet_interface'];
129
            switch ($name) {
130
                case 'topology':
131
                    if ($itIsInternetInterfce) {
132
                        $eth->$name = ($data['usenat'] === 'on') ? LanInterfaces::TOPOLOGY_PRIVATE : LanInterfaces::TOPOLOGY_PUBLIC;
133
                    } else {
134
                        $eth->$name = '';
135
                    }
136
                    break;
137
                case 'extipaddr':
138
                    if ($itIsInternetInterfce) {
139
                        if (array_key_exists($name, $data)) {
140
                            $eth->$name = ($data['usenat'] === 'on') ? $data[$name] : $data['ipaddr_' . $eth->id];
141
                        } else {
142
                            $eth->$name = $data['ipaddr_' . $eth->id];
143
                        }
144
                    } else {
145
                        $eth->$name = '';
146
                    }
147
148
                    break;
149
                case 'exthostname':
150
                    if ($itIsInternetInterfce) {
151
                        if (array_key_exists($name, $data)) {
152
                            $eth->$name = ($data['usenat'] === 'on') ? $data[$name] : $data['hostname'];
153
                        } else {
154
                            $eth->$name = $data['hostname'];
155
                        }
156
                    } else {
157
                        $eth->$name = '';
158
                    }
159
                    break;
160
                case 'dhcp':
161
                    if (array_key_exists($name . '_' . $eth->id, $data)) {
162
                        $eth->$name = ($data['dhcp_' . $eth->id]) === 'on' ? '1' : '0';
163
                    }
164
                    if ($isDocker){
165
                        $eth->dhcp = '1';
166
                    }
167
                    break;
168
                case 'internet':
169
                    $eth->$name = $itIsInternetInterfce ? '1' : '0';
170
                    break;
171
                case 'ipaddr':
172
                case 'subnet':
173
                    $eth->$name = '';
174
                    if (array_key_exists($name . '_' . $eth->id, $data)) {
175
                        $eth->$name = ($data['dhcp_' . $eth->id]) === 'on' ? '' : $data[$name . '_' . $eth->id];
176
                    }
177
                    break;
178
                case 'interface':
179
                    if ($eth->id === 0) {
180
                        $eth->$name = LanInterfaces::findFirstById($data[$name . '_' . $eth->id])->interface;
181
                    }
182
                    break;
183
                case 'domain':
184
                case 'hostname':
185
                case 'gateway':
186
                case 'primarydns':
187
                case 'secondarydns':
188
                    if (array_key_exists($name, $data) && $itIsInternetInterfce) {
189
                        $eth->$name = $data[$name];
190
                    } else {
191
                        $eth->$name = '';
192
                    }
193
                    break;
194
                default:
195
                    if (array_key_exists($name . '_' . $eth->id, $data)) {
196
                        $eth->$name = $data[$name . '_' . $eth->id];
197
                    }
198
            }
199
        }
200
    }
201
202
    /**
203
     * Saves the LAN interface configurations.
204
     *
205
     * This method iterates through each existing LAN interface, updates its configuration based on the provided data,
206
     * and saves the changes. If a new interface needs to be added (specified by 'interface_0'), it creates and saves this
207
     * new interface as well. If any save operation fails, the method returns an array containing `false` and the error messages.
208
     *
209
     * @param array $data Array containing the interface configurations.
210
     *                    Expected to contain interface settings such as IP, mask, etc., and a special key 'interface_0' for new interfaces.
211
     * @return array Returns an array with a boolean success flag and an array of error messages if applicable.
212
     */
213
    private function saveLanInterfaces(array $data): array
214
    {
215
        $networkInterfaces = LanInterfaces::find();
216
217
        // Update interface settings
218
        foreach ($networkInterfaces as $eth) {
219
            $this->fillEthStructure($eth, $data);
220
            if ($eth->save() === false) {
221
                $errors = $eth->getMessages();
222
                return [false, $errors];
223
            }
224
        }
225
226
        // Save additional interface settings if it exists
227
        if ($data['interface_0'] !== '') {
228
            $eth = new LanInterfaces();
229
            $eth->id = 0;
230
            $this->fillEthStructure($eth, $data);
231
            $eth->id = null;
232
            $eth->disabled = '0';
233
            if ($eth->create() === false) {
234
                $errors = $eth->getMessages();
235
                return [false, $errors];
236
            }
237
        }
238
239
        return [true, []];
240
    }
241
242
    /**
243
     * Saves the NAT-related settings for external access.
244
     *
245
     * Iterates through a list of predefined setting keys related to NAT configuration (like external SIP and TLS ports),
246
     * and updates these settings with new values from the provided data. If a setting fails to save, the method returns
247
     * immediately with an error.
248
     *
249
     * @param array $data Associative array where keys are setting names and values are the new settings to be saved.
250
     * @return array Returns an array with a boolean success flag and, if unsuccessful, an array of error messages.
251
     */
252
    private function saveNatSettings(array $data): array
253
    {
254
        foreach ($data as $key=>$value) {
255
            switch ($key) {
256
                case PbxSettingsConstants::AUTO_UPDATE_EXTERNAL_IP:
257
                    if (!PbxSettings::setValue($key, $value === 'on' ? '1' : '0')){
258
                            return [false, ['Error on save '.$key]];
259
                    }
260
                    break;
261
                case PbxSettingsConstants::EXTERNAL_SIP_PORT:
262
                case PbxSettingsConstants::EXTERNAL_TLS_PORT:
263
                    if (!PbxSettings::setValue($key, trim($value))) {
264
                        return [false, ['Error on save '.$key]];
265
                    }
266
                break;
267
            default:
268
            }
269
        }
270
        return [true, []];
271
    }
272
273
    /**
274
     * Delete a lan interface by ID
275
     *
276
     * @param string $ethId interface id
277
     */
278
    public function deleteAction(string $ethId = ''): void
279
    {
280
        $eth = LanInterfaces::findFirstById($ethId);
281
        if ($eth !== null && $eth->delete() === false) {
282
            $errors = $eth->getMessages();
283
            $this->flash->warning(implode('<br>', $errors));
284
            $this->view->success = false;
285
            return;
286
        }
287
        $this->view->success = true;
288
    }
289
}
290