From e8a3c4eb40460681ab33bed7b5c0a2a9a2669af1 Mon Sep 17 00:00:00 2001 From: Ludovic <54670129+lbr38@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:20:01 +0100 Subject: [PATCH] 4.16.0 --- Todolist | 1 - docker/config/nginx/repomanager.conf | 2 +- www/controllers/Api/Host/Host.php | 2 +- www/controllers/Cve/Tools/Import.php | 9 +- www/controllers/Host.php | 263 ++--------------- www/controllers/Host/Package/Event.php | 75 +++++ www/controllers/Host/Package/Package.php | 75 +++++ .../Container/vars/host/packages.vars.inc.php | 22 +- .../Container/vars/host/summary.vars.inc.php | 22 +- .../vars/hosts/overview.vars.inc.php | 5 +- .../Layout/Panel/vars/repos/edit.vars.inc.php | 20 ++ .../vars/host/available-packages.vars.inc.php | 21 +- .../Table/vars/host/history.vars.inc.php | 10 +- www/controllers/Repo/Edit/Form.php | 178 ++++++++++++ www/controllers/Repo/Repo.php | 8 + www/controllers/Repo/Snapshot.php | 15 + www/controllers/Task/Form/Form.php | 4 +- www/controllers/ajax/host.php | 8 +- www/controllers/ajax/repo/edit.php | 19 ++ www/models/Host.php | 267 ++---------------- www/models/Host/Package/Event.php | 81 ++++++ www/models/Host/Package/Package.php | 150 ++++++++++ www/models/Host/Request.php | 38 +-- www/models/Repo/Repo.php | 17 ++ www/models/Repo/Snapshot.php | 13 + www/public/assets/icons/arrow-back.svg | 106 ------- www/public/assets/icons/rollback.svg | 38 +++ www/public/assets/icons/update-red.svg | 38 +++ www/public/assets/icons/update-yellow.svg | 38 +++ www/public/resources/js/events/repo/edit.js | 101 +++++++ www/public/resources/js/host.js | 2 +- www/public/resources/js/task.js | 78 +++-- www/public/resources/styles/common.css | 2 +- www/public/resources/styles/stats-hosts.css | 3 - www/update/database/4.16.0.php | 44 +++ www/version | 2 +- .../includes/containers/host/packages.inc.php | 36 +-- .../includes/containers/hosts/list.inc.php | 11 +- www/views/includes/footer.inc.php | 2 +- www/views/includes/forms/edit.inc.php | 72 +++++ .../host/package/event-details.inc.php | 19 ++ .../includes/host/package/timeline.inc.php | 65 +++++ .../includes/labels/label-icon-tr.inc.php | 11 + www/views/includes/panels/repos/edit.inc.php | 9 + .../includes/tables/host/history.inc.php | 62 +++- .../includes/tables/host/requests.inc.php | 12 +- 46 files changed, 1306 insertions(+), 770 deletions(-) create mode 100644 www/controllers/Host/Package/Event.php create mode 100644 www/controllers/Host/Package/Package.php create mode 100644 www/controllers/Layout/Panel/vars/repos/edit.vars.inc.php create mode 100644 www/controllers/Repo/Edit/Form.php create mode 100644 www/controllers/Repo/Snapshot.php create mode 100644 www/controllers/ajax/repo/edit.php create mode 100644 www/models/Host/Package/Event.php create mode 100644 www/models/Host/Package/Package.php create mode 100644 www/models/Repo/Snapshot.php delete mode 100644 www/public/assets/icons/arrow-back.svg create mode 100644 www/public/assets/icons/rollback.svg create mode 100644 www/public/assets/icons/update-red.svg create mode 100644 www/public/assets/icons/update-yellow.svg create mode 100644 www/public/resources/js/events/repo/edit.js create mode 100644 www/update/database/4.16.0.php create mode 100644 www/views/includes/forms/edit.inc.php create mode 100644 www/views/includes/host/package/event-details.inc.php create mode 100644 www/views/includes/host/package/timeline.inc.php create mode 100644 www/views/includes/labels/label-icon-tr.inc.php create mode 100644 www/views/includes/panels/repos/edit.inc.php diff --git a/Todolist b/Todolist index fc4c05a5..5ccd7179 100644 --- a/Todolist +++ b/Todolist @@ -6,7 +6,6 @@ [ REPOS ] - Think about a way to publish debian repos in a more elegant way. Currently: https:///repo/debian/dists/buster/main_prod buster main_prod - - (Feature) Add a way to edit repository properties like its source repository - (Feature) Support Arch Linux packages https://blog.desdelinux.net/en/create-your-local-arch-linux-repository/ https://wiki.archlinux.org/title/Pacman#Repositories_and_mirrors diff --git a/docker/config/nginx/repomanager.conf b/docker/config/nginx/repomanager.conf index 24393fe6..bc496c32 100644 --- a/docker/config/nginx/repomanager.conf +++ b/docker/config/nginx/repomanager.conf @@ -102,7 +102,7 @@ server { location ~ \.(?:css|js|woff2?|svg|gif|map)$ { try_files $uri $uri/ =404; - add_header Cache-Control "public, max-age=15778463"; + add_header Cache-Control "public, max-age=3600"; add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; add_header Referrer-Policy "no-referrer" always; add_header X-Content-Type-Options "nosniff" always; diff --git a/www/controllers/Api/Host/Host.php b/www/controllers/Api/Host/Host.php index 11ed8aef..f95f4dfd 100644 --- a/www/controllers/Api/Host/Host.php +++ b/www/controllers/Api/Host/Host.php @@ -99,7 +99,7 @@ public function execute() * https://repomanager.mydomain.net/api/v2/host/registering */ if ($this->component == 'registering' and $this->method == 'DELETE') { - $myhost->unregister(); + $myhost->delete($myhost->getId()); return array('message' => array('Host has been deleted.')); } diff --git a/www/controllers/Cve/Tools/Import.php b/www/controllers/Cve/Tools/Import.php index c7c0b573..9e2818d2 100644 --- a/www/controllers/Cve/Tools/Import.php +++ b/www/controllers/Cve/Tools/Import.php @@ -447,12 +447,12 @@ public function importAffectedHosts() /** * Open host database */ - $myhost->openHostDb($host['Id']); + $hostPackageController = new \Controllers\Host\Package\Package($host['Id']); /** * Get list of all installed packages on this host */ - $installedPackages = $myhost->getPackagesInstalled($host['Id']); + $installedPackages = $hostPackageController->getInstalled(); $installedPackagesArray = array(); foreach ($installedPackages as $package) { @@ -470,11 +470,6 @@ public function importAffectedHosts() 'Os_family' => $hostOsFamily, 'Installed_packages' => $installedPackagesArray ); - - /** - * Close host database - */ - $myhost->closeHostDb(); } /** diff --git a/www/controllers/Host.php b/www/controllers/Host.php index f10615e5..b02a857c 100644 --- a/www/controllers/Host.php +++ b/www/controllers/Host.php @@ -188,31 +188,6 @@ public function getHostWithProfile(string $profile) return $this->model->getHostWithProfile($profile); } - /** - * Récupère la liste des paquets présents sur l'hôte - */ - public function getPackagesInventory() - { - return $this->model->getPackagesInventory(); - } - - /** - * Retourne les paquets installés sur l'hôte - */ - public function getPackagesInstalled() - { - return $this->model->getPackagesInstalled(); - } - - /** - * Retrieve the list of packages available for update on the host - * It is possible to add an offset to the request - */ - public function getPackagesAvailable(bool $withOffset = false, int $offset = 0) - { - return $this->model->getPackagesAvailable($withOffset, $offset); - } - /** * Retrieve the list of requests sent to the host * It is possible to add an offset to the request @@ -230,15 +205,6 @@ public function getLastPendingRequest(int $id) return $this->model->getLastPendingRequest($id); } - /** - * Retrieve information about all actions performed on host packages (install, update, remove...) - * It is possible to add an offset to the request - */ - public function getEventsHistory(bool $withOffset = false, int $offset = 0) - { - return $this->model->getEventsHistory($withOffset, $offset); - } - /** * Récupère la liste des paquets issus d'un évènemnt et dont l'état des paquets est défini par $packageState (installed, upgraded, removed) * Les informations sont récupérées à la fois dans la table packages et dans packages_history @@ -248,189 +214,6 @@ public function getEventPackagesList(string $eventId, string $packageState) return $this->model->getEventPackagesList($eventId, $packageState); } - /** - * Récupère le détails d'un évènement sur un type de paquets en particulier (installés, mis à jour, etc...) - * Cette fonction est notamment déclenchée au passage de la souris sur une ligne de l'historique des évènements - */ - public function getEventDetails(string $id, string $eventId, string $packageState) - { - /** - * Si il manque l'id de l'hôte, on quitte car on en a besoin pour ouvrir sa BDD dédiée - */ - if (empty($id)) { - throw new Exception('Host Id must be specified'); - } - - $packageState = \Controllers\Common::validateData($packageState); - - /** - * Ouverture de la BDD dédiée de l'hôte - */ - $this->model->openHostDb($id); - - $packages = $this->model->getEventDetails($eventId, $packageState); - - if ($packageState == 'installed') { - $content = '

