Passed
Push — develop ( a56058...ddfce4 )
by Nikolay
04:39
created

RestoreDefaultSettingsAction   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 297
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 34
eloc 166
c 0
b 0
f 0
dl 0
loc 297
rs 9.68

7 Methods

Rating   Name   Duplication   Size   Complexity  
A createParkingSlots() 0 31 5
A cleaningSoundFiles() 0 16 4
A cleaningBackups() 0 9 2
A cleaningOtherExtensions() 0 32 5
B main() 0 85 8
A preCleaning() 0 21 5
A cleaningMainTables() 0 37 5
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\PBXCoreREST\Lib\System;
21
22
use MikoPBX\Common\Models\AsteriskManagerUsers;
23
use MikoPBX\Common\Models\CallQueueMembers;
24
use MikoPBX\Common\Models\CallQueues;
25
use MikoPBX\Common\Models\CustomFiles;
26
use MikoPBX\Common\Models\ExtensionForwardingRights;
27
use MikoPBX\Common\Models\Extensions;
28
use MikoPBX\Common\Models\FirewallRules;
29
use MikoPBX\Common\Models\Iax;
30
use MikoPBX\Common\Models\IncomingRoutingTable;
31
use MikoPBX\Common\Models\IvrMenu;
32
use MikoPBX\Common\Models\IvrMenuActions;
33
use MikoPBX\Common\Models\NetworkFilters;
34
use MikoPBX\Common\Models\OutgoingRoutingTable;
35
use MikoPBX\Common\Models\OutWorkTimes;
36
use MikoPBX\Common\Models\PbxExtensionModules;
37
use MikoPBX\Common\Models\PbxSettings;
38
use MikoPBX\Common\Models\PbxSettingsConstants;
39
use MikoPBX\Common\Models\Sip;
40
use MikoPBX\Common\Models\SoundFiles;
41
use MikoPBX\Common\Models\Users;
42
use MikoPBX\Core\Asterisk\CdrDb;
43
use MikoPBX\Core\System\PBX;
44
use MikoPBX\Core\System\Processes;
45
use MikoPBX\Core\System\SystemMessages;
46
use MikoPBX\Core\System\Upgrade\UpdateDatabase;
47
use MikoPBX\Core\System\Util;
48
use MikoPBX\Modules\PbxExtensionUtils;
49
use MikoPBX\PBXCoreREST\Lib\PBXApiResult;
50
use Phalcon\Di;
51
52
/**
53
 * Returns MikoPBX into default settings stage without any extensions, providers, cdr and sound files
54
 *
55
 * @package MikoPBX\PBXCoreREST\Lib\System
56
 */
