maintenance_logs.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <?php
  2. /*
  3. * FusionPBX
  4. * Version: MPL 1.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is FusionPBX
  17. *
  18. * The Initial Developer of the Original Code is
  19. * Mark J Crane <[email protected]>
  20. * Portions created by the Initial Developer are Copyright (C) 2008-2024
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. * Mark J Crane <[email protected]>
  25. * Tim Fry <[email protected]>
  26. */
  27. /**
  28. * Description of maintenance_logs
  29. *
  30. * @author Tim Fry <[email protected]>
  31. */
  32. class maintenance_logs implements database_maintenance {
  33. const APP_NAME = 'maintenance_logs';
  34. const APP_UUID = '5be7b4c2-1a4f-4236-b91a-60e3c33904d7';
  35. const PERMISSION_PREFIX = 'maintenance_log_';
  36. const LIST_PAGE = 'maintenance_logs.php';
  37. const TABLE = 'maintenance_logs';
  38. const UUID_PREFIX = 'maintenance_log_';
  39. const TOGGLE_FIELD = 'maintenance_log_enable';
  40. const TOGGLE_VALUES = ['true', 'false'];
  41. private $database;
  42. private $settings;
  43. private $domain_uuid;
  44. private $user_uuid;
  45. /**
  46. * Called when a database maintenance is triggered from the maintenance service.
  47. * <p>This could be copied and pasted in to any other class that requires database maintenance
  48. * as long as the constant for TABLE exists. Currently most classes would need to be changed from using
  49. * $this->table (only available with an object) to be self::TABLE (available without an object).</p>
  50. */
  51. public static function database_maintenance(settings $settings): void {
  52. //set the table name for this class
  53. $table = self::TABLE;
  54. //get the database used
  55. $database = $settings->database();
  56. //get a list of all domains ignoring the domain_enabled field
  57. $domains = maintenance_service::get_domains($database, true);
  58. //run the maintenance per domain
  59. foreach ($domains as $domain_uuid => $domain_name) {
  60. //get the settings for this domain
  61. $domain_settings = new $settings(['database' => $database, 'domain_uuid' => $domain_uuid]);
  62. //get retention days using the class defined category and subcategory
  63. $retention_days = $domain_settings->get(self::database_maintenance_category(), self::database_maintenance_subcategory(), '');
  64. //ensure there is something to do
  65. if (!empty($retention_days) && is_numeric($retention_days)) {
  66. //delete old entries for this domain
  67. $database->execute("delete from v_{$table} where insert_date < NOW() - INTERVAL '{$retention_days} days' and domain_uuid = '{$domain_uuid}'");
  68. $code = $database->message['code'] ?? 0;
  69. //ensure the removal was successful
  70. if ($database->message['code'] == 200) {
  71. //log success
  72. maintenance_service::log_write(self::class, "Successfully removed entries older than $retention_days", $domain_uuid);
  73. } else {
  74. //log failure
  75. $message = $database->message['message'] ?? "An unknown error has occurred";
  76. maintenance_service::log_write(self::class, "Unable to remove old database records. Error message: $message ($code)", $domain_uuid, maintenance_service::LOG_ERROR);
  77. }
  78. } else {
  79. //database retention not set or not a valid number
  80. maintenance_service::log_write(self::class, 'Retention days not set', '', maintenance_service::LOG_ERROR);
  81. }
  82. }
  83. }
  84. public function __construct(database $database, settings $settings) {
  85. if ($database !== null) {
  86. $this->database = $database;
  87. } else {
  88. $this->database = new $database;
  89. }
  90. $this->domain_uuid = $_SESSION['domain_uuid'] ?? '';
  91. $this->user_uuid = $_SESSION['user_uuid'] ?? '';
  92. if ($settings !== null) {
  93. $this->settings = $settings;
  94. } else {
  95. $this->settings = new settings([
  96. 'database' => $database
  97. , 'domain_uuid' => $this->domain_uuid
  98. , 'user_uuid' => $this->user_uuid
  99. ]);
  100. }
  101. $database->app_name = self::APP_NAME;
  102. $database->app_uuid = self::APP_UUID;
  103. }
  104. /**
  105. * delete records
  106. */
  107. public function delete(array $records) {
  108. //add multi-lingual support
  109. $language = new text;
  110. $text = $language->get();
  111. if (!permission_exists(self::PERMISSION_PREFIX . 'delete') || empty($records)) {
  112. message::add($text['message-no_records'], 'negative');
  113. header('Location: ' . self::LIST_PAGE);
  114. exit;
  115. }
  116. //validate the token
  117. $token = new token;
  118. if (!$token->validate($_SERVER['PHP_SELF'])) {
  119. message::add($text['message-invalid_token'], 'negative');
  120. header('Location: ' . self::LIST_PAGE);
  121. exit;
  122. }
  123. //delete multiple records by building an array of records to remove
  124. $remove_array = [];
  125. foreach ($records as $x => $record) {
  126. if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
  127. $remove_array[self::TABLE][$x][self::UUID_PREFIX . 'uuid'] = $record['uuid'];
  128. }
  129. }
  130. //delete the checked rows
  131. if (!empty($remove_array)) {
  132. //execute delete
  133. $this->database->delete($remove_array);
  134. //set message
  135. message::add($text['message-delete']);
  136. }
  137. }
  138. /**
  139. * toggle records
  140. */
  141. public function toggle(array $records) {
  142. //add multi-lingual support
  143. $language = new text;
  144. $text = $language->get();
  145. //check that we have something to do
  146. if (empty($records) || !permission_exists(self::PERMISSION_PREFIX . 'edit')) {
  147. message::add($text['message-no_records'], 'negative');
  148. header('Location: ' . self::LIST_PAGE);
  149. return;
  150. }
  151. //validate the token
  152. $token = new token;
  153. if (!$token->validate($_SERVER['PHP_SELF'])) {
  154. message::add($text['message-invalid_token'], 'negative');
  155. header('Location: ' . self::LIST_PAGE);
  156. exit;
  157. }
  158. //toggle the checked records to get current toggle state
  159. $uuids = [];
  160. foreach ($records as $x => $record) {
  161. if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
  162. $uuids[] = "'" . $record['uuid'] . "'";
  163. }
  164. }
  165. if (!empty($uuids)) {
  166. $sql = "select " . self::UUID_PREFIX . "uuid as uuid, " . self::TOGGLE_FIELD . " as toggle from v_" . self::TABLE . " ";
  167. $sql .= "where (domain_uuid = :domain_uuid or domain_uuid is null) ";
  168. $sql .= "and " . self::UUID_PREFIX . "uuid in (" . implode(', ', $uuids) . ") ";
  169. $parameters['domain_uuid'] = $this->domain_uuid;
  170. $rows = $this->database->select($sql, $parameters, 'all');
  171. if (!empty($rows)) {
  172. $states = [];
  173. foreach ($rows as $row) {
  174. $states[$row['uuid']] = $row['toggle'];
  175. }
  176. }
  177. }
  178. //build update array
  179. $x = 0;
  180. $array = [];
  181. foreach ($states as $uuid => $state) {
  182. $array[self::TABLE][$x][self::UUID_PREFIX . 'uuid'] = $uuid;
  183. $array[self::TABLE][$x][self::TOGGLE_FIELD] = $state == self::TOGGLE_VALUES[0] ? self::TOGGLE_VALUES[1] : self::TOGGLE_VALUES[0];
  184. $x++;
  185. }
  186. //save the changes
  187. if (!empty($array)) {
  188. //save the array
  189. $database->app_name = self::APP_NAME;
  190. $database->app_uuid = self::APP_UUID;
  191. $this->database->save($array);
  192. //set message
  193. message::add($text['message-toggle']);
  194. }
  195. }
  196. /**
  197. * copy records
  198. */
  199. public function copy(array $records) {
  200. //check that we have something to do
  201. if (empty($records) || !permission_exists(self::PERMISSION_PREFIX . 'add')) {
  202. return;
  203. }
  204. //add multi-lingual support
  205. $language = new text;
  206. $text = $language->get();
  207. //validate the token
  208. $token = new token;
  209. if (!$token->validate($_SERVER['PHP_SELF'])) {
  210. message::add($text['message-invalid_token'], 'negative');
  211. header('Location: ' . self::LIST_PAGE);
  212. exit;
  213. }
  214. //get checked records
  215. $uuids = [];
  216. foreach ($records as $record) {
  217. if (!empty($record['checked']) && $record['checked'] == 'true' && is_uuid($record['uuid'])) {
  218. $uuids[] = "'" . $record['uuid'] . "'";
  219. }
  220. }
  221. //create insert array from existing data
  222. if (!empty($uuids)) {
  223. $sql = "select * from v_" . self::TABLE
  224. . " where (domain_uuid = :domain_uuid or domain_uuid is null)"
  225. . " and " . self::UUID_PREFIX . "uuid in (" . implode(', ', $uuids) . ")";
  226. $parameters['domain_uuid'] = $this->domain_uuid;
  227. $rows = $this->database->select($sql, $parameters, 'all');
  228. if (!empty($rows)) {
  229. $array = [];
  230. foreach ($rows as $x => $row) {
  231. //copy data
  232. $array[self::TABLE][$x] = $row;
  233. //overwrite
  234. $array[self::TABLE][$x][self::UUID_PREFIX . 'uuid'] = uuid();
  235. $array[self::TABLE][$x]['bridge_description'] = trim($row['bridge_description'] . ' (' . $text['label-copy'] . ')');
  236. }
  237. $this->database->save($array);
  238. }
  239. //set message
  240. message::add($text['message-copy']);
  241. }
  242. }
  243. public static function database_maintenance_category(): string {
  244. return "maintenance_logs";
  245. }
  246. public static function database_maintenance_subcategory(): string {
  247. return "database_retention_days";
  248. }
  249. }