Installed:

'; - } - if ($packageState == 'dep-installed') { - $content = '

Installed dependencies:

'; - } - if ($packageState == 'upgraded') { - $content = '

Updated:

'; - } - if ($packageState == 'removed') { - $content = '

Uninstalled:

'; - } - if ($packageState == 'downgraded') { - $content = '

Downgraded:

'; - } - - $content .= '
'; - - foreach ($packages as $package) { - $content .= '
'; - $content .= \Controllers\Common::printProductIcon($package['Name']); - $content .= '' . $package['Name'] . ''; - $content .= '
'; - $content .= '' . $package['Version'] . ''; - } - - $content .= '
'; - - return $content; - } - - /** - * Retrieve the complete history of a package (its installation, its updates, etc...) - */ - public function getPackageTimeline(string $id, string $packageName) - { - /** - * If the host id is missing, we quit because we need it to open its dedicated DB - */ - if (empty($id)) { - throw new Exception('Host Id must be specified'); - } - - /** - * Open the dedicated DB of the host - */ - $this->model->openHostDb($id); - - $events = $this->model->getPackageTimeline($packageName); - - /** - * Build the timeline to display and send it back to the ajax controller because it is jquery that will take care of displaying it afterwards - */ - $content = '
'; - - /** - * The first block will be displayed on the left in the timeline - */ - $contentPosition = 'left'; - - foreach ($events as $event) { - /** - * Add the date, time and state of the package - */ - if ($event['State'] == "inventored") { - $contentIcon = 'package'; - $contentText = 'Inventored'; - } - if ($event['State'] == "installed") { - $contentIcon = 'down'; - $contentText = 'Installed'; - } - if ($event['State'] == "dep-installed") { - $contentIcon = 'down'; - $contentText = 'Installed (as depencency)'; - } - if ($event['State'] == "upgraded") { - $contentIcon = 'update'; - $contentText = 'Updated'; - } - if ($event['State'] == "removed") { - $contentIcon = 'delete'; - $contentText = 'Uninstalled'; - } - if ($event['State'] == "downgraded") { - $contentIcon = 'arrow-back'; - $contentText = 'Downgraded'; - } - if ($event['State'] == "reinstalled") { - $contentIcon = 'down'; - $contentText = 'Reinstalled'; - } - if ($event['State'] == "purged") { - $contentIcon = 'delete'; - $contentText = 'Uninstalled (purged)'; - } - - /** - * Position of the container block in the timeline according to the last displayed - */ - $content .= '
'; - - /** - * Display the date, time and state of the package - */ - $content .= '
'; - $content .= ''; - $content .= '
'; - $content .= '

' . DateTime::createFromFormat('Y-m-d', $event['Date'])->format('d-m-Y') . '

'; - $content .= '

' . $event['Time'] . '

'; - $content .= '
'; - $content .= '
'; - $content .= '

' . $contentText . '

'; - $content .= '

Version: ' . $event['Version'] . '