57
class RestoreDefaultSettingsAction extends \Phalcon\Di\Injectable
58
{
59
    /**
60
     * Restore default system settings.
61
     *
62
     * @return PBXApiResult An object containing the result of the API call.
63
     */
64
    public static function main(): PBXApiResult
65
    {
66
        $res            = new PBXApiResult();
67
        $res->processor = __METHOD__;
68
        $di             = DI::getDefault();
69
        if ($di === null) {
70
            $res->messages[] = 'Error on DI initialize';
71
            return $res;
72
        }
73
        $rm     = Util::which('rm');
74
        $res->success = true;
75
76
        // Change incoming rule to default action
77
        IncomingRoutingTable::resetDefaultRoute();
78
        self::preCleaning($res);
79
80
        self::cleaningMainTables($res);
81
        self::cleaningOtherExtensions($res);
82
        self::cleaningSoundFiles($res);
83
        self::cleaningBackups();
84
85
        // Delete PbxExtensions modules
86
        $records = PbxExtensionModules::find();
87
        foreach ($records as $record) {
88
            $moduleDir = PbxExtensionUtils::getModuleDir($record->uniqid);
89
            Processes::mwExec("{$rm} -rf {$moduleDir}");
90
            if ( ! $record->delete()) {
91
                $res->messages[] = $record->getMessages();
92
                $res->success    = false;
93
            }
94
        }
95
96
        // Reset PBXSettings
97
        $defaultValues = PbxSettings::getDefaultArrayValues();
98
        $fixedKeys = [
99
            PbxSettingsConstants::PBX_NAME,
100
            PbxSettingsConstants::PBX_DESCRIPTION,
101
            PbxSettingsConstants::SSH_PASSWORD,
102
            PbxSettingsConstants::SSH_RSA_KEY,
103
            PbxSettingsConstants::SSH_DSS_KEY,
104
            PbxSettingsConstants::SSH_AUTHORIZED_KEYS,
105
            PbxSettingsConstants::SSH_ECDSA_KEY,
106
            PbxSettingsConstants::SSH_LANGUAGE,
107
            PbxSettingsConstants::WEB_HTTPS_PUBLIC_KEY,
108
            PbxSettingsConstants::WEB_HTTPS_PRIVATE_KEY,
109
            PbxSettingsConstants::REDIRECT_TO_HTTPS,
110
            PbxSettingsConstants::PBX_LANGUAGE,
111
            PbxSettingsConstants::PBX_VERSION,
112
            PbxSettingsConstants::WEB_ADMIN_LOGIN,
113
            PbxSettingsConstants::WEB_ADMIN_PASSWORD,
114
            PbxSettingsConstants::WEB_ADMIN_LANGUAGE,
115
        ];
116
        foreach ($defaultValues as $key=>$defaultValue){
117
            if (in_array($key, $fixedKeys, true)){
118
                continue;
119
            }
120
            $record = PbxSettings::findFirstByKey($key);
121
            if ($record===null){
122
                $record = new PbxSettings();
123
                $record->key = $key;
124
            }
125
            $record->value = $defaultValue;
126
        }
127
128
        // Delete CallRecords from database
129
        $cdr = CdrDb::getPathToDB();
130
        Processes::mwExec("{$rm} -rf {$cdr}*");
131
        $dbUpdater = new UpdateDatabase();
132
        $dbUpdater->updateDatabaseStructure();
133
134
        // Delete CallRecords sound files
135
        $callRecordsPath = $di->getShared('config')->path('asterisk.monitordir');
136
        if (stripos($callRecordsPath, '/storage/usbdisk1/mikopbx') !== false) {
137
            Processes::mwExec("{$rm} -rf {$callRecordsPath}/*");
138
        }
139
140
        // Recreate parking slots
141
        self::createParkingSlots();
142
143
        // Restart PBX
144
        $pbxConsole = Util::which('pbx-console');
145
        shell_exec("$pbxConsole services restart-all");
146
        PBX::coreRestart();
147
148
        return $res;
149
    }
150
151
    /**
152
     * Perform pre-cleaning operations on specific columns of certain models.
153
     *
154
     * @param PBXApiResult $res The result object to store any error messages.
155
     *
156
     * @return void
157
     */
158
    public static function preCleaning(PBXApiResult &$res):void
159
    {
160
        $preCleaning = [
161
            CallQueues::class => [
162
                'redirect_to_extension_if_empty',
163
                'redirect_to_extension_if_unanswered',
164
                'redirect_to_extension_if_repeat_exceeded'
165
            ],
166
            IvrMenu::class => [
167
                'timeout_extension'
168
            ]
169
        ];
170
        foreach ($preCleaning as $class => $columns) {
171
            $records = call_user_func([$class, 'find']);
172
            foreach ($records as $record){
173
                foreach ($columns as $column){
174
                    $record->$column = '';
175
                }
176
                if ( ! $record->save()) {
177
                    $res->messages[] = $record->getMessages();
178
                    $res->success    = false;
179
                }
180
            }
181
        }
182
    }
183
184
    /**
185
     * Perform cleaning operations on main tables.
186
     *
187
     * @param PBXApiResult $res The result object to store any error messages.
188
     *
189
     * @return void
190
     */
191
    public static function cleaningMainTables(&$res):void
192
    {
193
        // Define the models and conditions for cleaning
194
        $clearThisModels = [
195
            [ExtensionForwardingRights::class => ''],
196
            [OutWorkTimes::class => ''],
197
            [IvrMenuActions::class => ''],
198
            [CallQueueMembers::class => ''],
199
            [OutgoingRoutingTable::class => ''],
200
            [IncomingRoutingTable::class => 'id>1'],
201
            [Sip::class => ''], // All SIP providers
202
            [Iax::class => ''], // All IAX providers
203
            [AsteriskManagerUsers::class => ''],
204
            [Extensions::class => 'type="' . Extensions::TYPE_IVR_MENU . '"'],  // IVR Menu
205
            [Extensions::class => 'type="' . Extensions::TYPE_CONFERENCE . '"'],  // CONFERENCE
206
            [Extensions::class => 'type="' . Extensions::TYPE_QUEUE . '"'],  // QUEUE
207
            [Users::class => 'id>"1"'], // All except root with their extensions
208
            [CustomFiles::class => ''],
209
            [NetworkFilters::class=>'permit!="0.0.0.0/0" AND deny!="0.0.0.0/0"'] //Delete all other rules
210
        ];
211
212
        // Iterate over each model and perform deletion based on conditions
213
        foreach ($clearThisModels as $modelParams) {
214
            foreach ($modelParams as $key => $value) {
215
                $records = call_user_func([$key, 'find'], $value);
216
                if (!$records->delete()) {
217
                    // If deletion fails, add error messages to the result object
218
                    $res->messages[] = $records->getMessages();
219
                    $res->success    = false;
220
                }
221
            }
222
        }
223
        // Allow all connections for 0.0.0.0/0 in firewall rules
224
        $firewallRules = FirewallRules::find();
225
        foreach ($firewallRules as $firewallRule){
226
            $firewallRule->action = 'allow';
227
            $firewallRule->save();
228
        }
229
    }
230
231
    /**
232
     * Perform cleaning operations on other extensions.
233
     *
234
     * @param PBXApiResult $res The result object to store any error messages.
235
     *
236
     * @return void
237
     */
238
    public static function cleaningOtherExtensions(&$res):void
239
    {
240
        // Define the parameters for querying the extensions to delete
241
        $parameters     = [
242
            'conditions' => 'not number IN ({ids:array})',
243
            'bind'       => [
244
                'ids' => [
245
                    '000063',   // Reads back the extension
246
                    '000064',   // 0000MILLI
247
                    '10003246', // Echo test
248
                    IncomingRoutingTable::ACTION_HANGUP,   // System Extension
249
                    IncomingRoutingTable::ACTION_BUSY,     // System Extension
250
                    IncomingRoutingTable::ACTION_DID, // System Extension
251
                    IncomingRoutingTable::ACTION_VOICEMAIL,// System Extension
252
                ],
253
            ],
254
        ];
255
        $stopDeleting   = false;
256
        $countRecords   = Extensions::count($parameters);
257
        $deleteAttempts = 0;
258
        while ($stopDeleting === false) {
259
            $record = Extensions::findFirst($parameters);
260
            if ($record === null) {
261
                $stopDeleting = true;
262
                continue;
263
            }
264
            if ( ! $record->delete()) {
265
                $deleteAttempts += 1;
266
            }
267
            if ($deleteAttempts > $countRecords * 10) {
268
                $stopDeleting    = true; // Prevent loop
269
                $res->messages[] = $record->getMessages();
270
            }
271
        }
272
    }
273
274
    /**
275
     * Clean up custom sound files.
276
     *
277
     * @param PBXApiResult $res The result object to store any error messages.
278
     *
279
     * @return void
280
     */
281
    public static function cleaningSoundFiles(&$res):void
282
    {
283
        $rm     = Util::which('rm');
284
        $parameters = [
285
            'conditions' => 'category = :custom:',
286
            'bind'       => [
287
                'custom' => SoundFiles::CATEGORY_CUSTOM,
288
            ],
289
        ];
290
        $records    = SoundFiles::find($parameters);
291
        foreach ($records as $record) {
292
            if (stripos($record->path, '/storage/usbdisk1/mikopbx') !== false) {
293
                Processes::mwExec("{$rm} -rf {$record->path}");
294
                if ( ! $record->delete()) {
295
                    $res->messages[] = $record->getMessages();
296
                    $res->success    = false;
297
                }
298
            }
299
        }
300
    }
301
302
    /**
303
     * Deletes main database (CF) backups
304
     * @return void
305
     */
306
    public static function cleaningBackups():void
307
    {
308
        $di = Di::getDefault();
309
        $dir = $di->getShared('config')->path('core.mediaMountPoint').'/mikopbx/backup';
310
        if(file_exists($dir)){
311
            $chAttr     = Util::which('chattr');
312
            Processes::mwExec("$chAttr -i -R $dir");
313
            $rm     = Util::which('rm');
314
            Processes::mwExec("$rm -rf $dir/*");
315
        }
316
    }
317
318
    /**
319
     * Create parking extensions.
320
     *
321
     * @return void
322
     */
323
    public static function createParkingSlots()
324
    {
325
        // Delete all parking slots
326
        $currentSlots = Extensions::findByType(Extensions::TYPE_PARKING);
327
        foreach ($currentSlots as $currentSlot) {
328
            if (!$currentSlot->delete()) {
329
                SystemMessages::sysLogMsg(
330
                    __CLASS__,
331
                    'Can not delete extenison ' . $currentSlot->number . ' from \MikoPBX\Common\Models\Extensions ' . implode($currentSlot->getMessages()),
332
                    LOG_ERR
333
                );
334
            }
335
        }
336
337
        $startSlot = intval(PbxSettings::getValueByKey(PbxSettingsConstants::PBX_CALL_PARKING_START_SLOT));
338
        $endSlot = intval(PbxSettings::getValueByKey(PbxSettingsConstants::PBX_CALL_PARKING_END_SLOT));
339
        $reservedSlot = intval(PbxSettings::getValueByKey(PbxSettingsConstants::PBX_CALL_PARKING_EXT));
340
341
        // Create an array of new numbers
342
        $numbers = range($startSlot, $endSlot);
343
        $numbers[] = $reservedSlot;
344
        foreach ($numbers as $number) {
345
            $record = new Extensions();
346
            $record->type = Extensions::TYPE_PARKING;
347
            $record->number = $number;
348
            $record->show_in_phonebook = '0';
349
            if (!$record->create()) {
350
                SystemMessages::sysLogMsg(
351
                    __CLASS__,
352
                    'Can not create extenison ' . $record->number . ' from \MikoPBX\Common\Models\Extensions ' . implode($record->getMessages()),
353
                    LOG_ERR
354
                );
355
            }
356
        }
357
    }
358
359
}