From 799b870f9a97a37c15dc89ae448953f11f531875 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 17:58:48 +0100 Subject: [PATCH 01/38] use table helper --- utils/Commands/ListcacheCommand.php | 70 ++++++++++++++++------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/utils/Commands/ListcacheCommand.php b/utils/Commands/ListcacheCommand.php index d42a6e649..d01651d20 100644 --- a/utils/Commands/ListcacheCommand.php +++ b/utils/Commands/ListcacheCommand.php @@ -6,6 +6,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Helper\Table; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; @@ -48,36 +49,39 @@ class ListcacheCommand extends Command $outformat = '%-20s %-40s %15s %7d'; require_once('inc/inc.DBInit.php'); - $cachedir = $settings->_cacheDir; - $totalc = 0; - $totalspace = 0; - // Preview for png, pdf, and txt */ - foreach(['png', 'pdf', 'txt'] as $t) { - $path = addDirSep($cachedir).$t; - if(file_exists($path)) { - $space = dskspace($path); - $fi = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS); - $c = iterator_count($fi); - } else { - $space = $c = 0; - } - $totalc += $c; - $totalspace += $space; - $output->writeln(sprintf($outformat, 'preview'.$t, $translator->translate('preview_'.$t), SeedDMS_Core_File::format_filesize($space), $c)); - } + $cachedir = $settings->_cacheDir; + $totalc = 0; + $totalspace = 0; + $tabledata = []; + // Preview for png, pdf, and txt */ + foreach(['png', 'pdf', 'txt'] as $t) { + $path = addDirSep($cachedir).$t; + if(file_exists($path)) { + $space = dskspace($path); + $fi = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS); + $c = iterator_count($fi); + } else { + $space = $c = 0; + } + $totalc += $c; + $totalspace += $space; +// $output->writeln(sprintf($outformat, 'preview'.$t, $translator->translate('preview_'.$t), SeedDMS_Core_File::format_filesize($space), $c)); + $tabledata[] = ['preview'.$t, $translator->translate('preview_'.$t), SeedDMS_Core_File::format_filesize($space), $c]; + } - /* Javascript */ - $path = addDirSep($cachedir).'js'; - if(file_exists($path)) { - $space = dskspace($path); - $fi = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS); - $c = iterator_count($fi); - } else { - $space = $c = 0; - } - $totalc += $c; - $totalspace += $space; - $output->writeln(sprintf($outformat, 'js', $translator->translate('temp_jscode'), SeedDMS_Core_File::format_filesize($space), $c)); + /* Javascript */ + $path = addDirSep($cachedir).'js'; + if(file_exists($path)) { + $space = dskspace($path); + $fi = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS); + $c = iterator_count($fi); + } else { + $space = $c = 0; + } + $totalc += $c; + $totalspace += $space; +// $output->writeln(sprintf($outformat, 'js', $translator->translate('temp_jscode'), SeedDMS_Core_File::format_filesize($space), $c)); + $tabledata[] = ['js', $translator->translate('temp_jscode'), SeedDMS_Core_File::format_filesize($space), $c]; $caches = []; /* Create a dummy view for passing it to additionalCache() */ @@ -90,8 +94,14 @@ class ListcacheCommand extends Command } } foreach($caches as $cache) { - $output->writeln(sprintf($outformat, $cache[0], $cache[1], SeedDMS_Core_File::format_filesize($cache[2]), $cache[3])); +// $output->writeln(sprintf($outformat, $cache[0], $cache[1], SeedDMS_Core_File::format_filesize($cache[2]), $cache[3])); + $tabledata[] = [$cache[0], $cache[1], SeedDMS_Core_File::format_filesize($cache[2]), $cache[3]]; } + $table = new Table($output); + $table + ->setHeaders(['Cache', 'Name', 'Size', 'Count']) + ->setRows($tabledata); + $table->render(); // print_r($caches); return Command::SUCCESS; From 994fe49e6deb47693234113d924871b6cb9fd933 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:55:49 +0100 Subject: [PATCH 02/38] about comment about deprecated functions --- inc/inc.Language.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/inc.Language.php b/inc/inc.Language.php index 33e1f9025..94344656b 100644 --- a/inc/inc.Language.php +++ b/inc/inc.Language.php @@ -23,6 +23,10 @@ use Seeddms\Seeddms\Translator; $translator = new Translator($settings); $translator->init(); +/* All remaining functions in this file are deprecated and should + * not be used anymore. Use instead the equivalent methods in class + * Translator; + */ function getAvailableLanguages() { /* {{{ */ trigger_error("getAvailableLanguages() is deprecated.", E_USER_DEPRECATED); foreach(debug_backtrace() as $n) { From 7c9ef030d651ad8b631f269a16180c6eaf188cd7 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:56:08 +0100 Subject: [PATCH 03/38] ask before clearing the cache --- utils/Commands/ClearcacheCommand.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/utils/Commands/ClearcacheCommand.php b/utils/Commands/ClearcacheCommand.php index 0aae1c010..6d9842803 100644 --- a/utils/Commands/ClearcacheCommand.php +++ b/utils/Commands/ClearcacheCommand.php @@ -6,6 +6,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Question\ConfirmationQuestion; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; @@ -33,9 +35,10 @@ class ClearcacheCommand extends Command protected function configure() { $this->setName('cache:clear') - ->setDescription('Clears the cache') - ->setHelp('Clears all cache or those specified.') - ->addOption('cache', '', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Remove files from cache.', null) + ->setDescription('Clear cache') + ->setHelp('Clears either all caches or those specified with option --cache. Think twice before you clear a cache with previews. Depending on the number of documents in your DMS, it may take a long time to recreate the cache.') + ->addOption('cache', '', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Remove files from this cache.', null) + ->addOption('force', '', InputOption::VALUE_NONE, 'Force operation, do not ask') ; } @@ -52,6 +55,14 @@ class ClearcacheCommand extends Command return Command::FAILURE; } + if (!$input->getOption('force')) { + $helper = new QuestionHelper(); + $question = new ConfirmationQuestion('Do you really want to clear the cache? ', false); + if (!$helper->ask($input, $output, $question)) { + return Command::SUCCESS; + } + } + require_once('inc/inc.DBInit.php'); $post = array_flip($input->getOption('cache')); From 8b67c33fa7adce56ab17a11cc708dea70b82bd34 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:57:22 +0100 Subject: [PATCH 04/38] fix description and help text --- utils/Commands/PackageextensionCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/Commands/PackageextensionCommand.php b/utils/Commands/PackageextensionCommand.php index 7a8fef84d..e4e5ffe7f 100644 --- a/utils/Commands/PackageextensionCommand.php +++ b/utils/Commands/PackageextensionCommand.php @@ -38,8 +38,8 @@ class PackageextensionCommand extends Command protected function configure() { $this->setName('ext:package') - ->setDescription('Package extension as a zip file. If --output-dir is given, the zip file will be placed into this directory otherwise it will be saved in the current directory. The name of the zip file will be -.zip. If such a file already exists, it will be deleted and recreated.') - ->setHelp('Creates a zip file of an extension, which can be uploaded into SeedDMS.') + ->setDescription('Package extension as a zip file') + ->setHelp('Creates a zip file of an extension, which can be uploaded into SeedDMS. If --output-dir is given, the zip file will be placed into this directory otherwise it will be saved in the current directory. The name of the zip file will be -.zip. If such a file already exists, it will be deleted and recreated.') ->addOption('name', '', InputOption::VALUE_REQUIRED, 'Name of extension.', null) ->addOption('output-dir', '', InputOption::VALUE_REQUIRED, 'Name of directory where the zip file is saved.', null) ; From 0446009024ad2ac36bc7ddcb76561f50e6b17021 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:57:46 +0100 Subject: [PATCH 05/38] render stats as table --- utils/Commands/StatsCommand.php | 75 ++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/utils/Commands/StatsCommand.php b/utils/Commands/StatsCommand.php index e1df7257d..322960384 100644 --- a/utils/Commands/StatsCommand.php +++ b/utils/Commands/StatsCommand.php @@ -6,9 +6,13 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\TableCell; +use Symfony\Component\Console\Helper\TableSeparator; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; +use SeedDMS_Core_File; use Log_file; class StatsCommand extends Command @@ -30,9 +34,9 @@ class StatsCommand extends Command protected function configure() { $this->setName('dms:stats') - ->setDescription('Prints Statistics') - ->setHelp('Demonstration of custom commands created by Symfony Console component.') - ->addOption('json', '', InputOption::VALUE_NONE, 'Export data as json') + ->setDescription('Print statistics') + ->setHelp('Outputs the number of documents, folders, users, etc. in total and how many of them are owned by they users.') + ->addOption('json', '', InputOption::VALUE_NONE, 'Print data as json instead of a table') ; } @@ -45,7 +49,7 @@ class StatsCommand extends Command require_once('inc/inc.DBInit.php'); foreach (array('docstotal'=>'documents', 'folderstotal'=>'folders', 'userstotal'=>'users', 'groupstotal'=>'groups', 'categoriestotal'=>'categories') as $type=>$name) { - $stats[$type] = $dms->getStatisticalData($type); + $stats['total'][substr($type, 0, -5)] = $dms->getStatisticalData($type); } foreach (array('docsperuser'=>'documents', 'foldersperuser'=>'folders','sizeperuser'=>'size') as $type=>$name) { $stats[$type] = $dms->getStatisticalData($type); @@ -54,26 +58,49 @@ class StatsCommand extends Command if ($input->getOption('json')) { $output->writeln(json_encode($stats)); } else { - $outformat = '%-30s %-10d'; - $output->writeln(sprintf($outformat, 'Documents', $stats['docstotal'])); - $output->writeln(sprintf($outformat, 'Folders', $stats['folderstotal'])); - $output->writeln(sprintf($outformat, 'Users', $stats['userstotal'])); - $output->writeln(sprintf($outformat, 'Groups', $stats['groupstotal'])); - $output->writeln(sprintf($outformat, 'Categories', $stats['categoriestotal'])); - $output->writeln(''); - $output->writeln('Documents per user:'); - foreach($stats['docsperuser'] as $d) { - $output->writeln(sprintf($outformat, $d['key'], $d['total'])); - } - $output->writeln(''); - $output->writeln('Folders per user:'); - foreach($stats['foldersperuser'] as $d) { - $output->writeln(sprintf($outformat, $d['key'], $d['total'])); - } - $output->writeln(''); - $output->writeln('Size per user:'); - foreach($stats['sizeperuser'] as $d) { - $output->writeln(sprintf($outformat, $d['key'], $d['total'])); + if(1) { + $table = new Table($output); + $table->setHeaders(['Name', 'Count/Size']); + foreach($stats['total'] as $k=>$v) + $table->addRow([$k, $v]); + $table->addRow(new TableSeparator()); + $table->addRow([new TableCell($translator->translate('chart_docsperuser_title'), ['colspan' => 2])]); + $table->addRow(new TableSeparator()); + foreach($stats['docsperuser'] as $v) + $table->addRow([$v['key'], $v['total']]); + $table->addRow(new TableSeparator()); + $table->addRow([new TableCell($translator->translate('chart_foldersperuser_title'), ['colspan' => 2])]); + $table->addRow(new TableSeparator()); + foreach($stats['foldersperuser'] as $v) + $table->addRow([$v['key'], $v['total']]); + $table->addRow(new TableSeparator()); + $table->addRow([new TableCell($translator->translate('chart_sizeperuser_title'), ['colspan' => 2])]); + $table->addRow(new TableSeparator()); + foreach($stats['sizeperuser'] as $v) + $table->addRow([$v['key'], SeedDMS_Core_File::format_filesize((int)$v['total'])]); + $table->render(); + } else { + $outformat = '%-30s %-10d'; + $output->writeln(sprintf($outformat, 'Documents', $stats['docstotal'])); + $output->writeln(sprintf($outformat, 'Folders', $stats['folderstotal'])); + $output->writeln(sprintf($outformat, 'Users', $stats['userstotal'])); + $output->writeln(sprintf($outformat, 'Groups', $stats['groupstotal'])); + $output->writeln(sprintf($outformat, 'Categories', $stats['categoriestotal'])); + $output->writeln(''); + $output->writeln('Documents per user:'); + foreach($stats['docsperuser'] as $d) { + $output->writeln(sprintf($outformat, $d['key'], $d['total'])); + } + $output->writeln(''); + $output->writeln('Folders per user:'); + foreach($stats['foldersperuser'] as $d) { + $output->writeln(sprintf($outformat, $d['key'], $d['total'])); + } + $output->writeln(''); + $output->writeln('Size per user:'); + foreach($stats['sizeperuser'] as $d) { + $output->writeln(sprintf($outformat, $d['key'], $d['total'])); + } } } return Command::SUCCESS; From d2574c8caad4b62847e195b27d1cfcc594d164ad Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:58:10 +0100 Subject: [PATCH 06/38] fix typo --- utils/console | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/console b/utils/console index 2cf31546b..ccd021a4a 100755 --- a/utils/console +++ b/utils/console @@ -23,7 +23,7 @@ use Seeddms\Seeddms\Translator; $settings = new Settings(); /* For now includce inc.Language.php, because it defines the old - * translation functions (e.g. getMLText()), which is still used + * translation functions (e.g. getMLText()), which are still used * by many extensions. */ require_once('inc/inc.Language.php'); From cb3d5b6379bd9f38ea8cc64851c0abf9b7148869 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 18:58:22 +0100 Subject: [PATCH 07/38] and changes for 5.1.43 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2346c1531..2acc54000 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ -------------------------------------------------------------------------------- - add Slim middleware for Basic authentication (can be used by extensions) - rest api endpoint 'statstotal' returns number of groups and categories +- add new command line program utils/console -------------------------------------------------------------------------------- Changes in version 5.1.42 From 73e266bab7ef566c22c5f53f1b0eeae44594b9a7 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 22:20:16 +0100 Subject: [PATCH 08/38] add command to upload extension --- utils/Commands/UploadextensionCommand.php | 77 +++++++++++++++++++++++ utils/console | 2 + 2 files changed, 79 insertions(+) create mode 100644 utils/Commands/UploadextensionCommand.php diff --git a/utils/Commands/UploadextensionCommand.php b/utils/Commands/UploadextensionCommand.php new file mode 100644 index 000000000..65a75817f --- /dev/null +++ b/utils/Commands/UploadextensionCommand.php @@ -0,0 +1,77 @@ +settings = $settings; + $this->logger = $logger; + $this->translator = $translator; + $this->extmgr = $extmgr; + parent::__construct(); + } + + protected function configure() + { + $this->setName('ext:upload') + ->setDescription('Upload extension') + ->setHelp('Uploads an extensions, which replaces an exiting extension or inserts a new extension.') + ->addOption('file', '', InputOption::VALUE_REQUIRED, 'Filename of zipped extension.', null) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $settings = $this->settings; + $logger = $this->logger; + $translator = $this->translator; + $extmgr = $this->extmgr; + + $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + + if (!is_writable($settings->_configFilePath)) { + $output->writeln(sprintf("The configuration file '%s' is not writable by the system user running this script.", $settings->_configFilePath)); + return Command::FAILURE; + } + + if (!is_writable($settings->_cacheDir)) { + $output->writeln(sprintf("The cache dir '%s' is not writable for the system user running this script.", $settings->_cacheDir)); + return Command::FAILURE; + } + + if (!$extmgr->updateExtension($filename)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + return Command::FAILURE; + } + + return Command::SUCCESS; + } +} + +// vim: ts=4 sw=4 expandtab diff --git a/utils/console b/utils/console index ccd021a4a..4e1581f1d 100755 --- a/utils/console +++ b/utils/console @@ -16,6 +16,7 @@ use Seeddms\Console\Commands\ClearcacheCommand; use Seeddms\Console\Commands\ListcacheCommand; use Seeddms\Console\Commands\ListextensionCommand; use Seeddms\Console\Commands\ConfigureextensionCommand; +use Seeddms\Console\Commands\UploadextensionCommand; use Seeddms\Console\Commands\PackageextensionCommand; use Seeddms\Console\Commands\ReloadextensionCommand; use Seeddms\Seeddms\Settings; @@ -42,6 +43,7 @@ $application->add(new ClearcacheCommand($settings, $logger, $translator)); $application->add(new ListcacheCommand($settings, $logger, $translator)); $application->add(new ListextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new ConfigureextensionCommand($settings, $logger, $translator, $extmgr)); +$application->add(new UploadextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new PackageextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new ReloadextensionCommand($settings, $logger, $translator, $extmgr)); From bf28ffa215d704e2091bafd30c6adab417f999ca Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Thu, 13 Nov 2025 22:21:07 +0100 Subject: [PATCH 09/38] rename SeedDMS_Session and SeedDMS_SessionMgr into \Seeddms\Seeddms\... --- composer-dist.json | 2 +- composer.json | 2 +- inc/inc.Authentication.php | 8 +++++--- inc/inc.ClassAuthenticationMiddleware.php | 6 ++++-- inc/inc.ClassSession.php | 16 +++++++++------- op/op.Ajax.php | 4 +++- op/op.Login.php | 4 +++- op/op.Logout.php | 6 ++++-- restapi/index.php | 7 ++++--- views/bootstrap/class.Session.php | 7 ++----- views/bootstrap/class.UserList.php | 7 ++----- views/bootstrap/class.UsrMgr.php | 4 +++- 12 files changed, 41 insertions(+), 32 deletions(-) diff --git a/composer-dist.json b/composer-dist.json index e108080b0..f9f5bbfb4 100644 --- a/composer-dist.json +++ b/composer-dist.json @@ -22,7 +22,7 @@ "psr-4": { "SeedDMS\\Console\\": "seeddms/utils" }, - "classmap": ["seeddms/inc/inc.ClassTranslator.php", "seeddms/inc/inc.ClassSettings.php", "seeddms/inc/inc.Version.php", "seeddms/inc/inc.ClassViewCommon.php", "seeddms/inc/inc.ClassControllerCommon.php", "seeddms/inc/inc.ClassController.php"] + "classmap": ["seeddms/inc/inc.ClassTranslator.php", "seeddms/inc/inc.ClassSettings.php", "seeddms/inc/inc.Version.php", "seeddms/inc/inc.ClassViewCommon.php", "seeddms/inc/inc.ClassControllerCommon.php", "seeddms/inc/inc.ClassController.php", "seeddms/inc/inc.ClassSession.php"] }, "require": { "pear/http_request2": "^2", diff --git a/composer.json b/composer.json index 1f62d796e..bb53cce27 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "psr-4": { "Seeddms\\Console\\": "utils" }, - "classmap": ["inc/inc.ClassTranslator.php", "inc/inc.ClassSettings.php", "inc/inc.Version.php", "inc/inc.ClassViewCommon.php", "inc/inc.ClassControllerCommon.php", "inc/inc.ClassController.php"] + "classmap": ["inc/inc.ClassTranslator.php", "inc/inc.ClassSettings.php", "inc/inc.Version.php", "inc/inc.ClassViewCommon.php", "inc/inc.ClassControllerCommon.php", "inc/inc.ClassController.php", "inc/inc.ClassSession.php"] }, "require": { "php": ">=8.2.0", diff --git a/inc/inc.Authentication.php b/inc/inc.Authentication.php index bc132862b..c5811ac57 100644 --- a/inc/inc.Authentication.php +++ b/inc/inc.Authentication.php @@ -12,6 +12,8 @@ * @version Release: @package_version@ */ +use Seeddms\Seeddms\Session; + require_once("inc.ClassSession.php"); require_once("inc.ClassAccessOperation.php"); @@ -23,7 +25,7 @@ if (!strncmp("/op", $refer, 3)) { } if (!isset($_COOKIE["mydms_session"])) { if($settings->_enableGuestLogin && $settings->_enableGuestAutoLogin) { - $session = new SeedDMS_Session($db); + $session = new Session($db); if(!$dms_session = $session->create(array('userid'=>$settings->_guestID, 'theme'=>$settings->_theme, 'lang'=>$settings->_language))) { header("Location: " . $settings->_httpRoot . "out/out.Login.php?referuri=".$refer); exit; @@ -44,7 +46,7 @@ if (!isset($_COOKIE["mydms_session"])) { $lang = $settings->_language; $user->setLanguage($lang); } - $session = new SeedDMS_Session($db); + $session = new Session($db); if(!$dms_session = $session->create(array('userid'=>$user->getID(), 'theme'=>$theme, 'lang'=>$lang))) { header("Location: " . $settings->_httpRoot . "out/out.Login.php?referuri=".$refer); exit; @@ -57,7 +59,7 @@ if (!isset($_COOKIE["mydms_session"])) { } else { /* Load session */ $dms_session = $_COOKIE["mydms_session"]; - $session = new SeedDMS_Session($db); + $session = new Session($db); if(!$resArr = $session->load($dms_session)) { setcookie("mydms_session", $dms_session, time()-3600, $settings->_httpRoot); //delete cookie header("Location: " . $settings->_httpRoot . "out/out.Login.php?referuri=".$refer); diff --git a/inc/inc.ClassAuthenticationMiddleware.php b/inc/inc.ClassAuthenticationMiddleware.php index f406747cf..62795e4bf 100644 --- a/inc/inc.ClassAuthenticationMiddleware.php +++ b/inc/inc.ClassAuthenticationMiddleware.php @@ -30,6 +30,8 @@ * @link https://www.seeddms.org Main Site */ +use Seeddms\Seeddms\Session; + /* Middleware for authentication based on session */ class SeedDMS_Auth_Middleware_Session { /* {{{ */ @@ -67,8 +69,8 @@ class SeedDMS_Auth_Middleware_Session { /* {{{ */ } $logger->log("Invoke AuthSessionMiddleware for method " . $request->getMethod() . " on '" . $request->getUri()->getPath() . "'", PEAR_LOG_INFO); - require_once("inc/inc.ClassSession.php"); - $session = new SeedDMS_Session($dms->getDb()); +// require_once("inc/inc.ClassSession.php"); + $session = new Session($dms->getDb()); if (isset($_COOKIE["mydms_session"])) { $dms_session = $_COOKIE["mydms_session"]; $logger->log("Session key: " . $dms_session, PEAR_LOG_DEBUG); diff --git a/inc/inc.ClassSession.php b/inc/inc.ClassSession.php index e1f1c1b8e..f86199253 100644 --- a/inc/inc.ClassSession.php +++ b/inc/inc.ClassSession.php @@ -15,6 +15,8 @@ * @version Release: @package_version@ */ +namespace Seeddms\Seeddms; + /** * Class to represent a session * @@ -29,7 +31,7 @@ * @copyright 2011 Uwe Steinmann * @version Release: @package_version@ */ -class SeedDMS_Session { +class Session { /** * @var object $db reference to database object. This must be an instance * of {@link SeedDMS_Core_DatabaseAccess}. @@ -53,7 +55,7 @@ class SeedDMS_Session { * Create a new instance of the session handler * * @param object $db object to access the underlying database - * @return object instance of SeedDMS_Session + * @return object instance of Seeddms\Seeddms\Session */ function __construct($db) { /* {{{ */ $this->db = $db; @@ -428,7 +430,7 @@ class SeedDMS_Session { * @copyright 2014 Uwe Steinmann * @version Release: @package_version@ */ -class SeedDMS_SessionMgr { +class SessionMgr { /** * @var object $db reference to database object. This must be an instance * of {@link SeedDMS_Core_DatabaseAccess}. @@ -440,7 +442,7 @@ class SeedDMS_SessionMgr { * Create a new instance of the session manager * * @param object $db object to access the underlying database - * @return object instance of SeedDMS_SessionMgr + * @return object instance of Seeddms\Seeddms\SessionMgr */ function __construct($db) { /* {{{ */ $this->db = $db; @@ -478,7 +480,7 @@ class SeedDMS_SessionMgr { return false; $sessions = array(); foreach($resArr as $rec) { - $session = new SeedDMS_Session($this->db); + $session = new Session($this->db); $session->load($rec['id']); $sessions[] = $session; } @@ -501,7 +503,7 @@ class SeedDMS_SessionMgr { return false; $sessions = array(); foreach($resArr as $rec) { - $session = new SeedDMS_Session($this->db); + $session = new Session($this->db); $session->load($rec['id']); $sessions[] = $session; } @@ -523,7 +525,7 @@ class SeedDMS_SessionMgr { return false; $sessions = array(); foreach($resArr as $rec) { - $session = new SeedDMS_Session($this->db); + $session = new Session($this->db); $session->load($rec['id']); $sessions[] = $session; } diff --git a/op/op.Ajax.php b/op/op.Ajax.php index b14375ddb..e0e73c539 100644 --- a/op/op.Ajax.php +++ b/op/op.Ajax.php @@ -29,6 +29,8 @@ require_once("../inc/inc.ClassUI.php"); require_once("../inc/inc.ClassController.php"); require_once("../inc/inc.Notification.php"); +use Seeddms\Seeddms\Session; + require_once("../inc/inc.ClassSession.php"); require_once("../inc/inc.ClassPasswordStrength.php"); require_once("../inc/inc.ClassPasswordHistoryManager.php"); @@ -36,7 +38,7 @@ require_once("../inc/inc.ClassPasswordHistoryManager.php"); /* Load session */ if (isset($_COOKIE["mydms_session"])) { $dms_session = $_COOKIE["mydms_session"]; - $session = new SeedDMS_Session($db); + $session = new Session($db); if(!$resArr = $session->load($dms_session)) { header('Content-Type: application/json'); echo json_encode(array('error'=>1)); diff --git a/op/op.Login.php b/op/op.Login.php index f8a3d3632..135c5aefc 100644 --- a/op/op.Login.php +++ b/op/op.Login.php @@ -18,6 +18,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +use Seeddms\Seeddms\Session; + include("../inc/inc.Settings.php"); include("../inc/inc.Utils.php"); include("../inc/inc.LogInit.php"); @@ -67,7 +69,7 @@ if(isset($_REQUEST["lang"]) && strlen($_REQUEST["lang"])>0 && is_numeric(array_s $lang = (string) $_REQUEST["lang"]; } -$session = new SeedDMS_Session($db); +$session = new Session($db); // TODO: by the PHP manual: The superglobals $_GET and $_REQUEST are already decoded. // Using urldecode() on an element in $_GET or $_REQUEST could have unexpected and dangerous results. diff --git a/op/op.Logout.php b/op/op.Logout.php index 70d089139..6acc9166b 100644 --- a/op/op.Logout.php +++ b/op/op.Logout.php @@ -23,12 +23,14 @@ include("../inc/inc.Utils.php"); include("../inc/inc.LogInit.php"); include("../inc/inc.Language.php"); include("../inc/inc.Init.php"); -include("../inc/inc.Extension.php"); +//include("../inc/inc.Extension.php"); include("../inc/inc.ClassSession.php"); include("../inc/inc.ClassController.php"); include("../inc/inc.DBInit.php"); include("../inc/inc.Authentication.php"); +use Seeddms\Seeddms\Session; + $tmp = explode('.', basename($_SERVER['SCRIPT_FILENAME'])); $controller = Controller::factory($tmp[1], array('dms'=>$dms, 'user'=>$user)); @@ -36,7 +38,7 @@ $controller = Controller::factory($tmp[1], array('dms'=>$dms, 'user'=>$user)); if(isset($_COOKIE['mydms_session'])) { $dms_session = $_COOKIE["mydms_session"]; - $session = new SeedDMS_Session($db); + $session = new Session($db); $session->load($dms_session); // If setting the user id to 0 worked, it would be a way to logout a diff --git a/restapi/index.php b/restapi/index.php index 7c6894a8e..b6fb4b4c5 100644 --- a/restapi/index.php +++ b/restapi/index.php @@ -25,6 +25,7 @@ use Psr\Http\Server\MiddlewareInterface; use DI\ContainerBuilder; use Slim\Factory\AppFactory; use Seeddms\Seeddms\Translator; +use Seeddms\Seeddms\Session; final class JsonRenderer { /* {{{ */ public function json( @@ -264,7 +265,7 @@ final class SeedDMS_RestapiController { /* {{{ */ return $this->renderer->json($response, array('success'=>false, 'message'=>'Login failed', 'data'=>''))->withStatus(403); } else { require_once("../inc/inc.ClassSession.php"); - $session = new SeedDMS_Session($dms->getDb()); + $session = new Session($dms->getDb()); if(!$id = $session->create(array('userid'=>$userobj->getId(), 'theme'=>$userobj->getTheme(), 'lang'=>$userobj->getLanguage()))) { return $this->renderer->json($response, array('success'=>false, 'message'=>'Creating session failed', 'data'=>''))->withStatus(500); } @@ -291,7 +292,7 @@ final class SeedDMS_RestapiController { /* {{{ */ $dms_session = $_COOKIE["mydms_session"]; $db = $dms->getDb(); - $session = new SeedDMS_Session($db); + $session = new Session($db); $session->load($dms_session); // If setting the user id to 0 worked, it would be a way to logout a @@ -3175,7 +3176,7 @@ class RestapiAuthMiddleware implements MiddlewareInterface { /* {{{ */ } else { $logger->log("Checking for valid session", PEAR_LOG_INFO); require_once("../inc/inc.ClassSession.php"); - $session = new SeedDMS_Session($dms->getDb()); + $session = new Session($dms->getDb()); if (isset($_COOKIE["mydms_session"])) { $logger->log("Found cookie for session", PEAR_LOG_INFO); $dms_session = $_COOKIE["mydms_session"]; diff --git a/views/bootstrap/class.Session.php b/views/bootstrap/class.Session.php index 33a47de8c..8b54775e6 100644 --- a/views/bootstrap/class.Session.php +++ b/views/bootstrap/class.Session.php @@ -13,10 +13,7 @@ * @version Release: @package_version@ */ -/** - * Include parent class - */ -//require_once("class.Bootstrap.php"); +use Seeddms\Seeddms\SessionMgr; /** * Class which outputs the html page for clipboard view @@ -44,7 +41,7 @@ class SeedDMS_View_Session extends SeedDMS_Theme_Style { $dms = $this->params['dms']; $user = $this->params['user']; - $sessionmgr = new SeedDMS_SessionMgr($dms->getDB()); + $sessionmgr = new SessionMgr($dms->getDB()); $sessions = $sessionmgr->getLastAccessedSessions(date('Y-m-d H:i:s', time()-3600)); if(!$sessions) return; diff --git a/views/bootstrap/class.UserList.php b/views/bootstrap/class.UserList.php index 96b93b881..06146db06 100644 --- a/views/bootstrap/class.UserList.php +++ b/views/bootstrap/class.UserList.php @@ -13,10 +13,7 @@ * @version Release: @package_version@ */ -/** - * Include parent class - */ -//require_once("class.Bootstrap.php"); +use Seeddms\Seeddms\SessionMgr; /** * Class which outputs the html page for UserList view @@ -59,7 +56,7 @@ class SeedDMS_View_UserList extends SeedDMS_Theme_Style { $this->pageNavigation("", "admin_tools"); $this->contentHeading(getMLText("user_list")); - $sessionmgr = new SeedDMS_SessionMgr($dms->getDB()); + $sessionmgr = new SessionMgr($dms->getDB()); ?> diff --git a/views/bootstrap/class.UsrMgr.php b/views/bootstrap/class.UsrMgr.php index 91edd2685..4db135402 100644 --- a/views/bootstrap/class.UsrMgr.php +++ b/views/bootstrap/class.UsrMgr.php @@ -13,6 +13,8 @@ * @version Release: @package_version@ */ +use Seeddms\Seeddms\SessionMgr; + /** * Include parent class */ @@ -99,7 +101,7 @@ $(document).ready( function() { $workflowmode = $this->params['workflowmode']; if($seluser) { - $sessionmgr = new SeedDMS_SessionMgr($dms->getDB()); + $sessionmgr = new SessionMgr($dms->getDB()); $this->contentHeading(getMLText("user_info")); echo "\n"; From b42fdb44c641ddad0f34fafedcf1b4d45e680c41 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 09:29:51 +0100 Subject: [PATCH 10/38] set include_path instead using an absolute path to include autoload.php. This works in the devel enviroment and the installed SeedDMS --- utils/console | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/console b/utils/console index 4e1581f1d..8d67ca401 100755 --- a/utils/console +++ b/utils/console @@ -1,8 +1,8 @@ #!/usr/bin/env php Date: Fri, 14 Nov 2025 10:32:45 +0100 Subject: [PATCH 11/38] add new command for checking extensions --- utils/Commands/CheckextensionCommand.php | 71 ++++++++++++++++++++++++ utils/console | 2 + 2 files changed, 73 insertions(+) create mode 100644 utils/Commands/CheckextensionCommand.php diff --git a/utils/Commands/CheckextensionCommand.php b/utils/Commands/CheckextensionCommand.php new file mode 100644 index 000000000..564882d27 --- /dev/null +++ b/utils/Commands/CheckextensionCommand.php @@ -0,0 +1,71 @@ +settings = $settings; + $this->logger = $logger; + $this->translator = $translator; + $this->extmgr = $extmgr; + parent::__construct(); + } + + protected function configure() + { + $this->setName('ext:check') + ->setDescription('Check extensions') + ->setHelp('Checks all installed extensions for completeness and dependencies.') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $settings = $this->settings; + $logger = $this->logger; + $translator = $this->translator; + $extmgr = $this->extmgr; + + $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + + $extconfs = $extmgr->getExtensionConfiguration(); + foreach ($extconfs as $extname=>$extconf) { + if($extmgr->checkExtensionByDir($extname)) { + $output->writeln(sprintf("%s", $extname)); + } else { + $output->writeln(sprintf("%s", $extname)); + $errmsgs = $extmgr->getErrorMsgs(); + foreach($errmsgs as $errmsg) { + $output->writeln(sprintf("%s", $errmsg)); + } + } + } + return Command::SUCCESS; + } +} + +// vim: ts=4 sw=4 expandtab diff --git a/utils/console b/utils/console index 8d67ca401..9b853905d 100755 --- a/utils/console +++ b/utils/console @@ -19,6 +19,7 @@ use Seeddms\Console\Commands\ConfigureextensionCommand; use Seeddms\Console\Commands\UploadextensionCommand; use Seeddms\Console\Commands\PackageextensionCommand; use Seeddms\Console\Commands\ReloadextensionCommand; +use Seeddms\Console\Commands\CheckextensionCommand; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; @@ -46,6 +47,7 @@ $application->add(new ConfigureextensionCommand($settings, $logger, $translator, $application->add(new UploadextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new PackageextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new ReloadextensionCommand($settings, $logger, $translator, $extmgr)); +$application->add(new CheckextensionCommand($settings, $logger, $translator, $extmgr)); if(isset($GLOBALS['SEEDDMS_HOOKS']['console'])) { foreach($GLOBALS['SEEDDMS_HOOKS']['console'] as $hookObj) { From 41e7c6eb930cb259e781c29653591591d9a35850 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 10:33:12 +0100 Subject: [PATCH 12/38] do not use same variable for list of ext configurations and single configuration --- utils/Commands/ListextensionCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/Commands/ListextensionCommand.php b/utils/Commands/ListextensionCommand.php index 6e9fc1bd2..b6b7bcf28 100644 --- a/utils/Commands/ListextensionCommand.php +++ b/utils/Commands/ListextensionCommand.php @@ -60,8 +60,8 @@ class ListextensionCommand extends Command $enabled = 0; $disabled = 0; $haserror = 0; - $extconf = $extmgr->getExtensionConfiguration(); - foreach ($extconf as $extname=>$extconf) { + $extconfs = $extmgr->getExtensionConfiguration(); + foreach ($extconfs as $extname=>$extconf) { if (!$settings->extensionIsDisabled($extname)) { $enabled++; $output->writeln(sprintf(''.$outformat.'', '*', $extname, $extconf['version'], $extconf['releasedate'])); From f6b3081c5b02aca5fe1fe91c39b06d5642bad93b Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 11:05:14 +0100 Subject: [PATCH 13/38] move class SeedDMS_Extension_Mgr into namespace Seeddms\Seeddms --- inc/inc.ClassExtensionMgr.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 66f8f4217..fa5cb7c70 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -14,6 +14,8 @@ * @version Release: @package_version@ */ +namespace Seeddms\Seeddms; + /** * Class to represent an extension manager * @@ -25,7 +27,7 @@ * @copyright 2011 Uwe Steinmann * @version Release: @package_version@ */ -class SeedDMS_Extension_Mgr { +class ExtensionMgr { /** * @var string $extdir directory where extensions are located * @access protected @@ -440,7 +442,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); foreach($extconf['constraints']['depends'] as $dkey=>$dval) { switch($dkey) { case 'seeddms': - $version = new SeedDMS_Version; + $version = new Version; if(is_array($dval)) { $fullfill = false; foreach($dval as $ddval) { @@ -725,3 +727,5 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); return $this->errmsgs; } /* }}} */ } + +class_alias('Seeddms\Seeddms\ExtensionMgr', 'SeedDMS_Extension_Mgr'); From 83d08d1acc1fb64069958a29a190ad3804933ef9 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 11:06:25 +0100 Subject: [PATCH 14/38] move class into namespace Seeddms\Seeddms --- inc/inc.Version.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/inc/inc.Version.php b/inc/inc.Version.php index 5a9b303b0..0642b3cd8 100644 --- a/inc/inc.Version.php +++ b/inc/inc.Version.php @@ -18,7 +18,9 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -class SeedDMS_Version { /* {{{ */ +namespace Seeddms\Seeddms; + +class Version { /* {{{ */ const _number = "5.1.43"; const _string = "SeedDMS"; @@ -47,7 +49,7 @@ class SeedDMS_Version { /* {{{ */ function banner() { /* {{{ */ return self::_string .", ". self::_number; - } + } /* }}} */ /** * Compare two version @@ -84,3 +86,4 @@ class SeedDMS_Version { /* {{{ */ } /* }}} */ +class_alias('Seeddms\Seeddms\Version', 'SeedDMS_Version'); From 6d69af7d4e107b3202f9c2bdd4344845a7490142 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 11:06:53 +0100 Subject: [PATCH 15/38] add class alias to make old extensions work --- inc/inc.ClassSession.php | 4 ++++ inc/inc.ClassSettings.php | 1 + 2 files changed, 5 insertions(+) diff --git a/inc/inc.ClassSession.php b/inc/inc.ClassSession.php index f86199253..9ae55d518 100644 --- a/inc/inc.ClassSession.php +++ b/inc/inc.ClassSession.php @@ -419,6 +419,8 @@ class Session { } +class_alias('Seeddms\Seeddms\Session', 'SeedDMS_Session'); + /** * Class for managing sessions * @@ -533,3 +535,5 @@ class SessionMgr { } /* }}} */ } + +class_alias('Seeddms\Seeddms\SessionMgr', 'SeedDMS_SessionMgr'); diff --git a/inc/inc.ClassSettings.php b/inc/inc.ClassSettings.php index ebb0bdf9a..5769540a1 100644 --- a/inc/inc.ClassSettings.php +++ b/inc/inc.ClassSettings.php @@ -1881,3 +1881,4 @@ class Settings { /* {{{ */ } /* }}} */ +class_alias('Seeddms\Seeddms\Settings', 'SeedDMS_Settings'); From c8dba8881463e2e6f20b6edcbad57ced569dc9db Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 12:03:08 +0100 Subject: [PATCH 16/38] use propper namespace for classes --- inc/inc.ClassExtensionMgr.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index fa5cb7c70..146ae72cb 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -260,14 +260,14 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); unlink ($destination); } - $zip = new ZipArchive(); - if (!$zip->open($destination, ZIPARCHIVE::CREATE)) { + $zip = new \ZipArchive(); + if (!$zip->open($destination, \ZipArchive::CREATE)) { return false; } $source = str_replace('\\', '/', realpath($source)); if (is_dir($source) === true) { - $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST); + $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST); if ($include_dir) { $arr = explode("/",$source); @@ -328,7 +328,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); $tmpfile = $this->cachedir."/".$extname."-".$version.".zip"; } - if(!SeedDMS_Extension_Mgr::Zip($this->extdir."/".$extname, $tmpfile)) { + if(!ExtensionMgr::Zip($this->extdir."/".$extname, $tmpfile)) { return false; } // $cmd = "cd ".$this->extdir."/".$extname."; zip -r ".$tmpfile." ."; @@ -525,7 +525,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); $this->errmsgs[] = "Cannot create temp. extension directory"; return false; } - $zip = new ZipArchive; + $zip = new \ZipArchive; $res = $zip->open($file); if ($res === TRUE) { $zip->extractTo($newdir); @@ -590,7 +590,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); * single lines. Each line is either a comment if it starts with an '#' * or a json encoded array containing the extension configuration. * - * Run SeedDMS_Extension_Mgr::updateExtensionList() to ensure the + * Run Seeddms\Seeddms\ExtensionMgr::updateExtensionList() to ensure the * currently cached extension list file is up to date. * * @return string[] list of json strings or comments @@ -610,7 +610,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); * a list of extension configurations. Only the most recent version * of an extension will be included. * - * Run SeedDMS_Extension_Mgr::updateExtensionList() to ensure the + * Run Seeddms\Seeddms\ExtensionMgr::updateExtensionList() to ensure the * currently cached extension list file is up to date. * * @return array[] list of extension configurations @@ -641,7 +641,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); * a list of extension configurations. Only those extensions will * be included which maches the given name. * - * Run SeedDMS_Extension_Mgr::updateExtensionList() to ensure the + * Run Seeddms\Seeddms\ExtensionMgr::updateExtensionList() to ensure the * currently cached extension list file is up to date. * * @return array[] list of extension configurations @@ -657,7 +657,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); } } } - uksort($result, function($a, $b){return SeedDMS_Extension_Mgr::cmpVersion($b, $a);}); + uksort($result, function($a, $b){return ExtensionMgr::cmpVersion($b, $a);}); return $result; } /* }}} */ From 65dfe07a160c75b2bdfc13ba2f16f821a0750fd0 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 12:07:03 +0100 Subject: [PATCH 17/38] add changes for 5.1.43 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2acc54000..2d6784242 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ - add Slim middleware for Basic authentication (can be used by extensions) - rest api endpoint 'statstotal' returns number of groups and categories - add new command line program utils/console +- major code polishing -------------------------------------------------------------------------------- Changes in version 5.1.42 From 7414443acbaf84bf2629a43f07f2ceb19c2418fa Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 15:05:42 +0100 Subject: [PATCH 18/38] nicer formating for better readability --- composer-dist.json | 11 ++++++++++- composer.json | 17 +++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/composer-dist.json b/composer-dist.json index f9f5bbfb4..ef9159626 100644 --- a/composer-dist.json +++ b/composer-dist.json @@ -22,7 +22,16 @@ "psr-4": { "SeedDMS\\Console\\": "seeddms/utils" }, - "classmap": ["seeddms/inc/inc.ClassTranslator.php", "seeddms/inc/inc.ClassSettings.php", "seeddms/inc/inc.Version.php", "seeddms/inc/inc.ClassViewCommon.php", "seeddms/inc/inc.ClassControllerCommon.php", "seeddms/inc/inc.ClassController.php", "seeddms/inc/inc.ClassSession.php"] + "classmap": [ + "seeddms/inc/inc.ClassTranslator.php", + "seeddms/inc/inc.ClassSettings.php", + "seeddms/inc/inc.Version.php", + "seeddms/inc/inc.ClassViewCommon.php", + "seeddms/inc/inc.ClassControllerCommon.php", + "seeddms/inc/inc.ClassController.php", + "seeddms/inc/inc.ClassSession.php", + "seeddms/inc/inc.ClassUtilities.php" + ] }, "require": { "pear/http_request2": "^2", diff --git a/composer.json b/composer.json index bb53cce27..97335a73e 100644 --- a/composer.json +++ b/composer.json @@ -20,10 +20,19 @@ } }, "autoload": { - "psr-4": { - "Seeddms\\Console\\": "utils" - }, - "classmap": ["inc/inc.ClassTranslator.php", "inc/inc.ClassSettings.php", "inc/inc.Version.php", "inc/inc.ClassViewCommon.php", "inc/inc.ClassControllerCommon.php", "inc/inc.ClassController.php", "inc/inc.ClassSession.php"] + "psr-4": { + "Seeddms\\Console\\": "utils" + }, + "classmap": [ + "inc/inc.ClassTranslator.php", + "inc/inc.ClassSettings.php", + "inc/inc.Version.php", + "inc/inc.ClassViewCommon.php", + "inc/inc.ClassControllerCommon.php", + "inc/inc.ClassController.php", + "inc/inc.ClassSession.php", + "inc/inc.ClassUtilities.php" + ] }, "require": { "php": ">=8.2.0", From 2d963a3c6f00d94fbc10b7edf21894924370b4dd Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 15:06:30 +0100 Subject: [PATCH 19/38] use some functions into class Utitilities --- inc/inc.ClassUtilities.php | 94 ++++++++++++++++++++++++++++++++++++++ inc/inc.Utils.php | 77 +------------------------------ 2 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 inc/inc.ClassUtilities.php diff --git a/inc/inc.ClassUtilities.php b/inc/inc.ClassUtilities.php new file mode 100644 index 000000000..eeb853c62 --- /dev/null +++ b/inc/inc.ClassUtilities.php @@ -0,0 +1,94 @@ + + * @copyright Copyright (C) 2025 Uwe Steinmann + * @version Release: @package_version@ + */ + +namespace Seeddms\Seeddms; + +/** + * Class with various methods + * + * @category DMS + * @package SeedDMS + * @author Uwe Steinmann + * @copyright Copyright (C) 2025 Uwe Steinmann + * @version Release: @package_version@ + */ +class Utilities { /* {{{ */ + + /** + * Recursively remove a directory on disc + * + * @param string $dir name of directory + */ + static public function rrmdir($dir) { /* {{{ */ + if (is_dir($dir)) { + $objects = scandir($dir); + foreach ($objects as $object) { + if ($object != "." && $object != "..") { + if (filetype($dir."/".$object) == "dir") self::rrmdir($dir."/".$object); else unlink($dir."/".$object); + } + } + reset($objects); + rmdir($dir); + } + } /* }}} */ + + /** + * Create a random string + * + * @param integer $n number of chars + * @param string $alph alphabet used as source for chars + * @return string random string + */ + static public function makeRandomString($n, $alph = "0123456789abcdefghijklmnopqrstuvwxyz") { /* {{{ */ + $s = ""; + for ($i = 0; $i != $n; ++$i) + $s .= $alph[mt_rand(0, 35)]; + return $s; + } /* }}} */ + + /** + * Create a real uniqid for cryptographic purposes + * + * @ return string + */ + static public function uniqidReal($lenght = 13) { /* {{{ */ + // uniqid gives 13 chars, but you could adjust it to your needs. + if (function_exists("random_bytes")) { + $bytes = random_bytes(ceil($lenght / 2)); + } elseif (function_exists("openssl_random_pseudo_bytes")) { + $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2)); + } else { + throw new Exception("no cryptographically secure random function available"); + } + return substr(bin2hex($bytes), 0, $lenght); + } /* }}} */ + + /** + * Return nonce for CSP + * + * @return string + */ + static public function createNonce() { /* {{{ */ + $length = 16; + $usable = true; + $bytes = openssl_random_pseudo_bytes($length, $usable); + if ($usable === false) { + // weak + // @TODO do something? + } + return base64_encode($bytes); + } /* }}} */ + +} /* }}} */ + +class_alias('Seeddms\Seeddms\Utilities', 'SeedDMS_Utils'); diff --git a/inc/inc.Utils.php b/inc/inc.Utils.php index b86b2031c..ec8c69cb1 100644 --- a/inc/inc.Utils.php +++ b/inc/inc.Utils.php @@ -650,7 +650,7 @@ function checkFormKey($formid='', $method='POST') { /* {{{ */ * quota is reached. Negative values indicate a disk usage above quota. */ function checkQuota($user) { /* {{{ */ - global $settings, $dms; + global $settings; /* check if quota is turn off system wide */ if($settings->_quota == 0) @@ -1000,39 +1000,6 @@ function seed_pass_verify($password, $hash) { /* {{{ */ return $hash === md5($password); } /* }}} */ -/** - * Return nonce for CSP - * - * @return string - */ -function createNonce() { /* {{{ */ - $length = 16; - $usable = true; - $bytes = openssl_random_pseudo_bytes($length, $usable); - if ($usable === false) { - // weak - // @TODO do something? - } - return base64_encode($bytes); -} /* }}} */ - -/** - * Create a real uniqid for cryptographic purposes - * - * @ return string - */ -function uniqidReal($lenght = 13) { - // uniqid gives 13 chars, but you could adjust it to your needs. - if (function_exists("random_bytes")) { - $bytes = random_bytes(ceil($lenght / 2)); - } elseif (function_exists("openssl_random_pseudo_bytes")) { - $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2)); - } else { - throw new Exception("no cryptographically secure random function available"); - } - return substr(bin2hex($bytes), 0, $lenght); -} - /** * Compare function for sorting users by login * @@ -1265,47 +1232,7 @@ function getMandatoryApprovers($folder, $document, $user) { /* {{{ */ return $approvers; } /* }}} */ -/** - * Class with various utility methods - * - * This class will sooner or later comprise the functions above - * - */ -class SeedDMS_Utils { /* {{{ */ - - /** - * Recursively remove a directory on disc - * - * @param string $dir name of directory - */ - static public function rrmdir($dir) { /* {{{ */ - if (is_dir($dir)) { - $objects = scandir($dir); - foreach ($objects as $object) { - if ($object != "." && $object != "..") { - if (filetype($dir."/".$object) == "dir") self::rrmdir($dir."/".$object); else unlink($dir."/".$object); - } - } - reset($objects); - rmdir($dir); - } - } /* }}} */ - - /** - * Create a random string - * - * @param integer $n number of chars - * @param string $alph alphabet used as source for chars - * @return string random string - */ - static public function makeRandomString($n, $alph = "0123456789abcdefghijklmnopqrstuvwxyz") { /* {{{ */ - $s = ""; - for ($i = 0; $i != $n; ++$i) - $s .= $alph[mt_rand(0, 35)]; - return $s; - } /* }}} */ - -} /* }}} */ +require_once "inc/inc.ClassUtilities.php"; /** * Class for creating encrypted api keys From 220b633e4cfcacd1b899b48c6de130566c72308e Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 15:07:10 +0100 Subject: [PATCH 20/38] use new class Utilities --- views/bootstrap/class.Bootstrap.php | 3 ++- views/bootstrap4/class.Bootstrap4.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/views/bootstrap/class.Bootstrap.php b/views/bootstrap/class.Bootstrap.php index 30e561d44..d9dc03ebc 100644 --- a/views/bootstrap/class.Bootstrap.php +++ b/views/bootstrap/class.Bootstrap.php @@ -19,6 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +use Seeddms\Seeddms\Utilities; class SeedDMS_Theme_Style extends SeedDMS_View_Common { /** @@ -180,7 +181,7 @@ background-image: linear-gradient(to bottom, #882222, #111111);; } /* }}} */ function htmlAddJsHeader($script) { /* {{{ */ - $nonce = createNonce(); + $nonce = Utilities::createNonce(); $this->nonces[] = $nonce; $this->extraheader['js'] .= ''."\n"; } /* }}} */ diff --git a/views/bootstrap4/class.Bootstrap4.php b/views/bootstrap4/class.Bootstrap4.php index 57a52d96a..4a9043612 100644 --- a/views/bootstrap4/class.Bootstrap4.php +++ b/views/bootstrap4/class.Bootstrap4.php @@ -19,6 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +use Seeddms\Seeddms\Utilities; class SeedDMS_Theme_Style extends SeedDMS_View_Common { /** @@ -182,7 +183,7 @@ background-image: linear-gradient(to bottom, #882222, #111111);; } /* }}} */ function htmlAddJsHeader($script) { /* {{{ */ - $nonce = createNonce(); + $nonce = Utilities::createNonce(); $this->nonces[] = $nonce; $this->extraheader['js'] .= ''."\n"; } /* }}} */ From 0d23b652717bcf4cd83aa46362f86ae5c1d98e19 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 15:07:25 +0100 Subject: [PATCH 21/38] update copyright year --- inc/inc.ClassTranslator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/inc.ClassTranslator.php b/inc/inc.ClassTranslator.php index 66ed30927..6598eb4c3 100644 --- a/inc/inc.ClassTranslator.php +++ b/inc/inc.ClassTranslator.php @@ -21,7 +21,7 @@ use SeedDMS_Core_AttributeDefinition; * @category DMS * @package SeedDMS * @author Uwe Steinmann - * @copyright Copyright (C) 2011 Uwe Steinmann + * @copyright Copyright (C) 2025 Uwe Steinmann * @version Release: @package_version@ */ class Translator { /* {{{ */ From e105c85b226fb422a09f312e65d37f90fd258088 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 16:16:33 +0100 Subject: [PATCH 22/38] check for configuration in its regular place --- utils/console | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/utils/console b/utils/console index 9b853905d..d402da61d 100755 --- a/utils/console +++ b/utils/console @@ -23,7 +23,14 @@ use Seeddms\Console\Commands\CheckextensionCommand; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; -$settings = new Settings(); +/* Check if configuration is at regular place. Otherwise set + * SEEDDMS_CONFIG_FILE in your shell. + */ +if (file_exists(__DIR__.'/../../conf/settings.xml')) + $settings = new Settings(__DIR__.'/../../conf/settings.xml'); +else + $settings = new Settings(); + /* For now includce inc.Language.php, because it defines the old * translation functions (e.g. getMLText()), which are still used * by many extensions. From b7bd251bc63d9056b47467b295f98d521e59cc04 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 16:23:24 +0100 Subject: [PATCH 23/38] no need to write configuration file --- utils/Commands/UploadextensionCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/Commands/UploadextensionCommand.php b/utils/Commands/UploadextensionCommand.php index 65a75817f..dd2f708d3 100644 --- a/utils/Commands/UploadextensionCommand.php +++ b/utils/Commands/UploadextensionCommand.php @@ -52,12 +52,12 @@ class UploadextensionCommand extends Command $extmgr = $this->extmgr; $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); - +/* if (!is_writable($settings->_configFilePath)) { $output->writeln(sprintf("The configuration file '%s' is not writable by the system user running this script.", $settings->_configFilePath)); return Command::FAILURE; } - + */ if (!is_writable($settings->_cacheDir)) { $output->writeln(sprintf("The cache dir '%s' is not writable for the system user running this script.", $settings->_cacheDir)); return Command::FAILURE; From 25dd7873c92e19d666c9c9462adee3ce1b64dc2a Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 16:54:58 +0100 Subject: [PATCH 24/38] use new Seeddms\Seeddms\Utilities --- inc/inc.ClassExtensionMgr.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 146ae72cb..02019044b 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -16,6 +16,8 @@ namespace Seeddms\Seeddms; +use Seeddms\Seeddms\Utilities; + /** * Class to represent an extension manager * @@ -519,7 +521,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); $newdir = addDirSep($this->cachedir)."ext.new"; /* First remove a left over from a previous extension */ if(file_exists($newdir)) { - SeedDMS_Utils::rrmdir($newdir); + Utilities::rrmdir($newdir); } if(!mkdir($newdir, 0755)) { $this->errmsgs[] = "Cannot create temp. extension directory"; @@ -539,7 +541,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); /* Check if extension is complete and fullfills the constraints */ if(!self::checkExtensionByDir($newdir)) { - SeedDMS_Utils::rrmdir($newdir); + Utilities::rrmdir($newdir); return false; } @@ -550,11 +552,11 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); if(!is_dir($this->extdir)) { if(!mkdir($this->extdir, 0755)) { $this->errmsgs[] = "Cannot create extension directory"; - SeedDMS_Utils::rrmdir($newdir); + Utilities::rrmdir($newdir); return false; } } elseif(is_dir($this->extdir ."/". $extname)) { - SeedDMS_Utils::rrmdir($this->extdir ."/". $extname); + Utilities::rrmdir($this->extdir ."/". $extname); } /* Move the temp. created ext directory to the final location */ /* rename() may fail if dirs are moved from one device to another. @@ -576,7 +578,7 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); * has been copied. */ $this->errmsgs[] = "Cannot move temp. extension directory to final destination"; - SeedDMS_Utils::rrmdir($this->extdir ."/". $extname); + Utilities::rrmdir($this->extdir ."/". $extname); return false; } From f83a43671b62e1485529d75950ec863e8a21d117 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Fri, 14 Nov 2025 16:55:17 +0100 Subject: [PATCH 25/38] get file name from option --- utils/Commands/UploadextensionCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/Commands/UploadextensionCommand.php b/utils/Commands/UploadextensionCommand.php index dd2f708d3..4873bc545 100644 --- a/utils/Commands/UploadextensionCommand.php +++ b/utils/Commands/UploadextensionCommand.php @@ -63,6 +63,7 @@ class UploadextensionCommand extends Command return Command::FAILURE; } + $filename = $input->getOption('file'); if (!$extmgr->updateExtension($filename)) { foreach ($extmgr->getErrorMsgs() as $msg) { $output->writeln(sprintf("%s", $msg)); From 4be5afcef861abf7b1040d65fbaa80f5e28ac61a Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 11:26:31 +0100 Subject: [PATCH 26/38] add method setRepositoryUrl() --- inc/inc.ClassExtensionMgr.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 02019044b..455f480a6 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -179,6 +179,10 @@ class ExtensionMgr { return $this->cachedir."/extensions.php"; } /* }}} */ + public function setRepositoryUrl($reposurl) { /* {{{ */ + $this->reposurl = $reposurl; + } /* }}} */ + /** * Get the configuration of extensions * From 3efcf064f20fa69d8b053f24c959d117f3472a51 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 11:27:06 +0100 Subject: [PATCH 27/38] better documentation of checkExtensionByName() --- inc/inc.ClassExtensionMgr.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 455f480a6..08ca88d15 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -410,14 +410,19 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); } /* }}} */ /** - * Check content of extension directory or configuration of extension + * Check configuration of extension * - * @param string|array $dir full path to extension directory or extension name - * or an array containing the configuration. - * @param array $options array with options elements 'noconstraints' and 'nofiles'. - * Set 'noconstraints' to true if - * constraints to local seeddms installation shall not be checked. Set 'nofiles' - * to true to turn off checking of files + * This method checks if the configurations of an extension is complete + * and all dependencies specified in the configuration are met. + * + * @param string $extname not used anymore. Was previously use to store + * result of the check into $this->configcache, but this method can be + * used for installed extensions and those in the repository, which makes + * the use of a cache useless. + * @param array $extconf extension configuration to be checked + * @param array $options array with option element 'noconstraints'. + * Set 'noconstraints' to true if constraints to local seeddms + * installation shall not be checked. * @return boolean true if check was successful, otherwise false */ public function checkExtensionByName($extname, $extconf, $options=array()) { /* {{{ */ From a8c3650725672990dc52556ca68176d649b85c81 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 11:27:38 +0100 Subject: [PATCH 28/38] check if downloading a file from the repository succeeded --- inc/inc.ClassExtensionMgr.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 08ca88d15..7fc372905 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -712,9 +712,13 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); */ public function getExtensionFromRepository($file) { /* {{{ */ $content = file_get_contents($this->reposurl."/".$file, false, $this->getStreamContext()); - $tmpfile = tempnam(sys_get_temp_dir(), ''); - file_put_contents($tmpfile, $content); - return $tmpfile; + if ($content) { + $tmpfile = tempnam(sys_get_temp_dir(), ''); + file_put_contents($tmpfile, $content); + return $tmpfile; + } else { + return false; + } } /* }}} */ /** From 851d338d4a5758b4f29cb6078eb4e09b6255ee5e Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 11:28:33 +0100 Subject: [PATCH 29/38] tag text of question --- utils/Commands/ClearcacheCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/Commands/ClearcacheCommand.php b/utils/Commands/ClearcacheCommand.php index 6d9842803..7627d2321 100644 --- a/utils/Commands/ClearcacheCommand.php +++ b/utils/Commands/ClearcacheCommand.php @@ -57,7 +57,7 @@ class ClearcacheCommand extends Command if (!$input->getOption('force')) { $helper = new QuestionHelper(); - $question = new ConfirmationQuestion('Do you really want to clear the cache? ', false); + $question = new ConfirmationQuestion('Do you really want to clear the cache? ', false); if (!$helper->ask($input, $output, $question)) { return Command::SUCCESS; } From c0a6cb5d34446b4c5f14a730605e2ecf7758fe8e Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 11:29:17 +0100 Subject: [PATCH 30/38] add new commands to download and list extensions from/in repository --- utils/Commands/DownloadextensionCommand.php | 135 ++++++++++++++++++ utils/Commands/RepositoryextensionCommand.php | 101 +++++++++++++ utils/console | 4 + 3 files changed, 240 insertions(+) create mode 100644 utils/Commands/DownloadextensionCommand.php create mode 100644 utils/Commands/RepositoryextensionCommand.php diff --git a/utils/Commands/DownloadextensionCommand.php b/utils/Commands/DownloadextensionCommand.php new file mode 100644 index 000000000..3aaebf2a5 --- /dev/null +++ b/utils/Commands/DownloadextensionCommand.php @@ -0,0 +1,135 @@ +settings = $settings; + $this->logger = $logger; + $this->translator = $translator; + $this->extmgr = $extmgr; + parent::__construct(); + } + + protected function configure() + { + $this->setName('ext:download') + ->setDescription('Download extension from repository') + ->setHelp('') + ->addOption('url', '', InputOption::VALUE_REQUIRED, 'Url of repository.', null) + ->addOption('name', '', InputOption::VALUE_REQUIRED, 'Name of extension.', null) + ->addOption('extversion', '', InputOption::VALUE_REQUIRED, 'Version of extension.', null) + ->addOption('no-upload', '', InputOption::VALUE_NONE, 'Just download extension file') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $settings = $this->settings; + $logger = $this->logger; + $translator = $this->translator; + $extmgr = $this->extmgr; + + $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + + $reposurl = $input->getOption('url'); + if($reposurl) + $extmgr->setRepositoryUrl($reposurl); + + $extname = $input->getOption('name'); + if (!$extname) { + $output->writeln(sprintf("You must specify an extension name.")); + return Command::FAILURE; + } + $extversion = $input->getOption('extversion'); + $noupload = $input->getOption('no-upload'); + + /* Get a list of available extensions from the repository */ + if($ret = $extmgr->updateExtensionList('', true)) { + // list of installed extensions + $extconfs = $extmgr->getExtensionConfiguration(); + // list of extensions in repository, this will just return the + // latest version of an extension + $list = $extmgr->getExtensionList(); + if (isset($list[$extname])) { + /* if specific version is not requested, then take the + * last version of the extension. + */ + if (!$extversion) + $extversion = $list[$extname]['version']; + $extversions = $extmgr->getExtensionListByName($extname); + if (isset($extversions[$extversion])) { + if ($tmpfile = $extmgr->getExtensionFromRepository($extversions[$extversion]['filename'])) { + $output->writeln(sprintf("Downloaded extension file '%s'", $extversions[$extversion]['filename'])); + if (!$noupload) { + if ($extconfs[$extname]) { + if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($extconfs[$extname]['version'], $extversion)) { + $helper = new QuestionHelper(); + $question = new ConfirmationQuestion(sprintf("You are updating extension '%s' with an older version %s < %s. Do you want to proceed? ", $extname, $extversion, $extconfs[$extname]['version']), false); + if (!$helper->ask($input, $output, $question)) { + unlink($tmpfile); + return Command::SUCCESS; + } + } + $output->writeln(sprintf("Updating existing extension '%s' with version %s", $extname, $extversion)); + } else { + $output->writeln(sprintf("Installing new extension '%s' with version %s", $extname, $extversion)); + } + if (!$extmgr->updateExtension($tmpfile)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + unlink($tmpfile); + return Command::FAILURE; + } else { + unlink($tmpfile); + } + } else { + rename($tmpfile, $extversions[$extversion]['filename']); + } + } else { + $output->writeln(sprintf("Could not download file '%s'", $list[$extname]['filename'])); + } + return Command::SUCCESS; + } else { + $output->writeln(sprintf("Requested version '%s' of extension '%s' does not exist in repository.", $extversion, $extname)); + return Command::FAILURE; + } + } else { + $output->writeln(sprintf("Extension '%s' does not exist in repository.", $extname)); + return Command::FAILURE; + } + } else { + $output->writeln(sprintf("Could not get extension list from repository.", $filename)); + return Command::FAILURE; + } + } +} + +// vim: ts=4 sw=4 expandtab diff --git a/utils/Commands/RepositoryextensionCommand.php b/utils/Commands/RepositoryextensionCommand.php new file mode 100644 index 000000000..9d8a33f67 --- /dev/null +++ b/utils/Commands/RepositoryextensionCommand.php @@ -0,0 +1,101 @@ +settings = $settings; + $this->logger = $logger; + $this->translator = $translator; + $this->extmgr = $extmgr; + parent::__construct(); + } + + protected function configure() + { + $this->setName('ext:repository') + ->setDescription('Get list of extensions from repository') + ->setHelp('') + ->addOption('url', '', InputOption::VALUE_REQUIRED, 'Url of repository.', null) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $settings = $this->settings; + $logger = $this->logger; + $translator = $this->translator; + $extmgr = $this->extmgr; + + $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + + $reposurl = $input->getOption('url'); + if($reposurl) + $extmgr->setRepositoryUrl($reposurl); + + /* Get a list of available extensions from the repository */ + if($ret = $extmgr->updateExtensionList('', true)) { +// $output->writeln(sprintf("Updated extension list from repository.")); + // list of installed extensions + $extconfs = $extmgr->getExtensionConfiguration(); + // list of extensions in repository, this will just return the + // latest version of an extension + $list = $extmgr->getExtensionList(); +// print_r($list); + $tabledata = []; + foreach($list as $extname=>$data) { + $extversions = $extmgr->getExtensionListByName($extname); +// print_r($extversions); + $allowedversions = []; + foreach($extversions as $version=>$extversion) { + $check = $extmgr->checkExtensionByName($extname, $extversion); + if ($check) { + $allowedversions[] = ''.$version.''; + } else { + $allowedversions[] = ''.$version.''; + } + } + $tabledata[$extname] = [ + $extname, + $data['title'], + new TableCell(implode("\n", $allowedversions), ['rowspan' => count($allowedversions)]), + isset($extconfs[$extname]['version']) ? $extconfs[$extname]['version'] : '']; + } + $table = new Table($output); + $table + ->setHeaders(['Name', 'Title', 'Rep. ver.', 'Inst. ver.']) + ->setRows($tabledata); + $table->render(); + return Command::SUCCESS; + } else { + $output->writeln(sprintf("Could not get extension list from repository.", $filename)); + return Command::FAILURE; + } + } +} + +// vim: ts=4 sw=4 expandtab diff --git a/utils/console b/utils/console index d402da61d..9dc4c8c4b 100755 --- a/utils/console +++ b/utils/console @@ -20,6 +20,8 @@ use Seeddms\Console\Commands\UploadextensionCommand; use Seeddms\Console\Commands\PackageextensionCommand; use Seeddms\Console\Commands\ReloadextensionCommand; use Seeddms\Console\Commands\CheckextensionCommand; +use Seeddms\Console\Commands\RepositoryextensionCommand; +use Seeddms\Console\Commands\DownloadextensionCommand; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; @@ -55,6 +57,8 @@ $application->add(new UploadextensionCommand($settings, $logger, $translator, $e $application->add(new PackageextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new ReloadextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new CheckextensionCommand($settings, $logger, $translator, $extmgr)); +$application->add(new RepositoryextensionCommand($settings, $logger, $translator, $extmgr)); +$application->add(new DownloadextensionCommand($settings, $logger, $translator, $extmgr)); if(isset($GLOBALS['SEEDDMS_HOOKS']['console'])) { foreach($GLOBALS['SEEDDMS_HOOKS']['console'] as $hookObj) { From 6ca4c785c14c90409c7cfbc78c90cbda8e9eedd3 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 13:45:29 +0100 Subject: [PATCH 31/38] fix comparision of versions --- utils/Commands/DownloadextensionCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/Commands/DownloadextensionCommand.php b/utils/Commands/DownloadextensionCommand.php index 3aaebf2a5..1e31d410d 100644 --- a/utils/Commands/DownloadextensionCommand.php +++ b/utils/Commands/DownloadextensionCommand.php @@ -89,7 +89,7 @@ class DownloadextensionCommand extends Command $output->writeln(sprintf("Downloaded extension file '%s'", $extversions[$extversion]['filename'])); if (!$noupload) { if ($extconfs[$extname]) { - if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($extconfs[$extname]['version'], $extversion)) { + if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($extconfs[$extname]['version'], $extversion) > 0) { $helper = new QuestionHelper(); $question = new ConfirmationQuestion(sprintf("You are updating extension '%s' with an older version %s < %s. Do you want to proceed? ", $extname, $extversion, $extconfs[$extname]['version']), false); if (!$helper->ask($input, $output, $question)) { From b81fb224d5aa0a3af0cf79fea3bf844bdd1e84f0 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 20:43:41 +0100 Subject: [PATCH 32/38] better documentation of updateExtensionList() --- inc/inc.ClassExtensionMgr.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/inc.ClassExtensionMgr.php b/inc/inc.ClassExtensionMgr.php index 7fc372905..e83b2f928 100644 --- a/inc/inc.ClassExtensionMgr.php +++ b/inc/inc.ClassExtensionMgr.php @@ -675,6 +675,9 @@ $EXT_CONF = '.var_export($EXT_CONF, true).';'); /** * Import list of extension from repository * + * Will also update the list in the cache, which is used by getExtensionList() + * and getExtensionListByName(). + * * @param boolean $force force download even if file already exists */ public function updateExtensionList($version='', $force=false) { /* {{{ */ From 239586ed8779db28bd79aa61888bd8b8ac7010a7 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sat, 15 Nov 2025 21:22:45 +0100 Subject: [PATCH 33/38] fix output of message --- utils/Commands/RepositoryextensionCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/Commands/RepositoryextensionCommand.php b/utils/Commands/RepositoryextensionCommand.php index 9d8a33f67..26d10ed65 100644 --- a/utils/Commands/RepositoryextensionCommand.php +++ b/utils/Commands/RepositoryextensionCommand.php @@ -92,7 +92,7 @@ class RepositoryextensionCommand extends Command $table->render(); return Command::SUCCESS; } else { - $output->writeln(sprintf("Could not get extension list from repository.", $filename)); + $output->writeln(sprintf("Could not get extension list from repository.")); return Command::FAILURE; } } From 8b60aea55d5b91730b0a9d5b3e46ec81db9e9069 Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sun, 16 Nov 2025 15:50:22 +0100 Subject: [PATCH 34/38] check if $extconfs[$extname] exists --- utils/Commands/DownloadextensionCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/Commands/DownloadextensionCommand.php b/utils/Commands/DownloadextensionCommand.php index 1e31d410d..2a021eeea 100644 --- a/utils/Commands/DownloadextensionCommand.php +++ b/utils/Commands/DownloadextensionCommand.php @@ -88,7 +88,7 @@ class DownloadextensionCommand extends Command if ($tmpfile = $extmgr->getExtensionFromRepository($extversions[$extversion]['filename'])) { $output->writeln(sprintf("Downloaded extension file '%s'", $extversions[$extversion]['filename'])); if (!$noupload) { - if ($extconfs[$extname]) { + if (isset($extconfs[$extname])) { if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($extconfs[$extname]['version'], $extversion) > 0) { $helper = new QuestionHelper(); $question = new ConfirmationQuestion(sprintf("You are updating extension '%s' with an older version %s < %s. Do you want to proceed? ", $extname, $extversion, $extconfs[$extname]['version']), false); From fec5875f0749345778c75d18c0e632a18d68f74c Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sun, 16 Nov 2025 15:50:49 +0100 Subject: [PATCH 35/38] new command to update from repository --- utils/Commands/RepositoryextensionCommand.php | 2 + utils/Commands/UpdateextensionCommand.php | 156 ++++++++++++++++++ utils/console | 2 + 3 files changed, 160 insertions(+) create mode 100644 utils/Commands/UpdateextensionCommand.php diff --git a/utils/Commands/RepositoryextensionCommand.php b/utils/Commands/RepositoryextensionCommand.php index 26d10ed65..f50e5d247 100644 --- a/utils/Commands/RepositoryextensionCommand.php +++ b/utils/Commands/RepositoryextensionCommand.php @@ -8,6 +8,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Question\Question; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; diff --git a/utils/Commands/UpdateextensionCommand.php b/utils/Commands/UpdateextensionCommand.php new file mode 100644 index 000000000..e6ee4dd4e --- /dev/null +++ b/utils/Commands/UpdateextensionCommand.php @@ -0,0 +1,156 @@ +settings = $settings; + $this->logger = $logger; + $this->translator = $translator; + $this->extmgr = $extmgr; + parent::__construct(); + } + + protected function configure() + { + $this->setName('ext:update') + ->setDescription('Check for extension upates') + ->setHelp('') + ->addOption('url', '', InputOption::VALUE_REQUIRED, 'Url of repository.', null) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $settings = $this->settings; + $logger = $this->logger; + $translator = $this->translator; + $extmgr = $this->extmgr; + + $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + + $reposurl = $input->getOption('url'); + if($reposurl) + $extmgr->setRepositoryUrl($reposurl); + + $updates = []; + $installs = []; + /* Get a list of available extensions from the repository */ + if($ret = $extmgr->updateExtensionList('', true)) { +// $output->writeln(sprintf("Updated extension list from repository.")); + // list of installed extensions + $extconfs = $extmgr->getExtensionConfiguration(); + // list of extensions in repository, this will just return the + // latest version of an extension + $list = $extmgr->getExtensionList(); +// print_r($list); + foreach($list as $extname=>$data) { + $extversions = $extmgr->getExtensionListByName($extname); +// print_r($extversions); + $updates[$extname] = []; + $installs[$extname] = []; + $allowedversions = []; + foreach($extversions as $version=>$extversion) { + $check = $extmgr->checkExtensionByName($extname, $extversion); + if ($check) { + $allowedversions[] = ''.$version.''; + if (isset($extconfs[$extname])) { + if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($version, $extconfs[$extname]['version']) > 0) { + $updates[$extname][$version] = $extversion; + } + } else { + $installs[$extname][$version] = $extversion; + } + } else { + $allowedversions[] = ''.$version.''; + } + } + } + $helper = new QuestionHelper(); + foreach($updates as $extname=>$update) { + $availableversions = array_keys($update); + if ($update) { + $output->writeln(sprintf("Extension '%s' can be updated from %s to %s.", $extname, $extconfs[$extname]['version'], implode(', ', $availableversions))); + $question = new Question(sprintf("Enter version to update: "), ''); + if ($answer = $helper->ask($input, $output, $question)) { + if (in_array($answer, $availableversions)) { + $output->writeln(sprintf("Update extension '%s' to version %s.", $extname, $answer)); + if ($tmpfile = $extmgr->getExtensionFromRepository($update[$answer]['filename'])) { + + if (0&&!$extmgr->updateExtension($tmpfile)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + unlink($tmpfile); + return Command::FAILURE; + } else { + unlink($tmpfile); + } + } + } else { + $output->writeln(sprintf("Invalid version %s.", $answer)); + } + } + } + } + foreach($installs as $extname=>$install) { + $availableversions = array_keys($install); + if ($install) { + $output->writeln(sprintf("Extension '%s' can be installed as version %s.", $extname, implode(', ', $availableversions))); + $question = new Question(sprintf("Enter version to install: "), ''); + if ($answer = $helper->ask($input, $output, $question)) { + if (in_array($answer, $availableversions)) { + $output->writeln(sprintf("Install extension '%s' to version %s.", $extname, $answer)); + if ($tmpfile = $extmgr->getExtensionFromRepository($install[$answer]['filename'])) { + + if (0&&!$extmgr->updateExtension($tmpfile)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + unlink($tmpfile); + return Command::FAILURE; + } else { + unlink($tmpfile); + } + } + } else { + $output->writeln(sprintf("Invalid version %s.", $answer)); + } + } + } + } + return Command::SUCCESS; + } else { + $output->writeln(sprintf("Could not get extension list from repository.")); + return Command::FAILURE; + } + } +} + +// vim: ts=4 sw=4 expandtab diff --git a/utils/console b/utils/console index 9dc4c8c4b..ed7d3c0d8 100755 --- a/utils/console +++ b/utils/console @@ -21,6 +21,7 @@ use Seeddms\Console\Commands\PackageextensionCommand; use Seeddms\Console\Commands\ReloadextensionCommand; use Seeddms\Console\Commands\CheckextensionCommand; use Seeddms\Console\Commands\RepositoryextensionCommand; +use Seeddms\Console\Commands\UpdateextensionCommand; use Seeddms\Console\Commands\DownloadextensionCommand; use Seeddms\Seeddms\Settings; use Seeddms\Seeddms\Translator; @@ -58,6 +59,7 @@ $application->add(new PackageextensionCommand($settings, $logger, $translator, $ $application->add(new ReloadextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new CheckextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new RepositoryextensionCommand($settings, $logger, $translator, $extmgr)); +$application->add(new UpdateextensionCommand($settings, $logger, $translator, $extmgr)); $application->add(new DownloadextensionCommand($settings, $logger, $translator, $extmgr)); if(isset($GLOBALS['SEEDDMS_HOOKS']['console'])) { From 886a5eaf628064a42048c0b8855ed6a8c954e74e Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sun, 16 Nov 2025 17:14:16 +0100 Subject: [PATCH 36/38] check if cache is writable --- utils/Commands/DownloadextensionCommand.php | 5 +++++ utils/Commands/UpdateextensionCommand.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/utils/Commands/DownloadextensionCommand.php b/utils/Commands/DownloadextensionCommand.php index 2a021eeea..0b0c81b4e 100644 --- a/utils/Commands/DownloadextensionCommand.php +++ b/utils/Commands/DownloadextensionCommand.php @@ -58,6 +58,11 @@ class DownloadextensionCommand extends Command $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + if (!is_writable($settings->_cacheDir)) { + $output->writeln(sprintf("The cache dir '%s' is not writable for the system user running this script.", $settings->_cacheDir)); + return Command::FAILURE; + } + $reposurl = $input->getOption('url'); if($reposurl) $extmgr->setRepositoryUrl($reposurl); diff --git a/utils/Commands/UpdateextensionCommand.php b/utils/Commands/UpdateextensionCommand.php index e6ee4dd4e..a7eef574e 100644 --- a/utils/Commands/UpdateextensionCommand.php +++ b/utils/Commands/UpdateextensionCommand.php @@ -55,6 +55,11 @@ class UpdateextensionCommand extends Command $output->writeln("Using configuration from '".$settings->_configFilePath."'.", OutputInterface::VERBOSITY_VERBOSE); + if (!is_writable($settings->_cacheDir)) { + $output->writeln(sprintf("The cache dir '%s' is not writable for the system user running this script.", $settings->_cacheDir)); + return Command::FAILURE; + } + $reposurl = $input->getOption('url'); if($reposurl) $extmgr->setRepositoryUrl($reposurl); From 929a2acd256e25c71b20682fce3d379866591aca Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sun, 16 Nov 2025 17:14:41 +0100 Subject: [PATCH 37/38] output number in updatable, installable extensions, code cleanup --- utils/Commands/UpdateextensionCommand.php | 92 ++++++++++++----------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/utils/Commands/UpdateextensionCommand.php b/utils/Commands/UpdateextensionCommand.php index a7eef574e..e73e4afc1 100644 --- a/utils/Commands/UpdateextensionCommand.php +++ b/utils/Commands/UpdateextensionCommand.php @@ -68,23 +68,21 @@ class UpdateextensionCommand extends Command $installs = []; /* Get a list of available extensions from the repository */ if($ret = $extmgr->updateExtensionList('', true)) { -// $output->writeln(sprintf("Updated extension list from repository.")); // list of installed extensions $extconfs = $extmgr->getExtensionConfiguration(); // list of extensions in repository, this will just return the // latest version of an extension $list = $extmgr->getExtensionList(); -// print_r($list); foreach($list as $extname=>$data) { $extversions = $extmgr->getExtensionListByName($extname); -// print_r($extversions); - $updates[$extname] = []; - $installs[$extname] = []; - $allowedversions = []; +// $updates[$extname] = []; +// $installs[$extname] = []; foreach($extversions as $version=>$extversion) { + /* Only version which pass the check will be offered for + * update or install. + */ $check = $extmgr->checkExtensionByName($extname, $extversion); if ($check) { - $allowedversions[] = ''.$version.''; if (isset($extconfs[$extname])) { if (\Seeddms\Seeddms\ExtensionMgr::cmpVersion($version, $extconfs[$extname]['version']) > 0) { $updates[$extname][$version] = $extversion; @@ -92,60 +90,64 @@ class UpdateextensionCommand extends Command } else { $installs[$extname][$version] = $extversion; } - } else { - $allowedversions[] = ''.$version.''; } } } $helper = new QuestionHelper(); - foreach($updates as $extname=>$update) { - $availableversions = array_keys($update); - if ($update) { - $output->writeln(sprintf("Extension '%s' can be updated from %s to %s.", $extname, $extconfs[$extname]['version'], implode(', ', $availableversions))); - $question = new Question(sprintf("Enter version to update: "), ''); - if ($answer = $helper->ask($input, $output, $question)) { - if (in_array($answer, $availableversions)) { - $output->writeln(sprintf("Update extension '%s' to version %s.", $extname, $answer)); - if ($tmpfile = $extmgr->getExtensionFromRepository($update[$answer]['filename'])) { + if($updates) { + $output->writeln(sprintf("%d extensions can be updated.", count($updates))); + foreach($updates as $extname=>$update) { + $availableversions = array_keys($update); + if ($update) { + $output->writeln(sprintf("Extension '%s' can be updated from %s to %s.", $extname, $extconfs[$extname]['version'], implode(', ', $availableversions))); + $question = new Question(sprintf("Enter version to update: "), ''); + if ($answer = $helper->ask($input, $output, $question)) { + if (in_array($answer, $availableversions)) { + $output->writeln(sprintf("Update extension '%s' to version %s.", $extname, $answer)); + if ($tmpfile = $extmgr->getExtensionFromRepository($update[$answer]['filename'])) { - if (0&&!$extmgr->updateExtension($tmpfile)) { - foreach ($extmgr->getErrorMsgs() as $msg) { - $output->writeln(sprintf("%s", $msg)); + if (0&&!$extmgr->updateExtension($tmpfile)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + unlink($tmpfile); + return Command::FAILURE; + } else { + unlink($tmpfile); } - unlink($tmpfile); - return Command::FAILURE; - } else { - unlink($tmpfile); } + } else { + $output->writeln(sprintf("Invalid version %s.", $answer)); } - } else { - $output->writeln(sprintf("Invalid version %s.", $answer)); } } } } - foreach($installs as $extname=>$install) { - $availableversions = array_keys($install); - if ($install) { - $output->writeln(sprintf("Extension '%s' can be installed as version %s.", $extname, implode(', ', $availableversions))); - $question = new Question(sprintf("Enter version to install: "), ''); - if ($answer = $helper->ask($input, $output, $question)) { - if (in_array($answer, $availableversions)) { - $output->writeln(sprintf("Install extension '%s' to version %s.", $extname, $answer)); - if ($tmpfile = $extmgr->getExtensionFromRepository($install[$answer]['filename'])) { + if($installs) { + $output->writeln(sprintf("%d extensions can be installed.", count($installs))); + foreach($installs as $extname=>$install) { + $availableversions = array_keys($install); + if ($install) { + $output->writeln(sprintf("Extension '%s' can be installed as version %s.", $extname, implode(', ', $availableversions))); + $question = new Question(sprintf("Enter version to install: "), ''); + if ($answer = $helper->ask($input, $output, $question)) { + if (in_array($answer, $availableversions)) { + $output->writeln(sprintf("Install extension '%s' to version %s.", $extname, $answer)); + if ($tmpfile = $extmgr->getExtensionFromRepository($install[$answer]['filename'])) { - if (0&&!$extmgr->updateExtension($tmpfile)) { - foreach ($extmgr->getErrorMsgs() as $msg) { - $output->writeln(sprintf("%s", $msg)); + if (0&&!$extmgr->updateExtension($tmpfile)) { + foreach ($extmgr->getErrorMsgs() as $msg) { + $output->writeln(sprintf("%s", $msg)); + } + unlink($tmpfile); + return Command::FAILURE; + } else { + unlink($tmpfile); } - unlink($tmpfile); - return Command::FAILURE; - } else { - unlink($tmpfile); } + } else { + $output->writeln(sprintf("Invalid version %s.", $answer)); } - } else { - $output->writeln(sprintf("Invalid version %s.", $answer)); } } } From e7e14325b393ad0a1133dc90273edeba2a801f8d Mon Sep 17 00:00:00 2001 From: Uwe Steinmann Date: Sun, 16 Nov 2025 17:21:27 +0100 Subject: [PATCH 38/38] run 'composer dump -o' --- build.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.xml b/build.xml index 34f22a802..fcb335e52 100644 --- a/build.xml +++ b/build.xml @@ -90,6 +90,9 @@ + + +