'; - $content .= '
'; - $content .= '
'; - - /** - * If this event is the result of an update, install or uninstall event, then we indicate the Id of the event - */ - // if (!empty($event['Id_event'])) { - // $content .= ''; - // } - - /** - * If the previous block was on the left, we display the next one on the right and vice versa - */ - if ($contentPosition == "left") { - $contentPosition = 'right'; - } elseif ($contentPosition == "right") { - $contentPosition = 'left'; - } - - $content .= '
'; - } - - /** - * Close the timeline - */ - $content .= '
'; - - return $content; - } - - /** - * Compte le nombre de paquets installés, mis à jour, désinstallés... au cours des X derniers jours. - * Retourne un array contenant les dates => nombre de paquet - * Fonction utilisées notamment pour la création du graphique ChrtJS de type 'line' sur la page d'un hôte - */ - public function getLastPackagesStatusCount(string $status, string $days) - { - if ($status != 'installed' and $status != 'upgraded' and $status != 'removed') { - throw new Exception("Invalid status"); - } - - $dateEnd = date('Y-m-d'); - $dateStart = date_create($dateEnd)->modify("-${days} days")->format('Y-m-d'); - - return $this->model->getLastPackagesStatusCount($status, $dateStart, $dateEnd); - } - /** * Edit the display settings on the hosts page */ @@ -998,9 +781,9 @@ public function register() /** * Lorsque appelé par l'api, HOSTS_DIR n'est pas setté, donc on le fait */ - if (!defined('HOSTS_DIR')) { - define('HOSTS_DIR', ROOT . '/hosts'); - } + // if (!defined('HOSTS_DIR')) { + // define('HOSTS_DIR', DATA_DIR . '/hosts'); + // } /** * Si on n'a pas renseigné l'IP ou le hostname alors on quitte @@ -1083,9 +866,9 @@ public function register() */ } else { /** - * Ajout de l'hôte en base de données + * Add the host in database */ - $this->model->addHost($this->ip, $this->hostname, $this->authId, $this->token, $this->onlineStatus, date('Y-m-d'), date('H:i:s')); + $this->model->add($this->ip, $this->hostname, $this->authId, $this->token, $this->onlineStatus, date('Y-m-d'), date('H:i:s')); /** * Récupération de l'Id de l'hôte ajouté en BDD @@ -1118,14 +901,30 @@ public function register() } /** - * Suppression d'un hôte depuis l'api + * Delete a host from the database */ - public function unregister() + public function delete(int $id) { + $hostRequestController = new \Controllers\Host\Request(); + /** - * Changement du status de l'hôte en base de données ('deleted') + * Delete host from database */ - $this->model->setHostInactive($this->id); + $this->model->delete($id); + + /** + * Add a new ws request to disconnect the host + */ + $hostRequestController->new($id, 'disconnect'); + + /** + * Delete host's dedicated database + */ + if (is_dir(HOSTS_DIR . '/' . $id)) { + \Controllers\Filesystem\Directory::deleteRecursive(HOSTS_DIR . '/' . $id); + } + + unset($hostRequestController); } /** @@ -1211,20 +1010,10 @@ public function hostExec(array $hostsId, string $action) * Case where the requested action is a delete */ if ($action == 'delete') { - /** - * First, reset host data in database - */ - $this->model->resetHost($hostId); - /** * Set host status to 'deleted' in database */ - $this->model->setHostInactive($hostId); - - /** - * Add a new ws request to disconnect the host - */ - $hostRequestController->new($hostId, 'disconnect'); + $this->delete($hostId); } /** diff --git a/www/controllers/Host/Package/Event.php b/www/controllers/Host/Package/Event.php new file mode 100644 index 00000000..4b63dba4 --- /dev/null +++ b/www/controllers/Host/Package/Event.php @@ -0,0 +1,75 @@ +hostId = $hostId; + $this->model = new \Models\Host\Package\Event($hostId); + } + + /** + * Retrieves the details of an event for a specific type of packages (installed, updated, etc...) + * This function is triggered when hovering over a line in the event history + */ + public function getDetails(string $eventId, string $packageState) : string + { + $packageState = \Controllers\Common::validateData($packageState); + + /** + * Retrieve the details of the event + */ + $packages = $this->model->getDetails($eventId, $packageState); + + if ($packageState == 'installed') { + $title = 'INSTALLED'; + $icon = 'check.svg'; + } + if ($packageState == 'reinstalled') { + $title = 'REINSTALLED'; + $icon = 'check.svg'; + } + if ($packageState == 'dep-installed') { + $title = 'DEPENDENCIES INSTALLED'; + $icon = 'check.svg'; + } + if ($packageState == 'upgraded') { + $title = 'UPDATED'; + $icon = 'update-yellow.svg'; + } + if ($packageState == 'removed') { + $title = 'UNINSTALLED'; + $icon = 'error.svg'; + } + if ($packageState == 'purged') { + $title = 'PURGED'; + $icon = 'error.svg'; + } + if ($packageState == 'downgraded') { + $title = 'DOWNGRADED'; + $icon = 'rollback.svg'; + } + + ob_start(); + + include_once(ROOT . '/views/includes/host/package/event-details.inc.php'); + + return ob_get_clean(); + } + + /** + * Retrieve informations about all actions performed on host packages (install, update, remove...) + * It is possible to add an offset to the request + */ + public function getHistory(bool $withOffset = false, int $offset = 0) : array + { + return $this->model->getHistory($withOffset, $offset); + } +} diff --git a/www/controllers/Host/Package/Package.php b/www/controllers/Host/Package/Package.php new file mode 100644 index 00000000..73516230 --- /dev/null +++ b/www/controllers/Host/Package/Package.php @@ -0,0 +1,75 @@ +model = new \Models\Host\Package\Package($hostId); + } + + /** + * Retrieve the list of inventoried packages on the host + */ + public function getInventory() : array + { + return $this->model->getInventory(); + } + + /** + * Retrieve the list of installed packages on the host + */ + public function getInstalled() : array + { + return $this->model->getInstalled(); + } + + /** + * Retrieve the list of packages available for update on the host + * It is possible to add an offset to the request + */ + public function getAvailable(bool $withOffset = false, int $offset = 0) : array + { + return $this->model->getAvailable($withOffset, $offset); + } + + /** + * Retrieve the complete history of a package (its installation, its updates, etc...) + */ + public function getTimeline(string $packageName) : string + { + /** + * Retrieve the events of the package + */ + $events = $this->model->getTimeline($packageName); + + ob_start(); + + include_once(ROOT . '/views/includes/host/package/timeline.inc.php'); + + return ob_get_clean(); + } + + /** + * Count the number of packages installed, updated, removed... over the last X days. + * Returns an array containing dates => number of packages + * Function used notably for creating the ChartJS 'line' chart on the host page + */ + public function countByStatusOverDays(string $status, string $days) : array + { + if ($status != 'installed' and $status != 'upgraded' and $status != 'removed') { + throw new Exception("Invalid status"); + } + + $dateEnd = date('Y-m-d'); + $dateStart = date_create($dateEnd)->modify("-${days} days")->format('Y-m-d'); + + return $this->model->countByStatusOverDays($status, $dateStart, $dateEnd); + } +} diff --git a/www/controllers/Layout/Container/vars/host/packages.vars.inc.php b/www/controllers/Layout/Container/vars/host/packages.vars.inc.php index 4c015c77..5f6c68b0 100644 --- a/www/controllers/Layout/Container/vars/host/packages.vars.inc.php +++ b/www/controllers/Layout/Container/vars/host/packages.vars.inc.php @@ -1,12 +1,7 @@ openHostDb($id); +$hostPackageController = new \Controllers\Host\Package\Package($id); +$myhost = new \Controllers\Host(); /** * Getting hosts general threshold settings @@ -26,17 +21,12 @@ /** * Getting installed packages and its total */ -$packagesInventored = $myhost->getPackagesInventory(); -$packagesInstalledCount = count($myhost->getPackagesInstalled()); +$packagesInventored = $hostPackageController->getInventory(); +$packagesInstalledCount = count($hostPackageController->getInstalled()); /** * Getting available packages and its total */ -$packagesAvailableTotal = count($myhost->getPackagesAvailable()); - -/** - * Close host database - */ -$myhost->closeHostDb(); +$packagesAvailableTotal = count($hostPackageController->getAvailable()); -unset($myhost); +unset($myhost, $hostPackageController); diff --git a/www/controllers/Layout/Container/vars/host/summary.vars.inc.php b/www/controllers/Layout/Container/vars/host/summary.vars.inc.php index 3ae55410..997f9f53 100644 --- a/www/controllers/Layout/Container/vars/host/summary.vars.inc.php +++ b/www/controllers/Layout/Container/vars/host/summary.vars.inc.php @@ -1,6 +1,4 @@ openHostDb($id); - /** * First create a list of dates on a 15days period */ @@ -76,17 +71,17 @@ /** * Getting last 15days installed packages */ -$lastInstalledPackagesArray = $myhost->getLastPackagesStatusCount('installed', '15'); +$lastInstalledPackagesArray = $hostPackageController->countByStatusOverDays('installed', '15'); /** * Getting last 15days updated packages */ -$lastUpgradedPackagesArray = $myhost->getLastPackagesStatusCount('upgraded', '15'); +$lastUpgradedPackagesArray = $hostPackageController->countByStatusOverDays('upgraded', '15'); /** * Getting last 15days deleted packages */ -$lastRemovedPackagesArray = $myhost->getLastPackagesStatusCount('removed', '15'); +$lastRemovedPackagesArray = $hostPackageController->countByStatusOverDays('removed', '15'); /** * Merging all arrays with dates array @@ -104,9 +99,4 @@ $lineChartRemovedPackagesCount = "'" . implode("','", $lastRemovedPackagesArray) . "'"; $lineChartDates = "'" . implode("','", array_keys($dates)) . "'"; -/** - * Close host database - */ -$myhost->closeHostDb(); - -unset($myhost); +unset($myhost, $hostPackageController, $hostProperties, $dates, $dateStart, $dateEnd, $period, $lastInstalledPackagesArray, $lastUpgradedPackagesArray, $lastRemovedPackagesArray); diff --git a/www/controllers/Layout/Container/vars/hosts/overview.vars.inc.php b/www/controllers/Layout/Container/vars/hosts/overview.vars.inc.php index f91ea277..e7c55993 100644 --- a/www/controllers/Layout/Container/vars/hosts/overview.vars.inc.php +++ b/www/controllers/Layout/Container/vars/hosts/overview.vars.inc.php @@ -42,16 +42,17 @@ * Open the dedicated database of the host from its ID to be able to retrieve additional information */ $myhost->openHostDb($host['Id']); + $hostPackageController = new \Controllers\Host\Package\Package($host['Id']); /** * Retrieve the total number of available packages */ - $packagesAvailableTotal = count($myhost->getPackagesAvailable()); + $packagesAvailableTotal = count($hostPackageController->getAvailable()); /** * Retrieve the total number of installed packages */ - $packagesInstalledTotal = count($myhost->getPackagesInstalled()); + $packagesInstalledTotal = count($hostPackageController->getInstalled()); /** * If the total number of available packages retrieved previously is > $packagesCountConsideredOutdated (threshold defined by the user) then we increment $totalNotUptodate (counts the number of hosts that are not up to date in the chartjs) diff --git a/www/controllers/Layout/Panel/vars/repos/edit.vars.inc.php b/www/controllers/Layout/Panel/vars/repos/edit.vars.inc.php new file mode 100644 index 00000000..52133003 --- /dev/null +++ b/www/controllers/Layout/Panel/vars/repos/edit.vars.inc.php @@ -0,0 +1,20 @@ +get(json_decode($item['repos'], true)); diff --git a/www/controllers/Layout/Table/vars/host/available-packages.vars.inc.php b/www/controllers/Layout/Table/vars/host/available-packages.vars.inc.php index b2d6ebf6..fa2bf735 100644 --- a/www/controllers/Layout/Table/vars/host/available-packages.vars.inc.php +++ b/www/controllers/Layout/Table/vars/host/available-packages.vars.inc.php @@ -1,13 +1,7 @@ openHostDb($id); +$hostPackageController = new \Controllers\Host\Package\Package($id); +$reloadableTableOffset = 0; /** * Retrieve offset from cookie if exists @@ -19,12 +13,12 @@ /** * Get list of available packages updates, with offset */ -$reloadableTableContent = $myhost->getPackagesAvailable(true, $reloadableTableOffset); +$reloadableTableContent = $hostPackageController->getAvailable(true, $reloadableTableOffset); /** * Get list of ALL available packages updates, without offset, for the total count */ -$reloadableTableTotalItems = count($myhost->getPackagesAvailable()); +$reloadableTableTotalItems = count($hostPackageController->getAvailable()); /** * Count total pages for the pagination @@ -36,9 +30,4 @@ */ $reloadableTableCurrentPage = ceil($reloadableTableOffset / 10) + 1; -/** - * Close host database - */ -$myhost->closeHostDb(); - -unset($myhost); +unset($hostPackageController); diff --git a/www/controllers/Layout/Table/vars/host/history.vars.inc.php b/www/controllers/Layout/Table/vars/host/history.vars.inc.php index 9b68006a..6ebf0a7b 100644 --- a/www/controllers/Layout/Table/vars/host/history.vars.inc.php +++ b/www/controllers/Layout/Table/vars/host/history.vars.inc.php @@ -3,6 +3,7 @@ $reloadableTableOffset = 0; $id = __ACTUAL_URI__[2]; +$hostPackageEventController = new \Controllers\Host\Package\Event($id); /** * Open host database @@ -19,7 +20,7 @@ /** * Get list of packages events history, with offset */ -$events = $myhost->getEventsHistory(true, $reloadableTableOffset); +$events = $hostPackageEventController->getHistory(true, $reloadableTableOffset); /** * For each event, get the installed, updated, downgraded and removed packages @@ -32,6 +33,11 @@ */ $event['PackagesInstalled'] = $myhost->getEventPackagesList($event['Id'], 'installed'); + /** + * Getting reinstalled packages from this event + */ + $event['PackagesReinstalled'] = $myhost->getEventPackagesList($event['Id'], 'reinstalled'); + /** * Getting isntalled dependencies packages from this event */ @@ -68,7 +74,7 @@ /** * Get list of ALL events, without offset, for the total count */ -$reloadableTableTotalItems = count($myhost->getEventsHistory()); +$reloadableTableTotalItems = count($hostPackageEventController->getHistory()); /** * Count total pages for the pagination diff --git a/www/controllers/Repo/Edit/Form.php b/www/controllers/Repo/Edit/Form.php new file mode 100644 index 00000000..6b33607d --- /dev/null +++ b/www/controllers/Repo/Edit/Form.php @@ -0,0 +1,178 @@ +listAll('rpm'); + $newRepoDebSourcesList = $mysource->listAll('deb'); + + $content = '
'; + + foreach ($repos as $repo) { + $repoController = new \Controllers\Repo\Repo(); + $repoId = \Controllers\Common::validateData($repo['repo-id']); + $snapId = \Controllers\Common::validateData($repo['snap-id']); + + /** + * Check that the Ids are numeric + */ + if (!is_numeric($repoId)) { + throw new Exception('Repository Id is invalid'); + } + if (!is_numeric($snapId)) { + throw new Exception('Snapshot Id is invalid'); + } + + /** + * Check that the Ids exist in the database + */ + if (!$repoController->existsId($repoId)) { + throw new Exception('Repository Id does not exist'); + } + if (!$repoController->existsSnapId($snapId)) { + throw new Exception('Snapshot Id does not exist'); + } + + /** + * Retrieve all repo data from the Ids + */ + $repoController->getAllById($repoId, $snapId); + + /** + * Retrieve the package type of the repo + */ + $packageType = $repoController->getPackageType(); + + /** + * Build the form from a template + */ + ob_start(); + + echo '
'; + + /** + * Include form template + */ + include(ROOT . '/views/includes/forms/edit.inc.php'); + + echo '
'; + + echo '

