diff --git a/App/Manager/Download/DownloadManager.php b/App/Manager/Download/DownloadManager.php index 3b212dd0..fcfb05ba 100644 --- a/App/Manager/Download/DownloadManager.php +++ b/App/Manager/Download/DownloadManager.php @@ -20,7 +20,7 @@ class DownloadManager * @desc Download and install package with api return link, ex: "/Public/market/Resources/forum.zip" * @throws DownloadException */ - public static function installPackageWithLink(string $url, #[ExpectedValues(['package', 'Theme'])] string $type, string $name): void + public static function installPackageWithLink(string $url, #[ExpectedValues(['package', 'Theme'])] string $type, string $name, bool $runInit = true): void { if (!in_array($type, ['package', 'Theme'], true)) { throw new DownloadException('Type invalide'); @@ -56,7 +56,7 @@ public static function installPackageWithLink(string $url, #[ExpectedValues(['pa $archiveUpdate->close(); @unlink($zipPath); - if ($type === 'package') { + if ($type === 'package' && $runInit) { self::initPackages($name); } } diff --git a/App/Manager/Env/EnvManager.php b/App/Manager/Env/EnvManager.php index 6f069085..82041176 100644 --- a/App/Manager/Env/EnvManager.php +++ b/App/Manager/Env/EnvManager.php @@ -209,27 +209,14 @@ public function addValue(string $key, ?string $value): void $key = mb_strtoupper(trim($key)); if (!$this->valueExistInFile($key)) { - $path = $this->envPath . $this->envFileName; + $file = fopen($this->envPath . $this->envFileName, 'ab'); + $textToSet = static function (string $key, ?string $value) { + return $key . '=' . trim($value ?? 'UNDEFINED') . PHP_EOL; + }; - $file = fopen($path, 'cb+'); - if ($file === false) { - ErrorManager::showCustomErrorPage('IO error', 'Unable to open .env'); - } - $needsNewline = false; - $size = filesize($path); - if ($size > 0) { - fseek($file, -1, SEEK_END); - $lastChar = fgetc($file); - $needsNewline = ($lastChar !== "\n"); - fseek($file, 0, SEEK_END); - } - - if ($needsNewline) { - fwrite($file, PHP_EOL); - } + $res = $textToSet($key, $value); + fwrite($file, $res); - $line = $key . '=' . trim($value ?? '') . PHP_EOL; - fwrite($file, $line); fclose($file); $this->load(); diff --git a/App/Manager/Loader/Loader.php b/App/Manager/Loader/Loader.php index 9b64f574..dee7b998 100644 --- a/App/Manager/Loader/Loader.php +++ b/App/Manager/Loader/Loader.php @@ -59,7 +59,7 @@ public static function loadImplementations(string $interface): array $packages = PackageController::getAllPackages(); foreach ($packages as $package) { - $implementationsFolder = EnvManager::getInstance()->getValue('dir') . "App/Package/{$package->name()}/Implementations"; + $implementationsFolder = EnvManager::getInstance()->getValue('DIR') . "App/Package/{$package->name()}/Implementations"; if (!is_dir($implementationsFolder)) { continue; diff --git a/App/Package/Core/Controllers/CoreController.php b/App/Package/Core/Controllers/CoreController.php index d7e0d1dd..838725e6 100644 --- a/App/Package/Core/Controllers/CoreController.php +++ b/App/Package/Core/Controllers/CoreController.php @@ -18,6 +18,7 @@ use CMW\Manager\Uploads\ImagesManager; use CMW\Manager\Views\View; use CMW\Model\Core\CoreModel; +use CMW\Model\Core\UpdateCheckerModel; use CMW\Utils\Redirect; use JetBrains\PhpStorm\NoReturn; use function date; @@ -61,8 +62,10 @@ private function adminDashboard(): void Redirect::redirect(EnvManager::getInstance()->getValue('PATH_SUBFOLDER') . 'cmw-admin/dashboard'); } + $outdatedResources = UpdateCheckerModel::getInstance()->getOutdatedResources(); + View::createAdminView('Core', 'Dashboard/dashboard') - ->addVariableList([]) + ->addVariableList(['outdatedResources' => $outdatedResources]) ->addScriptBefore('Admin/Resources/Vendors/Apexcharts/Js/apexcharts.js') ->view(); } diff --git a/App/Package/Core/Controllers/PackageController.php b/App/Package/Core/Controllers/PackageController.php index 4fa7fdb4..9168fb84 100644 --- a/App/Package/Core/Controllers/PackageController.php +++ b/App/Package/Core/Controllers/PackageController.php @@ -509,7 +509,7 @@ private function adminPackageUpdate(): void if ($i === $lastUpdateIndex) { try { - DownloadManager::installPackageWithLink($update['file'], 'package', $packageName); + DownloadManager::installPackageWithLink($update['file'], 'package', $packageName, false); } catch (DownloadException $e) { Flash::send( Alert::ERROR, @@ -573,4 +573,42 @@ private function uninstallPackage(string $packageName): bool // Uninstall package: return Directory::delete(EnvManager::getInstance()->getValue('DIR') . "App/Package/$packageName"); } + + // HELPER + public function formatDownloads(int $value): string + { + if ($value >= 1_000_000_000) { + return floor($value / 1_000_000_000) . 'B+'; + } + + if ($value >= 1_000_000) { + return floor($value / 1_000_000) . 'M+'; + } + + if ($value >= 1000) { + return floor($value / 1000) . 'k+'; + } + + return (string) $value; + } + + public function renderStars(?string $rate): string + { + $value = (float) ($rate ?? 0); + $html = ''; + + for ($i = 1; $i <= 5; $i++) { + if ($value >= 1) { + $html .= ''; + $value -= 1; + } elseif ($value === 0.5) { + $html .= ''; + $value = 0; + } else { + $html .= ''; + } + } + + return $html; + } } diff --git a/App/Package/Core/Entities/UpdateCheckerEntity.php b/App/Package/Core/Entities/UpdateCheckerEntity.php new file mode 100644 index 00000000..bcdd1e76 --- /dev/null +++ b/App/Package/Core/Entities/UpdateCheckerEntity.php @@ -0,0 +1,80 @@ +name = $name; + $this->marketName = $marketName; + $this->type = $type; + $this->localVersion = $localVersion; + $this->remoteVersion = $remoteVersion; + $this->dateRelease = $dateRelease; + $this->versionId = $versionId; + } + + public function name(): string + { + return $this->name; + } + + public function marketName(): ?string + { + return $this->marketName; + } + + public function type(): string + { + return $this->type; + } + + public function localVersion(): string + { + return $this->localVersion; + } + + public function remoteVersion(): string + { + return $this->remoteVersion; + } + + public function dateRelease(): ?string + { + return Date::formatDate($this->dateRelease); + } + + public function versionId(): ?int + { + return $this->versionId; + } + + public function isOutdated(): bool + { + return $this->localVersion !== $this->remoteVersion; + } +} diff --git a/App/Package/Core/Lang/en.php b/App/Package/Core/Lang/en.php index e3cd7ff6..d9b536b9 100644 --- a/App/Package/Core/Lang/en.php +++ b/App/Package/Core/Lang/en.php @@ -77,7 +77,15 @@ 'weeks' => 'Weeks', 'months' => 'Months', 'alpha' => 'Please note that CraftMyWebsite2 is currently in BETA phase and is not yet complete.
Its use in a production environment is strongly discouraged. Key features may be missing or may not work as expected.
During this phase, complete system reinstalls may be required.
We appreciate your understanding and patience while we work on CraftMyWebsite.', - 'updateWarning' => 'Attention :The current version of your CMS is not the latest available. It is strongly recommended to update your CMS to benefit from the latest security fixes as well as new features added.', + 'updateWarningTitle' => 'Your CMS is not up to date!', + 'updateWarning' => 'Warning: The currently installed version of your CMS is not up to date.
+Continuing to use an outdated version may expose your website to security vulnerabilities, compatibility issues, or unexpected malfunctions with certain modules and themes.
+We strongly recommend performing the CMS update to benefit from the latest security patches, performance improvements, enhanced stability, and newly added features.
+Keeping your CMS up to date ensures a reliable, secure, and future-proof environment.', + 'updateResTitle' => 'Requires your attention', + 'updateResWaiting' => ' has a pending update!', + 'updateResFrom' => 'Since ', + 'updateResBtn' => 'Update', ], 'menus' => [ 'title' => 'Menus', @@ -180,8 +188,8 @@ ], 'db' => [ 'config' => [ - 'success' => 'Good configuration', - 'error' => 'Configuration error', + 'success' => 'Connection to the database is working!', + 'error' => 'Unable to connect to the database!', 'alreadyInstalled' => 'Data base already installed !', ], 'missing_inputs' => 'Please fill all inputs !', diff --git a/App/Package/Core/Lang/fr.php b/App/Package/Core/Lang/fr.php index 86001236..07c6e075 100644 --- a/App/Package/Core/Lang/fr.php +++ b/App/Package/Core/Lang/fr.php @@ -77,7 +77,15 @@ 'weeks' => 'Semaines', 'months' => 'Mois', 'alpha' => 'Veuillez noter que CraftMyWebsite2 est actuellement en phase BETA et n\'est pas encore achevé.
Son utilisation en environnement de production est fortement déconseillée. Des fonctionnalités clés peuvent manquer ou ne pas fonctionner comme prévu.
Pendant cette phase, des réinstallations complètes du système pourront être nécessaires.
Nous vous remercions de votre compréhension et de votre patience pendant que nous travaillons sur CraftMyWebsite.', - 'updateWarning' => 'Attention : La version actuelle de votre CMS n\'est pas la dernière disponible.Il est fortement conseillé de mettre à jour votre CMS pour bénéficier des derniers correctifs de sécurité ainsi que des nouvelles fonctionnalités ajoutées.', + 'updateWarningTitle' => 'Votre CMS n\'est pas à jour !', + 'updateWarning' => 'Attention : La version actuellement installée de votre CMS n’est pas à jour.
+Continuer à utiliser une version obsolète peut exposer votre site à des failles de sécurité, à des problèmes de compatibilité ou à des dysfonctionnements avec certains packages et thèmes.
+Nous vous recommandons vivement d’effectuer la mise à jour du CMS afin de bénéficier des derniers correctifs de sécurité, d’améliorations de performances, d’une meilleure stabilité globale et des nouvelles fonctionnalités récemment ajoutées.
+Mettre à jour régulièrement votre CMS permet de garantir un environnement fiable, sécurisé et conforme aux évolutions techniques.', + 'updateResTitle' => 'Requiert votre attention', + 'updateResWaiting' => 'à une mise à jour en attente !', + 'updateResFrom' => 'Depuis le ', + 'updateResBtn' => 'Mettre à jour', ], 'menus' => [ 'title' => 'Menus', @@ -180,8 +188,8 @@ ], 'db' => [ 'config' => [ - 'success' => 'Configuration fonctionnelle', - 'error' => 'Configuration invalide', + 'success' => 'Connexion avec la base de donnée fonctionnel !', + 'error' => 'Impossible de se connecter à la base de données', 'alreadyInstalled' => 'Base de données déjà installée !', ], 'missing_inputs' => 'Merci de remplir tous les champs !', diff --git a/App/Package/Core/Models/UpdateCheckerModel.php b/App/Package/Core/Models/UpdateCheckerModel.php new file mode 100644 index 00000000..c094cf9a --- /dev/null +++ b/App/Package/Core/Models/UpdateCheckerModel.php @@ -0,0 +1,93 @@ +getMarketResourcesOnline(); + + $marketByName = []; + foreach ($marketResources as $r) { + $name = $r['name'] ?? null; + if ($name) { + $marketByName[$name] = $r; + } + } + + $outdated = []; + + foreach (ThemeLoader::getInstance()->getInstalledThemes() as $theme) { + $name = $theme->name(); + $localVersion = (string) $theme->version(); + + if (!isset($marketByName[$name])) { + continue; + } + + $remoteVersion = (string) ($marketByName[$name]['version_name'] ?? ''); + + if ($remoteVersion !== '' && $localVersion !== $remoteVersion) { + $outdated[] = new UpdateCheckerEntity( + name: $name, + marketName: $marketByName[$name]['market_name'] ?? null, + type: 'theme', + localVersion: $localVersion, + remoteVersion: $remoteVersion, + dateRelease: $marketByName[$name]['date_release'] ?? null, + versionId: isset($marketByName[$name]['version_id']) ? (int) $marketByName[$name]['version_id'] : null + ); + } + } + + foreach (PackageController::getInstalledPackages() as $package) { + $name = $package->name(); + $localVersion = (string) $package->version(); + + if (!isset($marketByName[$name])) { + continue; + } + + $remoteVersion = (string) ($marketByName[$name]['version_name'] ?? ''); + + if ($remoteVersion !== '' && $localVersion !== $remoteVersion) { + $outdated[] = new UpdateCheckerEntity( + name: $name, + marketName: $marketByName[$name]['market_name'] ?? null, + type: 'package', + localVersion: $localVersion, + remoteVersion: $remoteVersion, + dateRelease: $marketByName[$name]['date_release'] ?? null, + versionId: isset($marketByName[$name]['version_id']) ? (int) $marketByName[$name]['version_id'] : null + ); + } + } + + return $outdated; + } +} diff --git a/App/Package/Core/Views/Dashboard/dashboard.admin.view.php b/App/Package/Core/Views/Dashboard/dashboard.admin.view.php index dcbb712e..7b26d0d1 100644 --- a/App/Package/Core/Views/Dashboard/dashboard.admin.view.php +++ b/App/Package/Core/Views/Dashboard/dashboard.admin.view.php @@ -9,20 +9,43 @@ Website::setTitle(LangManager::translate('core.dashboard.title')); Website::setDescription(LangManager::translate('core.dashboard.desc')); +/* @var \CMW\Entity\Core\UpdateCheckerEntity[] $outdatedResources */ + $needUpdate = UpdatesManager::checkNewUpdateAvailable(); ?> -
-
- -
- + +
+

- -
+
+
+ + +
+

+
+ +
+

+ marketName() ?>

+

localVersion()?>remoteVersion()?>

+

dateRelease()?>

+ +
+ +
+
+
+ + +
+ +
+

diff --git a/App/Package/Core/Views/Package/market.admin.view.php b/App/Package/Core/Views/Package/market.admin.view.php index b8a1df8f..586fe47e 100644 --- a/App/Package/Core/Views/Package/market.admin.view.php +++ b/App/Package/Core/Views/Package/market.admin.view.php @@ -27,7 +27,7 @@ alt="img">
-
En attente : ' : '' ?>
+
En attente : ' : '' ?>
@@ -71,15 +71,15 @@