'; + + $content .= ob_get_clean(); + } + + $content .= '


'; + $content .= ''; + + return $content; + } + + /** + * Validate the edit form filled by the user + * TODO : on utilise les mêmes controllers de vérification utilisés dans \Controllers\Task\Form\Form(), à refacto + */ + public function validate(array $params) : void + { + foreach ($params as $param) { + $repoController = new \Controllers\Repo\Repo(); + + if (empty($param['repo-id'])) { + throw new Exception('Repository Id is missing'); + } + + if (empty($param['snap-id'])) { + throw new Exception('Snapshot Id is missing'); + } + + /** + * Check that the snapshot id is valid + */ + \Controllers\Task\Form\Param\Snapshot::checkId($param['snap-id']); + + /** + * Retrieve all repo data from the Ids + */ + // $repoController->setSnapId($param['snap-id']); + $repoController->getAllById($param['repo-id'], $param['snap-id']); + + /** + * Check that the selected source repository is valid + */ + if ($repoController->getType() == 'mirror') { + \Controllers\Task\Form\Param\Source::check($param['source'], $repoController->getPackageType()); + } + + /** + * Check that the specified description is valid + * Description cannot contain single quotes or backslashes + * TODO: no editable description for now + */ + // if (str_contains($param['description'], "'") || str_contains($param['description'], "\\")) { + // throw new Exception('Description contains invalid characters'); + // } + // $description = \Controllers\Common::validateData($param['description']); + } + } + + /** + * Edit the repositories + */ + public function edit(array $params) : void + { + $historyController = new \Controllers\History(); + $layoutContainerReloadController = new \Controllers\Layout\ContainerReload(); + + foreach ($params as $param) { + $repoController = new \Controllers\Repo\Repo(); + + /** + * Retrieve all repo data from the Ids + */ + $repoController->getAllById($param['repo-id'], $param['snap-id']); + + /** + * Update repository source + */ + if ($repoController->getType() == 'mirror') { + $repoController->updateSource($param['repo-id'], $param['source']); + } + + /** + * Update snapshot description + * TODO: no editable description for now + */ + // $repoController->updateDescription($param['snap-id'], $description); + // $snapshotController->updateDescription($param['snap-id'], $description); + + /** + * Add history + */ + if ($repoController->getPackageType() == 'rpm') { + $historyController->set($_SESSION['username'], 'Editing ' . $repoController->getName() . ' repository properties (' . $repoController->getType() . ')', 'success'); + } + if ($repoController->getPackageType() == 'deb') { + $historyController->set($_SESSION['username'], 'Editing ' . $repoController->getName() . ' ❯ ' . $repoController->getDist() . ' ❯ ' . $repoController->getSection() . ' repository properties (' . $repoController->getType() . ')', 'success'); + } + + /** + * Reload repositories list + */ + $layoutContainerReloadController->reload('repos/list'); + } + } +} diff --git a/www/controllers/Repo/Repo.php b/www/controllers/Repo/Repo.php index 28e91f4d..9cb18173 100644 --- a/www/controllers/Repo/Repo.php +++ b/www/controllers/Repo/Repo.php @@ -888,4 +888,12 @@ public function updateSection(int $repoId, string $section) { $this->model->updateSection($repoId, $section); } + + /** + * Update source repository in database + */ + public function updateSource(int $repoId, string $source) + { + $this->model->updateSource($repoId, $source); + } } diff --git a/www/controllers/Repo/Snapshot.php b/www/controllers/Repo/Snapshot.php new file mode 100644 index 00000000..df8fe4c0 --- /dev/null +++ b/www/controllers/Repo/Snapshot.php @@ -0,0 +1,15 @@ +model = new \Models\Repo\Snapshot(); + } +} diff --git a/www/controllers/Task/Form/Form.php b/www/controllers/Task/Form/Form.php index 6a9ac9a9..21bc4ddb 100644 --- a/www/controllers/Task/Form/Form.php +++ b/www/controllers/Task/Form/Form.php @@ -11,12 +11,12 @@ class Form /** * Return the task form to the user according to his selection */ - public function get(string $action, array $repos) + public function get(string $action, array $repos) : string { $mylogin = new \Controllers\Login(); $usersEmail = $mylogin->getEmails(); - $content = '
'; + $content = ''; foreach ($repos as $repo) { $myrepo = new \Controllers\Repo\Repo(); diff --git a/www/controllers/ajax/host.php b/www/controllers/ajax/host.php index c231d877..1ce3912b 100644 --- a/www/controllers/ajax/host.php +++ b/www/controllers/ajax/host.php @@ -130,10 +130,10 @@ * Get package history timeline */ if ($action == "getPackageTimeline" and !empty($_POST['hostid']) and !empty($_POST['packagename'])) { - $myhost = new \Controllers\Host(); + $hostPackageController = new \Controllers\Host\Package\Package($_POST['hostid']); try { - $content = $myhost->getPackageTimeline($_POST['hostid'], $_POST['packagename']); + $content = $hostPackageController->getTimeline($_POST['packagename']); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } @@ -145,10 +145,10 @@ * Get event details (installed packages, updated packages...) */ if ($action == "getEventDetails" and !empty($_POST['hostId']) and !empty($_POST['eventId']) and !empty($_POST['packageState'])) { - $myhost = new \Controllers\Host(); + $hostPackageEventController = new \Controllers\Host\Package\Event($_POST['hostId']); try { - $content = $myhost->getEventDetails($_POST['hostId'], $_POST['eventId'], $_POST['packageState']); + $content = $hostPackageEventController->getDetails($_POST['eventId'], $_POST['packageState']); } catch (\Exception $e) { response(HTTP_BAD_REQUEST, $e->getMessage()); } diff --git a/www/controllers/ajax/repo/edit.php b/www/controllers/ajax/repo/edit.php new file mode 100644 index 00000000..b6582e2f --- /dev/null +++ b/www/controllers/ajax/repo/edit.php @@ -0,0 +1,19 @@ +validate($params); + $repoEditForm->edit($params); + } catch (Exception $e) { + response(HTTP_BAD_REQUEST, $e->getMessage()); + } + + response(HTTP_OK, 'Successfully edited.'); +} + +response(HTTP_BAD_REQUEST, 'Invalid action'); diff --git a/www/models/Host.php b/www/models/Host.php index 8c353f0a..2fec1d59 100644 --- a/www/models/Host.php +++ b/www/models/Host.php @@ -1017,102 +1017,6 @@ public function setSettings(string $packagesConsideredOutdated, string $packages } } - /** - * Récupère la liste des paquets présents sur l'hôte - */ - public function getPackagesInventory() - { - /** - * Si la BDD dédiée à l'hôte n'est pas instanciée dans $this->dedicatedDb alors on quitte - */ - if (empty($this->dedicatedDb)) { - return false; - } - - /** - * Récupération du total des paquets installés sur l'hôte - */ - $datas = array(); - - try { - $result = $this->dedicatedDb->query("SELECT * FROM packages ORDER BY Name ASC"); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $datas[] = $row; - } - - return $datas; - } - - /** - * Retourne les paquets installés sur l'hôte - */ - public function getPackagesInstalled() - { - /** - * Si la BDD dédiée à l'hôte n'est pas instanciée dans $this->dedicatedDb alors on quitte - */ - if (empty($this->dedicatedDb)) { - return false; - } - - /** - * Récupération du total des paquets installés sur l'hôte - */ - $datas = array(); - - try { - $result = $this->dedicatedDb->query("SELECT * FROM packages WHERE State = 'inventored' or State = 'installed' or State = 'dep-installed' or State = 'upgraded' or State = 'downgraded'"); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $datas[] = $row; - } - - return $datas; - } - - /** - * Retrieve the list of packages available for update on the host - * It is possible to add an offset to the request - */ - public function getPackagesAvailable(bool $withOffset, int $offset) - { - $data = array(); - - try { - $query = "SELECT * FROM packages_available"; - - /** - * Add offset if needed - */ - if ($withOffset === true) { - $query .= " LIMIT 10 OFFSET :offset"; - } - - /** - * Prepare query - */ - $stmt = $this->dedicatedDb->prepare($query); - $stmt->bindValue(':offset', $offset, SQLITE3_INTEGER); - - $result = $stmt->execute(); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $data[] = $row; - } - - return $data; - } - /** * Retrieve the list of requests sent to the host * It is possible to add an offset to the request @@ -1172,46 +1076,6 @@ public function getLastPendingRequest(int $id) return $data; } - /** - * Retrieve information about all actions performed on host packages (install, update, remove...) - * It is possible to add an offset to the request - */ - public function getEventsHistory(bool $withOffset, int $offset) - { - $data = array(); - - try { - $query = "SELECT * FROM events ORDER BY Date DESC, Time DESC"; - - /** - * Add offset if needed - */ - if ($withOffset === true) { - $query .= " LIMIT 10 OFFSET :offset"; - } - - /** - * Prepare query - */ - $stmt = $this->dedicatedDb->prepare($query); - $stmt->bindValue(':offset', $offset, SQLITE3_INTEGER); - - $result = $stmt->execute(); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - /** - * Add a column Event_type to the result to define that it is an 'event'. Will be useful when displaying data. - */ - $row['Event_type'] = 'event'; - $data[] = $row; - } - - return $data; - } - /** * Récupère la liste des paquets issus d'un évènemnt et dont l'état des paquets est défini par $packageState (installed, upgraded, removed) * Les informations sont récupérées à la fois dans la table packages et dans packages_history @@ -1247,104 +1111,6 @@ public function getEventPackagesList(string $eventId, string $packageState) return $datas; } - /** - * Récupère le détails d'un évènement sur un type de paquets en particulier (installés, mis à jour, etc...) - * Cette fonction est notamment déclenchée au passage de la souris sur une ligne de l'historique des évènements - */ - public function getEventDetails(string $eventId, string $packageState) - { - try { - $stmt = $this->dedicatedDb->prepare("SELECT Name, Version FROM packages - WHERE Id_event = :id_event and State = :state - UNION - SELECT Name, Version FROM packages_history - WHERE Id_event = :id_event and State = :state"); - $stmt->bindValue(':id_event', \Controllers\Common::validateData($eventId)); - $stmt->bindValue(':state', \Controllers\Common::validateData($packageState)); - $result = $stmt->execute(); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - $packages = array(); - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $packages[] = $row; - } - - $this->dedicatedDb->close(); - - return $packages; - } - - /** - * Récupère l'historique complet d'un paquet (son installation, ses mises à jour, etc...) - */ - public function getPackageTimeline(string $packageName) - { - $events = array(); - - /** - * Récupération de l'historique du paquet (table packages_history) ainsi que son état actuel (table packages) - */ - try { - $stmt = $this->dedicatedDb->prepare("SELECT * FROM packages_history - WHERE Name = :packagename - UNION SELECT * FROM packages - WHERE Name = :packagename - ORDER BY Date DESC, Time DESC"); - $stmt->bindValue(':packagename', $packageName); - $result = $stmt->execute(); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $events[] = $row; - } - - return $events; - } - - /** - * Compte le nombre de paquets installés, mis à jour, désinstallés... au cours des X derniers jours. - * Retourne un array contenant les dates => nombre de paquet - * Fonction utilisées notamment pour la création du graphique ChrtJS de type 'line' sur la page d'un hôte - */ - public function getLastPackagesStatusCount(string $status, string $dateStart, string $dateEnd) - { - /** - * Si la BDD dédiée à l'hôte n'est pas instanciée dans $this->dedicatedDb alors on quitte - */ - if (empty($this->dedicatedDb)) { - return false; - } - - try { - $stmt = $this->dedicatedDb->prepare("SELECT Date, COUNT(*) as date_count FROM packages WHERE State = :status and Date BETWEEN :dateStart and :dateEnd GROUP BY Date - UNION - SELECT Date, COUNT(*) as date_count FROM packages_history WHERE State = :status and Date BETWEEN :dateStart and :dateEnd GROUP BY Date"); - $stmt->bindValue(':status', $status); - $stmt->bindValue(':dateStart', $dateStart); - $stmt->bindValue(':dateEnd', $dateEnd); - $result = $stmt->execute(); - } catch (\Exception $e) { - $this->dedicatedDb->logError($e); - } - - $array = array(); - - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - if (!array_key_exists($row['Date'], $array)) { - $array[$row['Date']] = $row['date_count']; - } else { - $array[$row['Date']] += $row['date_count']; - } - } - - return $array; - } - /** * Return the hostname of the host by its Id */ @@ -1410,9 +1176,9 @@ public function getHostStatus(string $hostname) } /** - * Ajout d'un nouvel hôte en base de données + * Add a new host in database */ - public function addHost(string $ip, string $hostname, string $authId, string $token, string $onlineStatus, string $date, string $time) + public function add(string $ip, string $hostname, string $authId, string $token, string $onlineStatus, string $date, string $time) { try { $stmt = $this->db->prepare("INSERT INTO hosts (Ip, Hostname, AuthId, Token, Online_status, Online_status_date, Online_status_time, Status) VALUES (:ip, :hostname, :id, :token, :online_status, :date, :time, 'active')"); @@ -1429,6 +1195,20 @@ public function addHost(string $ip, string $hostname, string $authId, string $to } } + /** + * Delete a host from database + */ + public function delete(int $id) : void + { + try { + $stmt = $this->db->prepare("DELETE FROM hosts WHERE Id = :id"); + $stmt->bindValue(':id', $id); + $stmt->execute(); + } catch (Exception $e) { + $this->db->logError($e); + } + } + /** * Mise à jour d'un hôte en base de données */ @@ -1449,21 +1229,6 @@ public function updateHost(string $ip, string $hostname, string $authId, string } } - /** - * Désactive un hôte en base de données - * Pour identifier l'hôte on peut soit spécifier son Id, soit ses informations d'identification - */ - public function setHostInactive(string $hostId) - { - try { - $stmt = $this->db->prepare("UPDATE hosts SET Status = 'deleted', AuthId = null, Token = null WHERE id = :hostId"); - $stmt->bindValue(':hostId', $hostId); - $stmt->execute(); - } catch (\Exception $e) { - $this->db->logError($e); - } - } - /** * Reset host data */ diff --git a/www/models/Host/Package/Event.php b/www/models/Host/Package/Event.php new file mode 100644 index 00000000..ced93e26 --- /dev/null +++ b/www/models/Host/Package/Event.php @@ -0,0 +1,81 @@ +getConnection('host', $hostId); + } + + /** + * Retrieves the details of an event for a specific type of packages (installed, updated, etc...) + */ + public function getDetails(string $eventId, string $packageState) : array + { + $data = array(); + + try { + $stmt = $this->dedicatedDb->prepare("SELECT Name, Version FROM packages + WHERE Id_event = :id_event and State = :state + UNION + SELECT Name, Version FROM packages_history + WHERE Id_event = :id_event and State = :state"); + $stmt->bindValue(':id_event', \Controllers\Common::validateData($eventId)); + $stmt->bindValue(':state', \Controllers\Common::validateData($packageState)); + $result = $stmt->execute(); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $data[] = $row; + } + + return $data; + } + + /** + * Retrieve informations about all actions performed on host packages (install, update, remove...) + * It is possible to add an offset to the request + */ + public function getHistory(bool $withOffset, int $offset) : array + { + $data = array(); + + try { + $query = "SELECT * FROM events ORDER BY Date DESC, Time DESC"; + + /** + * Add offset if needed + */ + if ($withOffset === true) { + $query .= " LIMIT 10 OFFSET :offset"; + } + + /** + * Prepare query + */ + $stmt = $this->dedicatedDb->prepare($query); + $stmt->bindValue(':offset', $offset, SQLITE3_INTEGER); + + $result = $stmt->execute(); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + /** + * Add a column Event_type to the result to define that it is an 'event'. Will be useful when displaying data. + */ + $row['Event_type'] = 'event'; + $data[] = $row; + } + + return $data; + } +} diff --git a/www/models/Host/Package/Package.php b/www/models/Host/Package/Package.php new file mode 100644 index 00000000..1b358312 --- /dev/null +++ b/www/models/Host/Package/Package.php @@ -0,0 +1,150 @@ +getConnection('host', $hostId); + } + + /** + * Retrieve the list of inventoried packages in database + */ + public function getInventory() : array + { + $datas = array(); + + try { + $result = $this->dedicatedDb->query("SELECT * FROM packages ORDER BY Name ASC"); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $datas[] = $row; + } + + return $datas; + } + + /** + * Retrieve the list of installed packages in database + */ + public function getInstalled() : array + { + $datas = array(); + + try { + $result = $this->dedicatedDb->query("SELECT * FROM packages WHERE State = 'inventored' or State = 'installed' or State = 'dep-installed' or State = 'upgraded' or State = 'downgraded'"); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $datas[] = $row; + } + + return $datas; + } + + /** + * Retrieve the list of packages available for update in database + * It is possible to add an offset to the request + */ + public function getAvailable(bool $withOffset, int $offset) : array + { + $data = array(); + + try { + $query = "SELECT * FROM packages_available"; + + /** + * Add offset if needed + */ + if ($withOffset === true) { + $query .= " LIMIT 10 OFFSET :offset"; + } + + /** + * Prepare query + */ + $stmt = $this->dedicatedDb->prepare($query); + $stmt->bindValue(':offset', $offset, SQLITE3_INTEGER); + + $result = $stmt->execute(); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $data[] = $row; + } + + return $data; + } + + /** + * Retrieve the complete history of a package (its installation, its updates, etc...) + */ + public function getTimeline(string $package) : array + { + $events = array(); + + try { + $stmt = $this->dedicatedDb->prepare("SELECT * FROM packages_history + WHERE Name = :package + UNION SELECT * FROM packages + WHERE Name = :package + ORDER BY Date DESC, Time DESC"); + $stmt->bindValue(':package', $package); + $result = $stmt->execute(); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $events[] = $row; + } + + return $events; + } + + /** + * Count the number of packages installed, updated, removed... over the last X days. + */ + public function countByStatusOverDays(string $status, string $dateStart, string $dateEnd) : array + { + $array = array(); + + try { + $stmt = $this->dedicatedDb->prepare("SELECT Date, COUNT(*) as date_count FROM packages + WHERE State = :status and Date BETWEEN :dateStart and :dateEnd + GROUP BY Date + UNION + SELECT Date, COUNT(*) as date_count FROM packages_history + WHERE State = :status and Date BETWEEN :dateStart and :dateEnd + GROUP BY Date"); + $stmt->bindValue(':status', $status); + $stmt->bindValue(':dateStart', $dateStart); + $stmt->bindValue(':dateEnd', $dateEnd); + $result = $stmt->execute(); + } catch (Exception $e) { + $this->dedicatedDb->logError($e); + } + + while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + if (!array_key_exists($row['Date'], $array)) { + $array[$row['Date']] = $row['date_count']; + } else { + $array[$row['Date']] += $row['date_count']; + } + } + + return $array; + } +} diff --git a/www/models/Host/Request.php b/www/models/Host/Request.php index a6864d38..603b68c3 100644 --- a/www/models/Host/Request.php +++ b/www/models/Host/Request.php @@ -17,7 +17,7 @@ public function __construct() /** * Add a new request in database */ - public function new(int $hostId, string $request) + public function new(int $hostId, string $request) : void { try { $stmt = $this->db->prepare("INSERT INTO requests ('Date', 'Time', 'Request', 'Status', 'Retry', 'Id_host') VALUES (:date, :time, :request, 'new', '0', :hostId)"); @@ -26,7 +26,7 @@ public function new(int $hostId, string $request) $stmt->bindValue(':request', $request); $stmt->bindValue(':hostId', $hostId); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -34,7 +34,7 @@ public function new(int $hostId, string $request) /** * Return all requests from database */ - public function get(string|null $status) + public function get(string|null $status) : array { $requests = array(); @@ -49,7 +49,7 @@ public function get(string|null $status) $stmt = $this->db->prepare("SELECT * FROM requests ORDER BY Date DESC, Time DESC"); } $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } @@ -63,7 +63,7 @@ public function get(string|null $status) /** * Update request in database */ - public function update(int $id, string $status, string $info, string $responseJson) + public function update(int $id, string $status, string $info, string $responseJson) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Status = :status, Info = :info, Response_json = :responseJson WHERE Id = :id"); @@ -72,7 +72,7 @@ public function update(int $id, string $status, string $info, string $responseJs $stmt->bindValue(':responseJson', $responseJson); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -80,14 +80,14 @@ public function update(int $id, string $status, string $info, string $responseJs /** * Update request status in database */ - public function updateStatus(int $id, string $status) + public function updateStatus(int $id, string $status) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Status = :status WHERE Id = :id"); $stmt->bindValue(':status', $status); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -95,14 +95,14 @@ public function updateStatus(int $id, string $status) /** * Update request info message in database */ - public function updateInfo(int $id, string $info) + public function updateInfo(int $id, string $info) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Info = :info WHERE Id = :id"); $stmt->bindValue(':info', $info); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -110,14 +110,14 @@ public function updateInfo(int $id, string $info) /** * Update request retry in database */ - public function updateRetry(int $id, int $retry) + public function updateRetry(int $id, int $retry) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Retry = :retry WHERE Id = :id"); $stmt->bindValue(':retry', $retry); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -125,14 +125,14 @@ public function updateRetry(int $id, int $retry) /** * Update request next retry time in database */ - public function updateNextRetry(int $id, string $nextRetry) + public function updateNextRetry(int $id, string $nextRetry) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Next_retry = :nextRetry WHERE Id = :id"); $stmt->bindValue(':nextRetry', $nextRetry); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -140,13 +140,13 @@ public function updateNextRetry(int $id, string $nextRetry) /** * Cancel request in database */ - public function cancel(int $id) + public function cancel(int $id) : void { try { $stmt = $this->db->prepare("UPDATE requests SET Status = 'canceled', Info = Info || ' (canceled)' WHERE Id = :id"); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -154,13 +154,13 @@ public function cancel(int $id) /** * Delete request from database */ - public function delete(int $id) + public function delete(int $id) : void { try { $stmt = $this->db->prepare("DELETE FROM requests WHERE Id = :id"); $stmt->bindValue(':id', $id); $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } } @@ -199,7 +199,7 @@ public function getRequestPackageLog(int $id, string $package, string $status) : $stmt->bindValue(':path', '$.update.' . $status . '.packages."' . $package . '".log'); $stmt->bindValue(':id', $id); $result = $stmt->execute(); - } catch (\Exception $e) { + } catch (Exception $e) { $this->db->logError($e); } diff --git a/www/models/Repo/Repo.php b/www/models/Repo/Repo.php index 71c581ab..456c2420 100644 --- a/www/models/Repo/Repo.php +++ b/www/models/Repo/Repo.php @@ -1151,4 +1151,21 @@ public function updateSection(int $repoId, string $section) unset($stmt); } + + /** + * Update source repository in database + */ + public function updateSource(int $repoId, string $source) + { + try { + $stmt = $this->db->prepare("UPDATE repos SET Source = :source WHERE Id = :repoId"); + $stmt->bindValue(':source', $source); + $stmt->bindValue(':repoId', $repoId); + $stmt->execute(); + } catch (Exception $e) { + $this->db->logError($e); + } + + unset($stmt); + } } diff --git a/www/models/Repo/Snapshot.php b/www/models/Repo/Snapshot.php new file mode 100644 index 00000000..e3885ec0 --- /dev/null +++ b/www/models/Repo/Snapshot.php @@ -0,0 +1,13 @@ +getConnection('main'); + } +} diff --git a/www/public/assets/icons/arrow-back.svg b/www/public/assets/icons/arrow-back.svg deleted file mode 100644 index 5bca6394..00000000 --- a/www/public/assets/icons/arrow-back.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/www/public/assets/icons/rollback.svg b/www/public/assets/icons/rollback.svg new file mode 100644 index 00000000..e97a24c1 --- /dev/null +++ b/www/public/assets/icons/rollback.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/www/public/assets/icons/update-red.svg b/www/public/assets/icons/update-red.svg new file mode 100644 index 00000000..b5b44cb9 --- /dev/null +++ b/www/public/assets/icons/update-red.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/www/public/assets/icons/update-yellow.svg b/www/public/assets/icons/update-yellow.svg new file mode 100644 index 00000000..cb9c8d5f --- /dev/null +++ b/www/public/assets/icons/update-yellow.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/www/public/resources/js/events/repo/edit.js b/www/public/resources/js/events/repo/edit.js new file mode 100644 index 00000000..76feae4b --- /dev/null +++ b/www/public/resources/js/events/repo/edit.js @@ -0,0 +1,101 @@ +/** + * Event: submit reposiroty edit form + */ +$(document).on('submit','#edit-form',function () { + event.preventDefault(); + + /** + * Main array that will contain all the parameters of each repo to be processed (1 or more repos depending on the user's selection) + */ + var params = []; + + /** + * Retrieve the parameters entered in the form + */ + $(this).find('.edit-form-params').each(function () { + /** + * Object that will contain the parameters entered in the form for this repo + */ + var obj = {}; + + /** + * Retrieve the repo-id and snap-id of the repo to be processed + */ + obj['repo-id'] = $(this).attr('repo-id'); + obj['snap-id'] = $(this).attr('snap-id'); + + /** + * Retrieve the parameters entered by the user and push them into the object + * There is no associative array in js so we push an object. + */ + $(this).find('.edit-param').each(function () { + /** + * Retrieve the parameter name (input name) and its value (input value) + */ + var param_name = $(this).attr('param-name'); + + /** + * If the input is a checkbox and it is checked then its value will be 'true' + * If it is not checked then its value will be 'false' + */ + if ($(this).attr('type') == 'checkbox') { + if ($(this).is(":checked")) { + var param_value = 'true'; + } else { + var param_value = 'false'; + } + + /** + * If the input is a radio button then we only retrieve its value if it is checked, otherwise we move on to the next parameter + */ + } else if ($(this).attr('type') == 'radio') { + if ($(this).is(":checked")) { + var param_value = $(this).val(); + } else { + return; // return is the equivalent of 'continue' for jquery loops .each() + } + } else { + /** + * If the input is not a checkbox then we retrieve its value + */ + var param_value = $(this).val(); + } + + obj[param_name] = param_value; + }); + + /** + * Push each repo parameter into the main array + */ + params.push(obj); + }); + + /** + * Convert the main array to JSON format and send it to php for verification of the parameters + */ + var paramsJson = JSON.stringify(params); + + // for debug only + // console.log(paramsJson); + + ajaxRequest( + // Controller: + 'repo/edit', + // Action: + 'validateForm', + // Data: + { + params: paramsJson, + }, + // Print success alert: + true, + // Print error alert: + true + ).then(function () { + // Uncheck all checkboxes and remove all styles JQuery could have applied + $('.reposList').find('input[name=checkbox-repo]').prop('checked', false); + $('.reposList').find('input[name=checkbox-repo]').removeAttr('style'); + }); + + return false; +}); diff --git a/www/public/resources/js/host.js b/www/public/resources/js/host.js index 838ecc15..eaa77e63 100644 --- a/www/public/resources/js/host.js +++ b/www/public/resources/js/host.js @@ -927,7 +927,7 @@ $(document).on('mouseenter', '.event-packages-btn', function (e) { /** * Create a new
event-packages-details */ - $('footer').append('
Loading
'); + $('footer').append('

Loading

'); /** * Get screen width diff --git a/www/public/resources/js/task.js b/www/public/resources/js/task.js index 7edac784..4c7e66b2 100644 --- a/www/public/resources/js/task.js +++ b/www/public/resources/js/task.js @@ -190,11 +190,6 @@ $(document).on('click',"input[name=checkbox-repo]",function () { */ var count_checked = $('.reposList').find('input[name=checkbox-repo]:checked').length; - /** - * Define if 'Update' action is available in the action buttons - */ - var updateAction = true; - /** * If all checkboxes are unchecked then we hide all action buttons */ @@ -205,33 +200,20 @@ $(document).on('click',"input[name=checkbox-repo]",function () { return; } - /** - * If a 'local' repo is checked then we hide the 'update' button - */ - if ($('.reposList').find('input[name=checkbox-repo][repo-type=local]:checked').length > 0) { - // TODO: avoid displaying the Update button when a local repo is selected - // updateAction = false; - // closeConfirmBox(); - } - /** * Define confirm box buttons */ var buttons = []; - // If 'update' action is available then we add the 'update' button. This happens when no 'local' repo is checked - if (updateAction) { - buttons.push({ + // Add all other buttons + buttons.push( + { 'text': 'Update', 'color': 'blue-alt', 'callback': function () { executeAction('update') } - }); - } - - // Add all other buttons - buttons.push( + }, { 'text': 'Duplicate', 'color': 'blue-alt', @@ -253,6 +235,13 @@ $(document).on('click',"input[name=checkbox-repo]",function () { executeAction('rebuild'); } }, + { + 'text': 'Edit', + 'color': 'blue-alt', + 'callback': function () { + executeAction('edit') + } + }, { 'text': 'Delete', 'color': 'red', @@ -311,12 +300,21 @@ function executeAction(action) var repos = JSON.stringify(repos); /** - * Get the panel and form for the selected action + * If the action is 'edit', then get the edit panel */ - getPanel('repos/task', { - action: action, - repos: repos - }); + if (action == 'edit') { + getPanel('repos/edit', { + repos: repos + }); + /** + * Otherwise, get the task panel for the selected action + */ + } else { + getPanel('repos/task', { + action: action, + repos: repos + }); + } } /** @@ -420,7 +418,7 @@ $(document).on('click',".task-schedule-btn", function () { /** * Event: submit task form */ -$(document).on('submit','.task-form',function () { +$(document).on('submit','#task-form',function () { event.preventDefault(); /** @@ -481,7 +479,7 @@ $(document).on('submit','.task-form',function () { var taskParams = []; /** - * Retrive the parameters entered in the form + * Retrieve the parameters entered in the form */ $(this).find('.task-form-params').each(function () { /** @@ -594,18 +592,16 @@ $(document).on('submit','.task-form',function () { true, // Print error alert: true, - // Reload container: - [], - // Execute functions on success: - [ - 'closePanel()', - // Uncheck all checkboxes and remove all styles JQuery could have applied - "$('.reposList').find('input[name=checkbox-repo]').prop('checked', false);", - "$('.reposList').find('input[name=checkbox-repo]').removeAttr('style');", - // Reload right panel - "reloadContainer('repos/properties')" - ] - ); + ).then(function () { + closePanel(); + + // Uncheck all checkboxes and remove all styles JQuery could have applied + $('.reposList').find('input[name=checkbox-repo]').prop('checked', false); + $('.reposList').find('input[name=checkbox-repo]').removeAttr('style'); + + // Reload right panel + reloadContainer('repos/properties'); + }); return false; }); diff --git a/www/public/resources/styles/common.css b/www/public/resources/styles/common.css index e56a3b55..2dbb7666 100644 --- a/www/public/resources/styles/common.css +++ b/www/public/resources/styles/common.css @@ -589,7 +589,7 @@ input[type=checkbox]:not(.onoff-switch-input):checked { background-color: #f10e4b; } .slide-btn-yellow { - background-color: #eb984e; + background-color: #ffb536; } .slide-btn-yellow:hover { background-color: #eb984e; diff --git a/www/public/resources/styles/stats-hosts.css b/www/public/resources/styles/stats-hosts.css index 37a2f933..374501c4 100644 --- a/www/public/resources/styles/stats-hosts.css +++ b/www/public/resources/styles/stats-hosts.css @@ -172,9 +172,6 @@ -webkit-box-shadow: 0px 10px 13px -12px #000000, 0px 0px 10px 2px rgba(0,0,0,0.15); box-shadow: 0px 10px 13px -12px #000000, 0px 0px 10px 2px rgb(0 0 0 / 15%); } -.event-packages-details p { - margin-bottom: 5px; -} #hosts-requiring-reboot-chart-list, .hosts-charts-list-label-hosts-list { flex-direction: column; diff --git a/www/update/database/4.16.0.php b/www/update/database/4.16.0.php new file mode 100644 index 00000000..0b71310f --- /dev/null +++ b/www/update/database/4.16.0.php @@ -0,0 +1,44 @@ +query("SELECT Id FROM hosts WHERE Status = 'deleted'"); + +while ($row = $result->fetchArray(SQLITE3_ASSOC)) { + $deletedHosts[] = $row['Id']; +} + +if (empty($deletedHosts)) { + return; +} + +/** + * Clean all dedicated databases for deleted hosts + */ +foreach ($deletedHosts as $hostId) { + if (is_dir(HOSTS_DIR . '/' . $hostId)) { + \Controllers\Filesystem\Directory::deleteRecursive(HOSTS_DIR . '/' . $hostId); + } +} + +/** + * Remove all deleted hosts from database + */ +$hostsDb->exec("DELETE FROM hosts WHERE Status = 'deleted'"); diff --git a/www/version b/www/version index d78433cb..2c9aebff 100644 --- a/www/version +++ b/www/version @@ -1 +1 @@ -4.15.2 \ No newline at end of file +4.16.0 \ No newline at end of file diff --git a/www/views/includes/containers/host/packages.inc.php b/www/views/includes/containers/host/packages.inc.php index c9407df9..0eb68fd9 100644 --- a/www/views/includes/containers/host/packages.inc.php +++ b/www/views/includes/containers/host/packages.inc.php @@ -2,25 +2,29 @@
PACKAGES INVENTORY

Packages installed and available updates.

-
+
-
INSTALLED
- +
+ +
-
-
TO UPDATE
- - = $pkgs_count_considered_critical) { - $labelColor = 'red'; - } elseif ($packagesAvailableTotal >= $pkgs_count_considered_outdated) { - $labelColor = 'yellow'; - } ?> - - +
+
+ = $pkgs_count_considered_critical) { + $icon = 'update-red.svg'; + } elseif ($packagesAvailableTotal >= $pkgs_count_considered_outdated) { + $icon = 'update-yellow.svg'; + } + include(ROOT . '/views/includes/labels/label-icon-tr.inc.php'); ?> +
diff --git a/www/views/includes/containers/hosts/list.inc.php b/www/views/includes/containers/hosts/list.inc.php index 7b57f9f4..a269fb50 100644 --- a/www/views/includes/containers/hosts/list.inc.php +++ b/www/views/includes/containers/hosts/list.inc.php @@ -217,28 +217,23 @@ /** * Open the dedicated database of the host from its ID to be able to retrieve additional information */ - $hostDb->openHostDb($id); + $hostPackageController = new \Controllers\Host\Package\Package($id); /** * Retrieve the total number of available packages */ - $packagesAvailableTotal = count($hostDb->getPackagesAvailable()); + $packagesAvailableTotal = count($hostPackageController->getAvailable()); /** * Retrieve the total number of installed packages */ - $packagesInstalledTotal = count($hostDb->getPackagesInstalled()); + $packagesInstalledTotal = count($hostPackageController->getInstalled()); /** * Retrieve the last pending request (if there is one) */ $lastPendingRequest = $myhost->getLastPendingRequest($id); - /** - * Close the dedicated database of the host - */ - $hostDb->closeHostDb(); - /** * Print the host informations * Here the
will contain all the host informations in order to be able to search on it (input 'search a host') diff --git a/www/views/includes/footer.inc.php b/www/views/includes/footer.inc.php index 55dc65a0..2756a6f4 100644 --- a/www/views/includes/footer.inc.php +++ b/www/views/includes/footer.inc.php @@ -53,7 +53,7 @@ * Additional JS files */ if (__ACTUAL_URI__[1] == '') { - $jsFiles = ['repo', 'task', 'group', 'source', 'events/repo/source/distribution', 'events/repo/source/releasever', 'events/repo/source/source']; + $jsFiles = ['repo', 'task', 'group', 'source', 'events/repo/source/distribution', 'events/repo/source/releasever', 'events/repo/source/source', 'events/repo/edit']; } if (__ACTUAL_URI__[1] == 'hosts') { $jsFiles = ['host', 'events/host/layout', 'events/host/actions', 'events/profile/actions']; diff --git a/www/views/includes/forms/edit.inc.php b/www/views/includes/forms/edit.inc.php new file mode 100644 index 00000000..f4bacee1 --- /dev/null +++ b/www/views/includes/forms/edit.inc.php @@ -0,0 +1,72 @@ +
REPOSITORY
+getPackageType() == 'rpm') { + echo '' . $repoController->getName() . ''; +} +if ($repoController->getPackageType() == 'deb') { + echo '' . $repoController->getName() . ' ❯ ' . $repoController->getDist() . ' ❯ ' . $repoController->getSection() . ''; +} ?> + +getType() == 'mirror') : ?> +
SOURCE REPOSITORY
+

The repository to mirror from. Want more? Add or import a source repository.

+ + getPackageType() == 'rpm') { + if (empty($newRepoRpmSourcesList)) { + echo '

No rpm source repositories available. Please add a source repository first.

'; + } + + if (!empty($newRepoRpmSourcesList)) : ?> + + getPackageType() == 'deb') { + if (empty($newRepoDebSourcesList)) { + echo '

No deb source repositories available. Please add a source repository first.

'; + } + + if (!empty($newRepoDebSourcesList)) : ?> + + + + + +
SNAPSHOT
+getDateFormatted() ?> + +

Nothing editable for now but it will be soon!

diff --git a/www/views/includes/host/package/event-details.inc.php b/www/views/includes/host/package/event-details.inc.php new file mode 100644 index 00000000..4deb3063 --- /dev/null +++ b/www/views/includes/host/package/event-details.inc.php @@ -0,0 +1,19 @@ +
+ +
+
+ +

package(s)

+ +
+ +
+ +

+
+ +

+ +
diff --git a/www/views/includes/host/package/timeline.inc.php b/www/views/includes/host/package/timeline.inc.php new file mode 100644 index 00000000..1593163f --- /dev/null +++ b/www/views/includes/host/package/timeline.inc.php @@ -0,0 +1,65 @@ +
+ + +
+
+ + +
+

format('d-m-Y') ?>

+

+
+ +
+
+

+
+
+ + +
+ +
diff --git a/www/views/includes/labels/label-icon-tr.inc.php b/www/views/includes/labels/label-icon-tr.inc.php new file mode 100644 index 00000000..0e028e27 --- /dev/null +++ b/www/views/includes/labels/label-icon-tr.inc.php @@ -0,0 +1,11 @@ +
+ +
+

+ +

+ +
+
\ No newline at end of file diff --git a/www/views/includes/panels/repos/edit.inc.php b/www/views/includes/panels/repos/edit.inc.php new file mode 100644 index 00000000..3ed39be8 --- /dev/null +++ b/www/views/includes/panels/repos/edit.inc.php @@ -0,0 +1,9 @@ + + + + + -
+

format('d-m-Y') ?>

+ if (!empty($item['PackagesInstalled'])) : + $title = 'INSTALLED'; + $icon = 'check.svg'; + $count = count($item['PackagesInstalled']); ?> +
- installed + +
+ + +
+
+ if (!empty($item['DependenciesInstalled'])) : + $title = 'DEP. INSTALLED'; + $icon = 'check.svg'; + $count = count($item['DependenciesInstalled']); ?> +
- dep. installed +
+ if (!empty($item['PackagesUpdated'])) : + $title = 'UPDATED'; + $icon = 'update-yellow.svg'; + $count = count($item['PackagesUpdated']); ?> +
- updated +
+ if (!empty($item['PackagesDowngraded'])) : + $title = 'DOWNGRADED'; + $icon = 'rollback.svg'; + $count = count($item['PackagesDowngraded']); ?> +
- downgraded +
+ if (!empty($item['PackagesRemoved'])) : + $title = 'UNINSTALLED'; + $icon = 'error.svg'; + $count = count($item['PackagesRemoved']); ?> +
- uninstalled +
+ if (!empty($item['PackagesPurged'])) : + $title = 'PURGED'; + $icon = 'error.svg'; + $count = count($item['PackagesPurged']); ?> +
- uninstalled (purged) +
diff --git a/www/views/includes/tables/host/requests.inc.php b/www/views/includes/tables/host/requests.inc.php index 54d7c646..58fcd42c 100644 --- a/www/views/includes/tables/host/requests.inc.php +++ b/www/views/includes/tables/host/requests.inc.php @@ -335,8 +335,10 @@ /** * If there was packages updated */ - if (!empty($successPackages)) : ?> -

updated

+ if (!empty($successPackages)) : + $icon = 'update-yellow.svg'; + $title = count($successPackages) . ' packages updated'; + include(ROOT . '/views/includes/labels/label-icon-tr.inc.php'); ?>
-

failed

+ if (!empty($failedPackages)) : + $icon = 'warning-red.svg'; + $title = count($failedPackages) . ' packages failed'; + include(ROOT . '/views/includes/labels/label-icon-tr.inc.php'); ?>