From c625aa52cd786e1845859e820a81302976a565a3 Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 11:30:17 +0200 Subject: [PATCH 1/6] Installation gefixt --- cronjob.xml | 4 +- .../database/install_dev.hanashi.packages.php | 61 +++++++++++++++++++ install.sql | 15 ----- make.bat | 9 --- make.sh | 9 --- package.xml | 31 ++++------ 6 files changed, 74 insertions(+), 55 deletions(-) create mode 100644 files/acp/database/install_dev.hanashi.packages.php delete mode 100644 install.sql delete mode 100644 make.bat delete mode 100755 make.sh diff --git a/cronjob.xml b/cronjob.xml index 71ef685..b611626 100644 --- a/cronjob.xml +++ b/cronjob.xml @@ -1,7 +1,7 @@ - + packages\system\cronjob\PackageServerUpdateCronjob @@ -15,4 +15,4 @@ 1 - \ No newline at end of file + diff --git a/files/acp/database/install_dev.hanashi.packages.php b/files/acp/database/install_dev.hanashi.packages.php new file mode 100644 index 0000000..997d491 --- /dev/null +++ b/files/acp/database/install_dev.hanashi.packages.php @@ -0,0 +1,61 @@ +columns([ + ObjectIdDatabaseTableColumn::create('repositoryID'), + VarcharDatabaseTableColumn::create('name') + ->length(20) + ->notNull(), + NotNullInt10DatabaseTableColumn::create('packesCount') + ->defaultValue(0), + IntDatabaseTableColumn::create('lastUpdateTime') + ->length(10), + ]) + ->indices([ + DatabaseTablePrimaryIndex::create() + ->columns(['repositoryID']), + ]), + PartialDatabaseTable::create('wcf1_category') + ->columns([ + TinyintDatabaseTableColumn::create('isPackageServer') + ->length(1) + ->notNull() + ->defaultValue(0), + IntDatabaseTableColumn::create('repositoryID') + ->length(10), + ]) + ->foreignKeys([ + DatabaseTableForeignKey::create() + ->columns(['repositoryID']) + ->referencedTable('packages1_repository') + ->referencedColumns(['repositoryID']) + ->onDelete('SET NULL') + ]), + PartialDatabaseTable::create('filebase1_file_version') + ->columns([ + VarcharDatabaseTableColumn::create('packageName') + ->length(100), + VarcharDatabaseTableColumn::create('packageVersion') + ->length(80), + IntDatabaseTableColumn::create('repositoryID') + ->length(10), + ]) + ->foreignKeys([ + DatabaseTableForeignKey::create() + ->columns(['repositoryID']) + ->referencedTable('packages1_repository') + ->referencedColumns(['repositoryID']) + ->onDelete('SET NULL') + ]), +]; diff --git a/install.sql b/install.sql deleted file mode 100644 index fa322a6..0000000 --- a/install.sql +++ /dev/null @@ -1,15 +0,0 @@ -ALTER TABLE wcf1_category ADD isPackageServer TINYINT(1) NOT NULL DEFAULT 0; -ALTER TABLE wcf1_category ADD repositoryID INT(10); -ALTER TABLE filebase1_file_version ADD packageName VARCHAR(100); -ALTER TABLE filebase1_file_version ADD packageVersion VARCHAR(80); -ALTER TABLE filebase1_file_version ADD repositoryID INT(10); - -DROP TABLE IF EXISTS packages1_repository; -CREATE TABLE packages1_repository ( - repositoryID INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(20) NOT NULL, - packesCount INT(10) NOT NULL DEFAULT 0, - lastUpdateTime INT(10) -); -ALTER TABLE wcf1_category ADD FOREIGN KEY (repositoryID) REFERENCES packages1_repository (repositoryID) ON DELETE SET NULL; -ALTER TABLE filebase1_file_version ADD FOREIGN KEY (repositoryID) REFERENCES packages1_repository (repositoryID) ON DELETE SET NULL; diff --git a/make.bat b/make.bat deleted file mode 100644 index f0e2ef4..0000000 --- a/make.bat +++ /dev/null @@ -1,9 +0,0 @@ -@ECHO OFF -del acptemplates.tar -7z a -ttar -mx=9 acptemplates.tar .\acptemplates\* -del files.tar -7z a -ttar -mx=9 files.tar .\files\* -del templates.tar -7z a -ttar -mx=9 templates.tar .\templates\* -del eu.hanashi.packages.tar -7z a -ttar -mx=9 eu.hanashi.packages.tar .\* -x!acptemplates -x!files -x!templates -x!eu.hanashi.packages.tar -x!.git -x!.gitignore -x!make.bat -x!make.sh \ No newline at end of file diff --git a/make.sh b/make.sh deleted file mode 100755 index 205d578..0000000 --- a/make.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -rm -rf acptemplates.tar -7z a -ttar -mx=9 acptemplates.tar ./acptemplates/* -rm -rf files.tar -7z a -ttar -mx=9 files.tar ./files/* -# rm -rf templates.tar -# 7z a -ttar -mx=9 templates.tar ./templates/* -rm -rf eu.hanashi.packages.tar -7z a -ttar -mx=9 eu.hanashi.packages.tar ./* -x!acptemplates -x!files -x!templates -x!eu.hanashi.packages.tar -x!.git -x!.gitignore -x!make.bat -x!make.sh \ No newline at end of file diff --git a/package.xml b/package.xml index f44f471..cb395e1 100644 --- a/package.xml +++ b/package.xml @@ -1,34 +1,29 @@ - + - + 1 - 1.0.0 Alpha 6 - 2019-12-10 + 1.0.0 + 2023-10-21 - - + + - - - - - - com.woltlab.wcf - com.woltlab.filebase + com.woltlab.wcf + com.woltlab.filebase - + - + @@ -39,12 +34,8 @@ - + acp/database/install_dev.hanashi.packages.php - - - - From 11791d24d4ea2608191f9c305e7fd237f71487a8 Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 11:33:51 +0200 Subject: [PATCH 2/6] XML-Dateien angepasst --- acpMenu.xml | 5 +-- cronjob.xml | 9 ++--- eventListener.xml | 12 +++--- language/de.xml | 88 ++++++++++++++++++++++---------------------- package.xml | 69 ++++++++++++++++------------------ templateListener.xml | 4 +- userGroupOption.xml | 6 +-- 7 files changed, 92 insertions(+), 101 deletions(-) diff --git a/acpMenu.xml b/acpMenu.xml index 867ead2..ded8531 100644 --- a/acpMenu.xml +++ b/acpMenu.xml @@ -1,10 +1,9 @@ - + wcf.acp.menu.link.application - packages\acp\page\RepositoryListPage packages.acp.menu.link.package @@ -15,7 +14,7 @@ packages\acp\form\RepositoryAddForm packages.acp.menu.link.package.repository.list admin.packages.canManageRepository - fa-plus + plus diff --git a/cronjob.xml b/cronjob.xml index b611626..cc77365 100644 --- a/cronjob.xml +++ b/cronjob.xml @@ -1,18 +1,15 @@ - + packages\system\cronjob\PackageServerUpdateCronjob - - + Refreshs cache of package server. + Aktualisiert den Cache des Paket-Servers. */5 * * * * - 1 - 1 - 1 diff --git a/eventListener.xml b/eventListener.xml index 815dfd6..337724f 100644 --- a/eventListener.xml +++ b/eventListener.xml @@ -1,12 +1,12 @@ - - - + + + filebase\acp\form\CategoryEditForm readFormParameters,validate,save,assignVariables + packages\system\event\listener\FilebaseCategoryEditFormListener admin 1 - packages\system\event\listener\FilebaseCategoryEditFormListener filebase\acp\form\CategoryAddForm @@ -15,5 +15,5 @@ 1 packages\system\event\listener\FilebaseCategoryEditFormListener - - \ No newline at end of file + + diff --git a/language/de.xml b/language/de.xml index e4fcd0e..f157c95 100644 --- a/language/de.xml +++ b/language/de.xml @@ -1,45 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.xml b/package.xml index cb395e1..4080d14 100644 --- a/package.xml +++ b/package.xml @@ -1,41 +1,34 @@ - - - - + + + + Package server + Ein kleiner Paketserver der auf die Filebase von WoltLab aufbaut. 1 - 1.0.0 - 2023-10-21 - - - - - - - - - com.woltlab.wcf - com.woltlab.filebase - - - - - - - - - - - - - - - - - - - - - acp/database/install_dev.hanashi.packages.php - + 1.0.0 + 2023-10-21 + + + Hanashi Development + https://hanashi.dev/ + + + com.woltlab.wcf + com.woltlab.filebase + + + com.woltlab.wcf + com.woltlab.filebase + + + + + + + + + + + acp/database/install_dev.hanashi.packages.php + diff --git a/templateListener.xml b/templateListener.xml index bde0f2e..eb0d306 100644 --- a/templateListener.xml +++ b/templateListener.xml @@ -1,5 +1,5 @@ - + @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/userGroupOption.xml b/userGroupOption.xml index 66bbda6..35f09b6 100644 --- a/userGroupOption.xml +++ b/userGroupOption.xml @@ -1,5 +1,5 @@ - + @@ -7,7 +7,7 @@ - - \ No newline at end of file + From a80895106251083572b5a88bd98c52d6f4a008f2 Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 11:46:06 +0200 Subject: [PATCH 3/6] Codestyle --- .github/php-syntax.json | 15 + .github/workflows/codestyle.yml | 22 ++ .github/workflows/php.yml | 25 ++ .github/workflows/release.yml | 41 +++ .gitignore | 3 +- .php-cs-fixer.dist.php | 129 +++++++ .phpcs.xml | 18 + .../database/install_dev.hanashi.packages.php | 4 +- files/acp/global.php | 11 +- files/acp/index.php | 1 + files/global.php | 10 +- files/index.php | 1 + .../lib/acp/form/RepositoryAddForm.class.php | 128 ++++--- .../lib/acp/page/RepositoryListPage.class.php | 21 +- .../action/AbstractPackageAction.class.php | 231 ++++++------ .../lib/data/repository/Repository.class.php | 53 +-- .../repository/RepositoryAction.class.php | 75 ++-- .../repository/RepositoryEditor.class.php | 10 +- .../data/repository/RepositoryList.class.php | 6 +- files/lib/system/PackagesCore.class.php | 8 +- .../PackageServerUpdateCronjob.class.php | 225 ++++++------ ...FilebaseCategoryEditFormListener.class.php | 114 +++--- .../RepositoryActionHandler.class.php | 63 ++-- .../repository/RepositoryWriter.class.php | 343 ++++++++++-------- 24 files changed, 974 insertions(+), 583 deletions(-) create mode 100644 .github/php-syntax.json create mode 100644 .github/workflows/codestyle.yml create mode 100644 .github/workflows/php.yml create mode 100644 .github/workflows/release.yml create mode 100644 .php-cs-fixer.dist.php create mode 100644 .phpcs.xml diff --git a/.github/php-syntax.json b/.github/php-syntax.json new file mode 100644 index 0000000..a8b970d --- /dev/null +++ b/.github/php-syntax.json @@ -0,0 +1,15 @@ +{ + "problemMatcher": [ + { + "owner": "php -l", + "pattern": [ + { + "regexp": "^\\s*(PHP\\s+)?([a-zA-Z\\s]+):\\s+(.*)\\s+in\\s+(\\S+)\\s+on\\s+line\\s+(\\d+)$", + "file": 4, + "line": 5, + "message": 3 + } + ] + } + ] +} \ No newline at end of file diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml new file mode 100644 index 0000000..5c19af7 --- /dev/null +++ b/.github/workflows/codestyle.yml @@ -0,0 +1,22 @@ +name: Code Style + +on: + push: + pull_request: + +jobs: + php: + name: PHP + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup PHP with tools + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + extensions: ctype, dom, exif, gd, gmp, hash, intl, json, libxml, mbstring, opcache, pcre, pdo, pdo_mysql, zlib + tools: cs2pr, phpcs, php-cs-fixer + - name: phpcs + run: phpcs -n -q --report=checkstyle | cs2pr + - name: php-cs-fixer + run: php-cs-fixer fix --dry-run --diff diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..cab57e2 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,25 @@ +name: PHP + +on: + push: + pull_request: + +jobs: + syntax: + name: "Check Syntax (${{ matrix.php }})" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: + - '8.1' + - '8.2' + steps: + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + - uses: actions/checkout@v4 + - run: echo "::add-matcher::.github/php-syntax.json" + - run: | + ! find . -type f -name '*.php' -exec php -l '{}' \; 2>&1 |grep -v '^No syntax errors detected' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..555ec1e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Release + +on: + push: + tags: ['*'] + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Create package + run: | + rm -rf *.tar.gz + npx --yes wspackager@latest + + - name: Check file existence + id: check_files + uses: andstor/file-existence-action@v2.0.0 + with: + files: "*.tar.gz" + + - name: On Build Failure + if: steps.check_files.outputs.files_exists == 'false' + run: | + echo "Packaging FAILED" && exit 1 + + - name: Release + uses: softprops/action-gh-release@v0.1.15 + if: startsWith(github.ref, 'refs/tags/') && steps.check_files.outputs.files_exists == 'true' + with: + files: "*.tar.gz" diff --git a/.gitignore b/.gitignore index 72079da..830f6ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.tar -option.xml \ No newline at end of file +.phpcs-cache +*.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..87458e8 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,129 @@ +in(__DIR__.'/files/') + ->notPath('lib/system/api'); + +return (new PhpCsFixer\Config()) + ->setRiskyAllowed(true) + ->setRules([ + '@PSR1' => true, + '@PSR2' => true, + + 'array_push' => true, + 'backtick_to_shell_exec' => true, + 'no_alias_language_construct_call' => true, + 'no_mixed_echo_print' => true, + 'pow_to_exponentiation' => true, + 'random_api_migration' => true, + + 'array_syntax' => ['syntax' => 'short'], + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_whitespace_before_comma_in_array' => true, + 'normalize_index_brace' => true, + 'whitespace_after_comma_in_array' => true, + + 'non_printable_character' => ['use_escape_sequences_in_strings' => true], + + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'magic_method_casing' => true, + 'native_function_casing' => true, + 'native_function_type_declaration_casing' => true, + + 'cast_spaces' => ['space' => 'none'], + 'lowercase_cast' => true, + 'no_unset_cast' => true, + 'short_scalar_cast' => true, + + 'class_attributes_separation' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_null_property_initialization' => true, + 'self_accessor' => true, + 'single_class_element_per_statement' => true, + 'single_trait_insert_per_statement' => true, + + 'no_empty_comment' => true, + 'single_line_comment_style' => ['comment_types' => ['hash']], + + 'native_constant_invocation' => ['strict' => false], + + 'no_alternative_syntax' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_unneeded_control_parentheses' => ['statements' => ['break', 'clone', 'continue', 'echo_print', 'return', 'switch_case', 'yield', 'yield_from']], + 'no_unneeded_curly_braces' => ['namespaces' => true], + 'switch_continue_to_break' => true, + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + + 'function_typehint_space' => true, + 'lambda_not_used_import' => true, + 'native_function_invocation' => ['include' => ['@internal']], + 'no_unreachable_default_argument_value' => true, + 'nullable_type_declaration_for_default_null_value' => true, + 'return_type_declaration' => true, + 'static_lambda' => true, + + 'fully_qualified_strict_types' => true, + 'no_leading_import_slash' => true, + 'no_unused_imports' => true, + 'ordered_imports' => true, + + 'declare_equal_normalize' => true, + 'dir_constant' => true, + 'explicit_indirect_variable' => true, + 'function_to_constant' => true, + 'is_null' => true, + 'no_unset_on_property' => true, + + 'list_syntax' => ['syntax' => 'short'], + + 'clean_namespace' => true, + 'no_leading_namespace_whitespace' => true, + 'single_blank_line_before_namespace' => true, + + 'no_homoglyph_names' => true, + + 'binary_operator_spaces' => true, + 'concat_space' => ['spacing' => 'one'], + 'increment_style' => ['style' => 'post'], + 'logical_operators' => true, + 'object_operator_without_whitespace' => true, + 'operator_linebreak' => true, + 'standardize_increment' => true, + 'standardize_not_equals' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_elvis_operator' => true, + 'ternary_to_null_coalescing' => true, + 'unary_operator_spaces' => true, + + 'no_useless_return' => true, + 'return_assignment' => true, + + 'multiline_whitespace_before_semicolons' => true, + 'no_empty_statement' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'space_after_semicolon' => ['remove_in_empty_for_expressions' => true], + + 'escape_implicit_backslashes' => true, + 'explicit_string_variable' => true, + 'heredoc_to_nowdoc' => true, + 'no_binary_string' => true, + 'simple_to_complex_string_variable' => true, + + 'array_indentation' => true, + 'blank_line_before_statement' => ['statements' => ['return', 'exit']], + 'compact_nullable_typehint' => true, + 'method_chaining_indentation' => true, + 'no_extra_blank_lines' => ['tokens' => ['case', 'continue', 'curly_brace_block', 'default', 'extra', 'parenthesis_brace_block', 'square_brace_block', 'switch', 'throw', 'use']], + 'no_spaces_around_offset' => true, + + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => false, + 'import_functions' => false, + ], + 'ordered_imports' => [ + 'imports_order' => ['class', 'function', 'const'], + ], + ]) + ->setFinder($finder); diff --git a/.phpcs.xml b/.phpcs.xml new file mode 100644 index 0000000..903c00b --- /dev/null +++ b/.phpcs.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + files + lib/system/api/* + + + + diff --git a/files/acp/database/install_dev.hanashi.packages.php b/files/acp/database/install_dev.hanashi.packages.php index 997d491..d3b82e1 100644 --- a/files/acp/database/install_dev.hanashi.packages.php +++ b/files/acp/database/install_dev.hanashi.packages.php @@ -40,7 +40,7 @@ ->columns(['repositoryID']) ->referencedTable('packages1_repository') ->referencedColumns(['repositoryID']) - ->onDelete('SET NULL') + ->onDelete('SET NULL'), ]), PartialDatabaseTable::create('filebase1_file_version') ->columns([ @@ -56,6 +56,6 @@ ->columns(['repositoryID']) ->referencedTable('packages1_repository') ->referencedColumns(['repositoryID']) - ->onDelete('SET NULL') + ->onDelete('SET NULL'), ]), ]; diff --git a/files/acp/global.php b/files/acp/global.php index 6a1b0ec..4968693 100644 --- a/files/acp/global.php +++ b/files/acp/global.php @@ -1,6 +1,11 @@ handle('packages', true); diff --git a/files/global.php b/files/global.php index e130b52..316c820 100644 --- a/files/global.php +++ b/files/global.php @@ -1,3 +1,9 @@ handle('packages'); diff --git a/files/lib/acp/form/RepositoryAddForm.class.php b/files/lib/acp/form/RepositoryAddForm.class.php index 6369151..ccdc4b1 100644 --- a/files/lib/acp/form/RepositoryAddForm.class.php +++ b/files/lib/acp/form/RepositoryAddForm.class.php @@ -1,64 +1,78 @@ name = $_POST['name']; - } - - public function validate() { - parent::validate(); - - if (strlen($this->name) < 2) - throw new UserInputException('name', 'tooShort'); - if (preg_match('/^[0-9]+$/', substr($this->name, 0, 1))) - throw new UserInputException('name', 'noNumberOnStart'); - if (!preg_match('/^[a-z0-9]+$/', $this->name)) - throw new UserInputException('name', 'wrongFormat'); - if (strlen($this->name) > 20) - throw new UserInputException('name', 'nameTooLong'); - - $repositoryList = new RepositoryList(); - $repositoryList->getConditionBuilder()->add('name = ?', [$this->name]); - $repositoryList->readObjects(); - if (count($repositoryList) > 0) - throw new UserInputException('name', 'alreadyUsed'); - } - - public function save() { - parent::save(); - - $this->objectAction = new RepositoryAction([], 'create', ['data' => [ - 'name' => $this->name - ]]); - $this->objectAction->executeAction(); - - $this->saved(); - } - - public function saved() { - parent::saved(); - - WCF::getTPL()->assign('success', true); - } - - public function assignVariables() { - parent::assignVariables(); - - WCF::getTPL()->assign(array( - 'name' => $this->name - )); - } -} \ No newline at end of file +class RepositoryAddForm extends AbstractForm +{ + public $activeMenuItem = 'packages.acp.menu.link.package.repository.add'; + + protected $name; + + public function readFormParameters() + { + parent::readFormParameters(); + + if (isset($_POST['name'])) { + $this->name = $_POST['name']; + } + } + + public function validate() + { + parent::validate(); + + if (\strlen($this->name) < 2) { + throw new UserInputException('name', 'tooShort'); + } + if (\preg_match('/^[0-9]+$/', \substr($this->name, 0, 1))) { + throw new UserInputException('name', 'noNumberOnStart'); + } + if (!\preg_match('/^[a-z0-9]+$/', $this->name)) { + throw new UserInputException('name', 'wrongFormat'); + } + if (\strlen($this->name) > 20) { + throw new UserInputException('name', 'nameTooLong'); + } + + $repositoryList = new RepositoryList(); + $repositoryList->getConditionBuilder()->add('name = ?', [$this->name]); + $repositoryList->readObjects(); + if (\count($repositoryList) > 0) { + throw new UserInputException('name', 'alreadyUsed'); + } + } + + public function save() + { + parent::save(); + + $this->objectAction = new RepositoryAction([], 'create', ['data' => [ + 'name' => $this->name, + ]]); + $this->objectAction->executeAction(); + + $this->saved(); + } + + public function saved() + { + parent::saved(); + + WCF::getTPL()->assign('success', true); + } + + public function assignVariables() + { + parent::assignVariables(); + + WCF::getTPL()->assign([ + 'name' => $this->name, + ]); + } +} diff --git a/files/lib/acp/page/RepositoryListPage.class.php b/files/lib/acp/page/RepositoryListPage.class.php index a1c5374..5478380 100644 --- a/files/lib/acp/page/RepositoryListPage.class.php +++ b/files/lib/acp/page/RepositoryListPage.class.php @@ -1,14 +1,17 @@ changeUser(new User(null, ['username' => 'System', 'userID' => 0]), true); - $this->downloadFile($_REQUEST['packageName'], $_REQUEST['packageVersion']); - return; - } - - $repository = new Repository($this->repositoryID); - if ($repository->repositoryID != $this->repositoryID) { - echo 'Repository does not exist.'; - return; - } - - $cacheFile = $repository->getCacheFile(); - if (!file_exists($cacheFile)) { - echo 'Cache file does not exist.'; - return; - } - header('Content-type: application/xml'); - echo file_get_contents($repository->getCacheFile()); - } - - protected function downloadFile($packageName, $packageVersion) { - $fileVersionList = new FileVersionList(); - $fileVersionList->getConditionBuilder()->add('packageName = ? AND packageVersion = ?', [$packageName, $packageVersion]); - $fileVersionList->readObjects(); - - foreach ($fileVersionList as $fileVersion) { - if ($fileVersion->repositoryID != $this->repositoryID) { - echo 'File not found'; - return; - } - - $this->getFile($fileVersion); - return; - } - echo 'File not found'; - } - - protected function getFile($fileVersion) { - $this->authenticate($fileVersion); - - $location = $fileVersion->getLocation(); - if (!file_exists($location)) { - echo 'File not found'; - return; - } - header('Content-type: '.$fileVersion->fileType); - header('Content-disposition: attachment; filename="'.$fileVersion->filename.'"'); - echo file_get_contents($location); - - $editor = new FileEditor($fileVersion->getFile()); - $editor->updateCounters([ - 'downloads' => 1 - ]); - $editor = new FileVersionEditor($fileVersion); - $editor->updateCounters([ - 'downloads' => 1 - ]); - } - - protected function authenticate($fileVersion) { - if (!$fileVersion->canDownload() && !(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER["PHP_AUTH_PW"]))) { - $this->authHeader(); - } else if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER["PHP_AUTH_PW"])) { - try { - $user = UserAuthenticationFactory::getInstance()->getUserAuthentication()->loginManually($_SERVER['PHP_AUTH_USER'], $_SERVER["PHP_AUTH_PW"]); - } catch (UserInputException $e) { - if ($e->getField() == 'username') { - try { - $user = EmailUserAuthentication::getInstance()->loginManually($_SERVER['PHP_AUTH_USER'], $_SERVER["PHP_AUTH_PW"]); - } catch (UserInputException $e2) { - $this->authHeader(); - } - } else { - $this->authHeader(); - } - } - WCF::getSession()->changeUser($user); - if (!$fileVersion->canDownload()) { - $this->authHeader(); - } - } - } - - protected function authHeader() { - header('WWW-Authenticate: Basic realm="PackageServer"'); - header('HTTP/1.0 401 Unauthorized'); - echo 'Not authenticated.'; - exit; - } -} \ No newline at end of file +abstract class AbstractPackageAction extends AbstractAction +{ + public $repositoryID; + + public $repositoryName; + + public function readParameters() + { + parent::readParameters(); + } + + public function execute() + { + if (isset($_REQUEST['packageName']) && isset($_REQUEST['packageVersion'])) { + WCF::getSession()->changeUser(new User(null, ['username' => 'System', 'userID' => 0]), true); + $this->downloadFile($_REQUEST['packageName'], $_REQUEST['packageVersion']); + + return; + } + + $repository = new Repository($this->repositoryID); + if ($repository->repositoryID != $this->repositoryID) { + echo 'Repository does not exist.'; + + return; + } + + $cacheFile = $repository->getCacheFile(); + if (!\file_exists($cacheFile)) { + echo 'Cache file does not exist.'; + + return; + } + \header('Content-type: application/xml'); + echo \file_get_contents($repository->getCacheFile()); + } + + protected function downloadFile($packageName, $packageVersion) + { + $fileVersionList = new FileVersionList(); + $fileVersionList->getConditionBuilder()->add('packageName = ?', [$packageName]); + $fileVersionList->getConditionBuilder()->add('packageVersion = ?', [$packageVersion]); + $fileVersionList->readObjects(); + + foreach ($fileVersionList as $fileVersion) { + if ($fileVersion->repositoryID != $this->repositoryID) { + echo 'File not found'; + + return; + } + + $this->getFile($fileVersion); + + return; + } + echo 'File not found'; + } + + protected function getFile($fileVersion) + { + $this->authenticate($fileVersion); + + $location = $fileVersion->getLocation(); + if (!\file_exists($location)) { + echo 'File not found'; + + return; + } + \header('Content-type: ' . $fileVersion->fileType); + \header('Content-disposition: attachment; filename="' . $fileVersion->filename . '"'); + echo \file_get_contents($location); + + $editor = new FileEditor($fileVersion->getFile()); + $editor->updateCounters([ + 'downloads' => 1, + ]); + $editor = new FileVersionEditor($fileVersion); + $editor->updateCounters([ + 'downloads' => 1, + ]); + } + + protected function authenticate($fileVersion) + { + if (!$fileVersion->canDownload() && !(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER["PHP_AUTH_PW"]))) { + $this->authHeader(); + } elseif (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER["PHP_AUTH_PW"])) { + try { + $user = UserAuthenticationFactory::getInstance()->getUserAuthentication()->loginManually( + $_SERVER['PHP_AUTH_USER'], + $_SERVER["PHP_AUTH_PW"] + ); + } catch (UserInputException $e) { + if ($e->getField() == 'username') { + try { + $user = EmailUserAuthentication::getInstance()->loginManually( + $_SERVER['PHP_AUTH_USER'], + $_SERVER["PHP_AUTH_PW"] + ); + } catch (UserInputException $e2) { + $this->authHeader(); + } + } else { + $this->authHeader(); + } + } + WCF::getSession()->changeUser($user); + if (!$fileVersion->canDownload()) { + $this->authHeader(); + } + } + } + + protected function authHeader() + { + \header('WWW-Authenticate: Basic realm="PackageServer"'); + \header('HTTP/1.0 401 Unauthorized'); + echo 'Not authenticated.'; + + exit; + } +} diff --git a/files/lib/data/repository/Repository.class.php b/files/lib/data/repository/Repository.class.php index b6d6d0f..6a8374f 100644 --- a/files/lib/data/repository/Repository.class.php +++ b/files/lib/data/repository/Repository.class.php @@ -1,29 +1,38 @@ name; - } - - public function canManage() { - return true; - } - - public function getLink() { - return LinkHandler::getInstance()->getLink(StringUtil::firstCharToUpperCase($this->name), ['forceFrontend' => true, 'application' => 'packages']); - } - - public function getCacheFile() { - return WCF_DIR.'cache/cache.packages_'.$this->name.'.xml'; - } -} \ No newline at end of file +class Repository extends DatabaseObject implements IRouteController +{ + protected static $databaseTableName = 'repository'; + + protected static $databaseTableIndexName = 'repositoryID'; + + public function getTitle(): string + { + return $this->name; + } + + public function canManage() + { + return true; + } + + public function getLink(): string + { + return LinkHandler::getInstance()->getLink( + StringUtil::firstCharToUpperCase($this->name), + ['forceFrontend' => true, 'application' => 'packages'] + ); + } + + public function getCacheFile() + { + return WCF_DIR . 'cache/cache.packages_' . $this->name . '.xml'; + } +} diff --git a/files/lib/data/repository/RepositoryAction.class.php b/files/lib/data/repository/RepositoryAction.class.php index c187b64..39a39f2 100644 --- a/files/lib/data/repository/RepositoryAction.class.php +++ b/files/lib/data/repository/RepositoryAction.class.php @@ -1,40 +1,45 @@ objects as $object) { - if(!$object->canManage()) { - throw new PermissionDeniedException(); - } - } - } - - public function create() { - $repository = parent::create(); - - $repositoryActionHandler = new RepositoryActionHandler($repository); - $repositoryActionHandler->create(); - return $repository; - } - - public function delete() { - parent::delete(); - - foreach ($this->objects as $object) { - $repositoryActionHandler = new RepositoryActionHandler($object->getDecoratedObject()); - $repositoryActionHandler->delete(); - } - } -} \ No newline at end of file + +class RepositoryAction extends AbstractDatabaseObjectAction +{ + protected $permissionsCreate = ['admin.packages.canManageRepository']; + + protected $permissionsDelete = ['admin.packages.canManageRepository']; + + public function validateDelete() + { + parent::validateDelete(); + + foreach ($this->objects as $object) { + if (!$object->canManage()) { + throw new PermissionDeniedException(); + } + } + } + + public function create() + { + $repository = parent::create(); + + $repositoryActionHandler = new RepositoryActionHandler($repository); + $repositoryActionHandler->create(); + + return $repository; + } + + public function delete() + { + parent::delete(); + + foreach ($this->objects as $object) { + $repositoryActionHandler = new RepositoryActionHandler($object->getDecoratedObject()); + $repositoryActionHandler->delete(); + } + } +} diff --git a/files/lib/data/repository/RepositoryEditor.class.php b/files/lib/data/repository/RepositoryEditor.class.php index 031c1f2..dda41d8 100644 --- a/files/lib/data/repository/RepositoryEditor.class.php +++ b/files/lib/data/repository/RepositoryEditor.class.php @@ -1,8 +1,10 @@ readObjects(); + + foreach ($repositoryList as $repository) { + $this->createRepositoryCache($repository); + } + } + + protected function createRepositoryCache(Repository $repository) + { + $categoryList = new CategoryList(); + $categoryList->getConditionBuilder()->add('repositoryID = ?', [$repository->repositoryID]); + $categoryList->getConditionBuilder()->add('isPackageServer = 1'); + $categoryList->readObjectIDs(); + + $xml = new RepositoryWriter($repository->getCacheFile()); + $xml->createSection(); + + $fileList = new ViewableFileList(); + $fileList->getConditionBuilder()->add('categoryID IN (?)', [\implode(',', $categoryList->objectIDs)]); + $fileList->readObjects(); + + $packageCounter = 0; + foreach ($fileList as $file) { + if ($file->getLastVersion()->filesize == 0) { + continue; + } + + $fileVersion = new FileVersion($file->lastVersionID); + $fileVersion->getFile(); + + $archive = new PackageArchive($fileVersion->getLocation()); + try { + $archive->openArchive(); + } catch (PackageValidationException $e) { + continue; + } + + $packageNameArr = $archive->getPackageInfo('packageName'); + $packageDescriptionArr = $archive->getPackageInfo('packageDescription'); + + $name = $archive->getPackageInfo('name'); + $packageName = $packageNameArr['default']; + $packageDescription = ''; + if (isset($packageDescriptionArr['default'])) { + $packageDescription = $packageDescriptionArr['default']; + } + $author = $archive->getAuthorInfo('author'); + $authorUrl = $archive->getAuthorInfo('authorURL'); + $isApplication = $archive->getPackageInfo('isApplication'); + $license = ($file->isCommercial == 1) ? 'commercial' : 'free'; + + $fileVersionList = new FileVersionList(); + $fileVersionList->getConditionBuilder()->add('fileID = ?', [$file->fileID]); + $fileVersionList->readObjects(); + + $versions = []; + foreach ($fileVersionList as $fileVersion) { + $archive = new PackageArchive($fileVersion->getLocation()); + try { + $archive->openArchive(); + } catch (PackageValidationException $e) { + continue; + } + + $versions[] = [ + 'version' => $archive->getPackageInfo('version'), + 'timestamp' => $fileVersion->uploadTime, + 'updateType' => ($archive->getInstructions('update') == null) ? 'install' : 'update', + 'requiredPackages' => $archive->getRequirements(), + 'excludedPackages' => $archive->getExcludedPackages(), + 'instructions' => $archive->getInstructions('update'), + 'requireAuth' => ($fileVersion->canDownload()) ? 'false' : 'true', + ]; + + $objectAction = new FileVersionAction([$fileVersion], 'update', ['data' => [ + 'packageName' => $archive->getPackageInfo('name'), + 'packageVersion' => $archive->getPackageInfo('version'), + 'repositoryID' => $repository->repositoryID, + ]]); + $objectAction->executeAction(); + } + + $xml->createPackage( + $name, + $packageName, + $packageDescription, + $author, + $authorUrl, + $versions, + $isApplication, + $license + ); + + $packageCounter++; + } + $objectAction = new RepositoryAction([$repository], 'update', ['data' => [ + 'packesCount' => $packageCounter, + 'lastUpdateTime' => \time(), + ]]); + $objectAction->executeAction(); -class PackageServerUpdateCronjob extends AbstractCronjob { - public function execute(Cronjob $cronjob) { - parent::execute($cronjob); - - $repositoryList = new RepositoryList(); - $repositoryList->readObjects(); - - foreach ($repositoryList as $repository) { - $this->createRepositoryCache($repository); - } - } - - protected function createRepositoryCache(Repository $repository) { - $categoryList = new CategoryList(); - $categoryList->getConditionBuilder()->add('repositoryID = ? AND isPackageServer = 1', [$repository->repositoryID]); - $categoryList->readObjectIDs(); - - $xml = new RepositoryWriter($repository->getCacheFile()); - $xml->createSection(); - - $fileList = new ViewableFileList(); - $fileList->getConditionBuilder()->add('categoryID IN (?)', [implode(',', $categoryList->objectIDs)]); - $fileList->readObjects(); - - $packageCounter = 0; - foreach ($fileList as $file) { - if ($file->getLastVersion()->filesize == 0) { - continue; - } - - $fileVersion = new FileVersion($file->lastVersionID); - $fileVersion->getFile(); - - $archive = new PackageArchive($fileVersion->getLocation()); - try { - $archive->openArchive(); - } catch (PackageValidationException $e) { - continue; - } - - $packageNameArr = $archive->getPackageInfo('packageName'); - $packageDescriptionArr = $archive->getPackageInfo('packageDescription'); - - $name = $archive->getPackageInfo('name'); - $packageName = $packageNameArr['default']; - $packageDescription = ''; - if (isset($packageDescriptionArr['default'])) - $packageDescription = $packageDescriptionArr['default']; - $author = $archive->getAuthorInfo('author'); - $authorUrl = $archive->getAuthorInfo('authorURL'); - $isApplication = $archive->getPackageInfo('isApplication'); - $license = ($file->isCommercial == 1) ? 'commercial' : 'free'; - - $fileVersionList = new FileVersionList(); - $fileVersionList->getConditionBuilder()->add('fileID = ?', [$file->fileID]); - $fileVersionList->readObjects(); - - $versions = []; - foreach ($fileVersionList as $fileVersion) { - $archive = new PackageArchive($fileVersion->getLocation()); - try { - $archive->openArchive(); - } catch (PackageValidationException $e) { - continue; - } - - $versions[] = [ - 'version' => $archive->getPackageInfo('version'), - 'timestamp' => $fileVersion->uploadTime, - 'updateType' => ($archive->getInstructions('update') == null) ? 'install' : 'update', - 'requiredPackages' => $archive->getRequirements(), - 'excludedPackages' => $archive->getExcludedPackages(), - 'instructions' => $archive->getInstructions('update'), - 'requireAuth' => ($fileVersion->canDownload()) ? 'false' : 'true' - ]; - - $objectAction = new FileVersionAction([$fileVersion], 'update', ['data' => [ - 'packageName' => $archive->getPackageInfo('name'), - 'packageVersion' => $archive->getPackageInfo('version'), - 'repositoryID' => $repository->repositoryID - ]]); - $objectAction->executeAction(); - } - - $xml->createPackage( - $name, - $packageName, - $packageDescription, - $author, - $authorUrl, - $versions, - $isApplication, - $license - ); - - $packageCounter++; - } - $objectAction = new RepositoryAction([$repository], 'update', ['data' => [ - 'packesCount' => $packageCounter, - 'lastUpdateTime' => time() - ]]); - $objectAction->executeAction(); - - $xml->save(); - } + $xml->save(); + } } diff --git a/files/lib/system/event/listener/FilebaseCategoryEditFormListener.class.php b/files/lib/system/event/listener/FilebaseCategoryEditFormListener.class.php index 33b6265..7e8a508 100644 --- a/files/lib/system/event/listener/FilebaseCategoryEditFormListener.class.php +++ b/files/lib/system/event/listener/FilebaseCategoryEditFormListener.class.php @@ -1,63 +1,69 @@ packageServer = $_POST['values']['packageServer']; - if (isset($_POST['repository'])) - $this->repository = $_POST['repository']; - } else if ($eventName == 'validate') { - if ($this->packageServer == 1) { - if (empty($this->repository)) { - throw new UserInputException('repository', 'empty'); - } - - $repositoryList = new RepositoryList(); - $repositoryList->getConditionBuilder()->add('repositoryID = ?', [$this->repository]); - $repositoryList->readObjects(); - - if (count($repositoryList) == 0) { - throw new UserInputException('repository', 'notExist'); - } - } - } else if ($eventName == 'save') { - if ($this->packageServer == 1) { - $eventObj->additionalFields = array_merge($eventObj->additionalFields, [ - 'isPackageServer' => $this->packageServer, - 'repositoryID' => $this->repository - ]); - } else if ($this->packageServer == 0) { - $eventObj->additionalFields = array_merge($eventObj->additionalFields, [ - 'isPackageServer' => $this->packageServer, - 'repositoryID' => null - ]); - } - } else if ($eventName == 'assignVariables') { - if (empty($_POST) && $eventObj instanceof CategoryEditForm) { - $this->packageServer = $eventObj->category->isPackageServer; - $this->repository = $eventObj->category->repositoryID; - } - - $repositoryList = new RepositoryList(); - $repositoryList->readObjects(); - - WCF::getTPL()->assign([ - 'packagesFilebaseAdd' => true, - 'repositoryList' => $repositoryList, - 'packageServer' => $this->packageServer, - 'repositoryID' => $this->repository - ]); - } - } +class FilebaseCategoryEditFormListener implements IParameterizedEventListener +{ + protected $packageServer; + + protected $repository; + + public function execute($eventObj, $className, $eventName, array &$parameters) + { + if ($eventName == 'readFormParameters') { + if (isset($_POST['values']['packageServer'])) { + $this->packageServer = $_POST['values']['packageServer']; + } + if (isset($_POST['repository'])) { + $this->repository = $_POST['repository']; + } + } elseif ($eventName == 'validate') { + if ($this->packageServer == 1) { + if (empty($this->repository)) { + throw new UserInputException('repository', 'empty'); + } + + $repositoryList = new RepositoryList(); + $repositoryList->getConditionBuilder()->add('repositoryID = ?', [$this->repository]); + $repositoryList->readObjects(); + + if (\count($repositoryList) == 0) { + throw new UserInputException('repository', 'notExist'); + } + } + } elseif ($eventName == 'save') { + if ($this->packageServer == 1) { + $eventObj->additionalFields = \array_merge($eventObj->additionalFields, [ + 'isPackageServer' => $this->packageServer, + 'repositoryID' => $this->repository, + ]); + } elseif ($this->packageServer == 0) { + $eventObj->additionalFields = \array_merge($eventObj->additionalFields, [ + 'isPackageServer' => $this->packageServer, + 'repositoryID' => null, + ]); + } + } elseif ($eventName == 'assignVariables') { + if (empty($_POST) && $eventObj instanceof CategoryEditForm) { + $this->packageServer = $eventObj->category->isPackageServer; + $this->repository = $eventObj->category->repositoryID; + } + + $repositoryList = new RepositoryList(); + $repositoryList->readObjects(); + + WCF::getTPL()->assign([ + 'packagesFilebaseAdd' => true, + 'repositoryList' => $repositoryList, + 'packageServer' => $this->packageServer, + 'repositoryID' => $this->repository, + ]); + } + } } diff --git a/files/lib/system/repository/RepositoryActionHandler.class.php b/files/lib/system/repository/RepositoryActionHandler.class.php index 365bb79..e3c3ff7 100644 --- a/files/lib/system/repository/RepositoryActionHandler.class.php +++ b/files/lib/system/repository/RepositoryActionHandler.class.php @@ -1,34 +1,41 @@ repository = $repository; - } - - public function create() { - $templatePath = PACKAGES_DIR.'lib/action/PackageAction.class.template'; - $template = file_get_contents($templatePath); - - $className = StringUtil::firstCharToUpperCase($this->repository->name); - $template = str_replace('{className}', $className, $template); - $template = str_replace('{repositoryID}', $this->repository->repositoryID, $template); - $template = str_replace('{repositoryName}', $this->repository->name, $template); - - $classPathName = PACKAGES_DIR.'lib/action/'.$className.'Action.class.php'; - - file_put_contents($classPathName, $template); - } - - public function delete() { - $className = StringUtil::firstCharToUpperCase($this->repository->name); - $classPathName = PACKAGES_DIR.'lib/action/'.$className.'Action.class.php'; - - if (file_exists($classPathName)) - unlink($classPathName); - } +class RepositoryActionHandler +{ + protected $repository; + + public function __construct(Repository $repository) + { + $this->repository = $repository; + } + + public function create() + { + $templatePath = PACKAGES_DIR . 'lib/action/PackageAction.class.template'; + $template = \file_get_contents($templatePath); + + $className = StringUtil::firstCharToUpperCase($this->repository->name); + $template = \str_replace('{className}', $className, $template); + $template = \str_replace('{repositoryID}', $this->repository->repositoryID, $template); + $template = \str_replace('{repositoryName}', $this->repository->name, $template); + + $classPathName = PACKAGES_DIR . 'lib/action/' . $className . 'Action.class.php'; + + \file_put_contents($classPathName, $template); + } + + public function delete() + { + $className = StringUtil::firstCharToUpperCase($this->repository->name); + $classPathName = PACKAGES_DIR . 'lib/action/' . $className . 'Action.class.php'; + + if (\file_exists($classPathName)) { + \unlink($classPathName); + } + } } diff --git a/files/lib/system/repository/RepositoryWriter.class.php b/files/lib/system/repository/RepositoryWriter.class.php index a62ffd7..d13fef0 100644 --- a/files/lib/system/repository/RepositoryWriter.class.php +++ b/files/lib/system/repository/RepositoryWriter.class.php @@ -1,154 +1,199 @@ outputFile = $outputFile; - } - - public function createSection() { - $this->section = $this->document->createElement('section'); - $this->section->appendChild($this->createSimpleAttribute('xmlns', 'http://www.woltlab.com')); - $this->section->appendChild($this->createSimpleAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')); - $this->section->appendChild($this->createSimpleAttribute('name', 'packages')); - $this->section->appendChild($this->createSimpleAttribute('xsi:schemaLocation', 'http://www.woltlab.com https://www.woltlab.com/XSD/tornado/packageUpdateServer.xsd')); - } - - public function createPackage($name, $packageName, $packageDescription, $authorName, $authorURL, $versions, $isApplication, $license) { - $package = $this->document->createElement('package'); - $package->appendChild($this->createSimpleAttribute('name', $name)); - - $package->appendChild($this->createPackageInformation($packageName, $packageDescription, $isApplication)); - $package->appendChild($this->createAuthorInformation($authorName, $authorURL)); - $package->appendChild($this->createVersions($versions, $license)); - - $this->packages[] = $package; - } - - protected function createPackageInformation($packageName, $packageDescription, $isApplication) { - $packageinformation = $this->document->createElement('packageinformation'); - - $packageinformation->appendChild($this->createCDATAElement('packagename', $packageName)); - $packageinformation->appendChild($this->createCDATAElement('packagedescription', $packageDescription)); - if ($isApplication == 1) - $packageinformation->appendChild($this->document->createElement('isapplication', 1)); - - return $packageinformation; - } - - protected function createAuthorInformation($authorName, $authorURL) { - $authorinformation = $this->document->createElement('authorinformation'); - - $authorinformation->appendChild($this->createCDATAElement('author', $authorName)); - $authorinformation->appendChild($this->createCDATAElement('authorurl', $authorURL)); - - return $authorinformation; - } - - protected function createVersions($versions, $license) { - $versionsNode = $this->document->createElement('versions'); - - foreach ($versions as $version) { - $versionsNode->appendChild($this->createVersion($version['version'], $version['timestamp'], $version['updateType'], $version['requiredPackages'], $version['excludedPackages'], $version['instructions'], $license, $version['requireAuth'])); - } - - return $versionsNode; - } - - protected function createVersion($versionNr, $versionTime, $updateType, $requiredPackages, $excludedPackages, $updateInstructions, $license, $requireAuth) { - $version = $this->document->createElement('version'); - - $version->appendChild($this->createSimpleAttribute('name', $versionNr)); - $version->appendChild($this->createSimpleAttribute('accessible', 'true')); - $version->appendChild($this->createSimpleAttribute('requireAuth', $requireAuth)); - if ($updateInstructions != null) - { - $version->appendChild($this->createFromVersions($updateInstructions)); - } - if (count($requiredPackages) > 0) - { - $version->appendChild($this->createRequiredPackages($requiredPackages)); - } - if (count($excludedPackages) > 0) - { - $version->appendChild($this->createExcludedPackages($excludedPackages)); - } - $version->appendChild($this->createCDATAElement('updatetype', $updateType)); - $version->appendChild($this->createCDATAElement('timestamp', $versionTime)); - $version->appendChild($this->createCDATAElement('license', $license)); - - return $version; - } - - protected function createFromVersions($updateInstructions) { - $fromversions = $this->document->createElement('fromversions'); - - foreach($updateInstructions as $version => $updateInstruction) - { - $fromversion = $this->createCDATAElement('fromversion', $version); - - $fromversions->appendChild($fromversion); - } - - return $fromversions; - } - - protected function createRequiredPackages($requiredPackages) { - $requiredpackages = $this->document->createElement('requiredpackages'); - - foreach($requiredPackages as $name => $requiredPackage) - { - $requiredpackage = $this->createCDATAElement('requiredpackage', $requiredPackage['name']); - $requiredpackage->appendChild($this->createSimpleAttribute('minversion', $requiredPackage['minversion'])); - $requiredpackages->appendChild($requiredpackage); - } - - return $requiredpackages; - } - - protected function createExcludedPackages($excludedPackages) { - $excludedpackages = $this->document->createElement('excludedpackages'); - - foreach($excludedPackages as $excludedPackage) - { - $excludedpackage = $this->createCDATAElement('excludedpackage', $excludedPackage['name']); - $excludedpackage->appendChild($this->createSimpleAttribute('version', $excludedPackage['version'])); - $excludedpackages->appendChild($excludedpackage); - } - - return $excludedpackages; - } - - public function save() { - foreach ($this->packages as $package) { - $this->section->appendChild($package); - } - - $this->document->appendChild($this->section); - $this->document->formatOutput = true; - $this->document->save($this->outputFile); - } - - protected function createSimpleAttribute($name, $value) - { - $attr = $this->document->createAttribute($name); - $attr->value = $value; - return $attr; - } - - protected function createCDATAElement($name, $value) - { - $element = $this->document->createElement($name); - $element->appendChild($this->document->createCDATASection($value)); - return $element; - } +class RepositoryWriter extends XML +{ + protected $outputFile; + + protected $section; + + protected $packages = []; + + public function __construct($outputFile) + { + parent::__construct(); + + $this->outputFile = $outputFile; + } + + public function createSection() + { + $this->section = $this->document->createElement('section'); + $this->section->appendChild($this->createSimpleAttribute('xmlns', 'http://www.woltlab.com')); + $this->section->appendChild( + $this->createSimpleAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance') + ); + $this->section->appendChild($this->createSimpleAttribute('name', 'packages')); + $this->section->appendChild( + $this->createSimpleAttribute( + 'xsi:schemaLocation', + 'http://www.woltlab.com https://www.woltlab.com/XSD/tornado/packageUpdateServer.xsd' + ) + ); + } + + public function createPackage( + $name, + $packageName, + $packageDescription, + $authorName, + $authorURL, + $versions, + $isApplication, + $license + ) { + $package = $this->document->createElement('package'); + $package->appendChild($this->createSimpleAttribute('name', $name)); + + $package->appendChild($this->createPackageInformation($packageName, $packageDescription, $isApplication)); + $package->appendChild($this->createAuthorInformation($authorName, $authorURL)); + $package->appendChild($this->createVersions($versions, $license)); + + $this->packages[] = $package; + } + + protected function createPackageInformation($packageName, $packageDescription, $isApplication) + { + $packageinformation = $this->document->createElement('packageinformation'); + + $packageinformation->appendChild($this->createCDATAElement('packagename', $packageName)); + $packageinformation->appendChild($this->createCDATAElement('packagedescription', $packageDescription)); + if ($isApplication == 1) { + $packageinformation->appendChild($this->document->createElement('isapplication', 1)); + } + + return $packageinformation; + } + + protected function createAuthorInformation($authorName, $authorURL) + { + $authorinformation = $this->document->createElement('authorinformation'); + + $authorinformation->appendChild($this->createCDATAElement('author', $authorName)); + $authorinformation->appendChild($this->createCDATAElement('authorurl', $authorURL)); + + return $authorinformation; + } + + protected function createVersions($versions, $license) + { + $versionsNode = $this->document->createElement('versions'); + + foreach ($versions as $version) { + $versionsNode->appendChild( + $this->createVersion( + $version['version'], + $version['timestamp'], + $version['updateType'], + $version['requiredPackages'], + $version['excludedPackages'], + $version['instructions'], + $license, + $version['requireAuth'] + ) + ); + } + + return $versionsNode; + } + + protected function createVersion( + $versionNr, + $versionTime, + $updateType, + $requiredPackages, + $excludedPackages, + $updateInstructions, + $license, + $requireAuth + ) { + $version = $this->document->createElement('version'); + + $version->appendChild($this->createSimpleAttribute('name', $versionNr)); + $version->appendChild($this->createSimpleAttribute('accessible', 'true')); + $version->appendChild($this->createSimpleAttribute('requireAuth', $requireAuth)); + if ($updateInstructions != null) { + $version->appendChild($this->createFromVersions($updateInstructions)); + } + if (\count($requiredPackages) > 0) { + $version->appendChild($this->createRequiredPackages($requiredPackages)); + } + if (\count($excludedPackages) > 0) { + $version->appendChild($this->createExcludedPackages($excludedPackages)); + } + $version->appendChild($this->createCDATAElement('updatetype', $updateType)); + $version->appendChild($this->createCDATAElement('timestamp', $versionTime)); + $version->appendChild($this->createCDATAElement('license', $license)); + + return $version; + } + + protected function createFromVersions($updateInstructions) + { + $fromversions = $this->document->createElement('fromversions'); + + foreach ($updateInstructions as $version => $updateInstruction) { + $fromversion = $this->createCDATAElement('fromversion', $version); + + $fromversions->appendChild($fromversion); + } + + return $fromversions; + } + + protected function createRequiredPackages($requiredPackages) + { + $requiredpackages = $this->document->createElement('requiredpackages'); + + foreach ($requiredPackages as $name => $requiredPackage) { + $requiredpackage = $this->createCDATAElement('requiredpackage', $requiredPackage['name']); + $requiredpackage->appendChild($this->createSimpleAttribute('minversion', $requiredPackage['minversion'])); + $requiredpackages->appendChild($requiredpackage); + } + + return $requiredpackages; + } + + protected function createExcludedPackages($excludedPackages) + { + $excludedpackages = $this->document->createElement('excludedpackages'); + + foreach ($excludedPackages as $excludedPackage) { + $excludedpackage = $this->createCDATAElement('excludedpackage', $excludedPackage['name']); + $excludedpackage->appendChild($this->createSimpleAttribute('version', $excludedPackage['version'])); + $excludedpackages->appendChild($excludedpackage); + } + + return $excludedpackages; + } + + public function save() + { + foreach ($this->packages as $package) { + $this->section->appendChild($package); + } + + $this->document->appendChild($this->section); + $this->document->formatOutput = true; + $this->document->save($this->outputFile); + } + + protected function createSimpleAttribute($name, $value) + { + $attr = $this->document->createAttribute($name); + $attr->value = $value; + + return $attr; + } + + protected function createCDATAElement($name, $value) + { + $element = $this->document->createElement($name); + $element->appendChild($this->document->createCDATASection($value)); + + return $element; + } } From 40c10b7b436476778a1fc6bd8d5fd05a6600bbde Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 11:48:17 +0200 Subject: [PATCH 4/6] 1.1.0 --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 4080d14..51f5f5b 100644 --- a/package.xml +++ b/package.xml @@ -5,7 +5,7 @@ Package server Ein kleiner Paketserver der auf die Filebase von WoltLab aufbaut. 1 - 1.0.0 + 1.1.0 2023-10-21 From b38a345846820bf690d731c93baaf3bbc3a9172c Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 11:55:56 +0200 Subject: [PATCH 5/6] Icons angepasst --- .../__haFilebaseCategoryAddPackageServer.tpl | 6 +++--- acptemplates/repositoryAdd.tpl | 9 ++++++++- acptemplates/repositoryList.tpl | 16 +++++----------- .../system/repository/RepositoryWriter.class.php | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/acptemplates/__haFilebaseCategoryAddPackageServer.tpl b/acptemplates/__haFilebaseCategoryAddPackageServer.tpl index 0247fa6..279e398 100644 --- a/acptemplates/__haFilebaseCategoryAddPackageServer.tpl +++ b/acptemplates/__haFilebaseCategoryAddPackageServer.tpl @@ -8,11 +8,11 @@
  1. - +
  2. - +
{lang}packages.page.filebaseCategoryAdd.packageServer.description{/lang} @@ -41,4 +41,4 @@ -{/if} \ No newline at end of file +{/if} diff --git a/acptemplates/repositoryAdd.tpl b/acptemplates/repositoryAdd.tpl index 6b1cded..0dd1a9f 100644 --- a/acptemplates/repositoryAdd.tpl +++ b/acptemplates/repositoryAdd.tpl @@ -4,6 +4,13 @@

{lang}packages.page.repositoryAdd.title{/lang}

+ + {include file='formError'} @@ -42,7 +49,7 @@
- {@SECURITY_TOKEN_INPUT_TAG} + {csrfToken}
diff --git a/acptemplates/repositoryList.tpl b/acptemplates/repositoryList.tpl index a747fc0..c283108 100644 --- a/acptemplates/repositoryList.tpl +++ b/acptemplates/repositoryList.tpl @@ -1,11 +1,5 @@ {include file='header' pageTitle='packages.page.repositoryList.title'} - -

{lang}packages.page.repositoryList.title{/lang}

@@ -13,7 +7,7 @@ @@ -29,7 +23,7 @@ {if $objects|count}
- +
@@ -42,9 +36,9 @@ {foreach from=$objects item=object} - + @@ -63,4 +57,4 @@

{lang}wcf.global.noItems{/lang}

{/if} -{include file='footer'} \ No newline at end of file +{include file='footer'} diff --git a/files/lib/system/repository/RepositoryWriter.class.php b/files/lib/system/repository/RepositoryWriter.class.php index d13fef0..701d0c7 100644 --- a/files/lib/system/repository/RepositoryWriter.class.php +++ b/files/lib/system/repository/RepositoryWriter.class.php @@ -30,7 +30,7 @@ public function createSection() $this->section->appendChild( $this->createSimpleAttribute( 'xsi:schemaLocation', - 'http://www.woltlab.com https://www.woltlab.com/XSD/tornado/packageUpdateServer.xsd' + 'http://www.woltlab.com http://www.woltlab.com/XSD/6.0/packageUpdateServer.xsd' ) ); } From e13d855ce742d07950a24ff97bfd1377bfccfd0f Mon Sep 17 00:00:00 2001 From: Peter Lohse Date: Sat, 21 Oct 2023 12:06:53 +0200 Subject: [PATCH 6/6] FormBuilder Umbau --- acptemplates/repositoryAdd.tpl | 40 +----- .../lib/acp/form/RepositoryAddForm.class.php | 130 +++++++++--------- 2 files changed, 67 insertions(+), 103 deletions(-) diff --git a/acptemplates/repositoryAdd.tpl b/acptemplates/repositoryAdd.tpl index 0dd1a9f..3aa55c5 100644 --- a/acptemplates/repositoryAdd.tpl +++ b/acptemplates/repositoryAdd.tpl @@ -13,44 +13,6 @@ -{include file='formError'} - -{if $success|isset} -

- {lang}packages.page.repositoryAdd.scuccess{/lang} -

-{/if} - -
-
- -
-
- - {if $errorField == 'name'} - - {if $errorType == 'tooShort'} - {lang}packages.page.repositoryAdd.name.error.tooShort{/lang} - {else if $errorType == 'noNumberOnStart'} - {lang}packages.page.repositoryAdd.name.error.noNumberOnStart{/lang} - {else if $errorType == 'wrongFormat'} - {lang}packages.page.repositoryAdd.name.error.wrongFormat{/lang} - {else if $errorType == 'nameTooLong'} - {lang}packages.page.repositoryAdd.name.error.nameTooLong{/lang} - {else if $errorType == 'alreadyUsed'} - {lang}packages.page.repositoryAdd.name.error.alreadyUsed{/lang} - {/if} - - {/if} - {lang}packages.page.repositoryAdd.name.description{/lang} -
- -
- -
- - {csrfToken} -
- +{@$form->getHtml()} {include file='footer'} \ No newline at end of file diff --git a/files/lib/acp/form/RepositoryAddForm.class.php b/files/lib/acp/form/RepositoryAddForm.class.php index ccdc4b1..60f629c 100644 --- a/files/lib/acp/form/RepositoryAddForm.class.php +++ b/files/lib/acp/form/RepositoryAddForm.class.php @@ -4,75 +4,77 @@ use packages\data\repository\RepositoryAction; use packages\data\repository\RepositoryList; -use wcf\form\AbstractForm; -use wcf\system\exception\UserInputException; -use wcf\system\WCF; +use wcf\form\AbstractFormBuilderForm; +use wcf\system\form\builder\container\FormContainer; +use wcf\system\form\builder\field\TextFormField; +use wcf\system\form\builder\field\validation\FormFieldValidationError; +use wcf\system\form\builder\field\validation\FormFieldValidator; -class RepositoryAddForm extends AbstractForm +class RepositoryAddForm extends AbstractFormBuilderForm { + /** + * @inheritDoc + */ + public $objectActionClass = RepositoryAction::class; + + /** + * @inheritDoc + */ public $activeMenuItem = 'packages.acp.menu.link.package.repository.add'; - protected $name; - - public function readFormParameters() - { - parent::readFormParameters(); - - if (isset($_POST['name'])) { - $this->name = $_POST['name']; - } - } - - public function validate() - { - parent::validate(); - - if (\strlen($this->name) < 2) { - throw new UserInputException('name', 'tooShort'); - } - if (\preg_match('/^[0-9]+$/', \substr($this->name, 0, 1))) { - throw new UserInputException('name', 'noNumberOnStart'); - } - if (!\preg_match('/^[a-z0-9]+$/', $this->name)) { - throw new UserInputException('name', 'wrongFormat'); - } - if (\strlen($this->name) > 20) { - throw new UserInputException('name', 'nameTooLong'); - } - - $repositoryList = new RepositoryList(); - $repositoryList->getConditionBuilder()->add('name = ?', [$this->name]); - $repositoryList->readObjects(); - if (\count($repositoryList) > 0) { - throw new UserInputException('name', 'alreadyUsed'); - } - } - - public function save() + /** + * @inheritDoc + */ + protected function createForm() { - parent::save(); - - $this->objectAction = new RepositoryAction([], 'create', ['data' => [ - 'name' => $this->name, - ]]); - $this->objectAction->executeAction(); - - $this->saved(); - } - - public function saved() - { - parent::saved(); - - WCF::getTPL()->assign('success', true); - } - - public function assignVariables() - { - parent::assignVariables(); - - WCF::getTPL()->assign([ - 'name' => $this->name, + parent::createForm(); + + $this->form->appendChildren([ + FormContainer::create('data') + ->appendChildren([ + TextFormField::create('name') + ->label('packages.page.repositoryAdd.name') + ->description('packages.page.repositoryAdd.name.description') + ->required() + ->maximumLength(20) + ->minimumLength(2) + ->addValidator( + new FormFieldValidator('formatCheck', static function (TextFormField $formField) { + if (\preg_match('/^[0-9]+$/', \substr($formField->getValue(), 0, 1))) { + $formField->addValidationError( + new FormFieldValidationError( + 'noNumberOnStart', + 'packages.page.repositoryAdd.name.error.noNumberOnStart' + ) + ); + + return; + } + if (!\preg_match('/^[a-z0-9]+$/', $formField->getValue())) { + $formField->addValidationError( + new FormFieldValidationError( + 'wrongFormat', + 'packages.page.repositoryAdd.name.error.wrongFormat' + ) + ); + + return; + } + + $repositoryList = new RepositoryList(); + $repositoryList->getConditionBuilder()->add('name = ?', [$formField->getValue()]); + $repositoryList->readObjects(); + if (\count($repositoryList) > 0) { + $formField->addValidationError( + new FormFieldValidationError( + 'alreadyUsed', + 'packages.page.repositoryAdd.name.error.alreadyUsed' + ) + ); + } + }) + ), + ]), ]); } }
- + {objectAction action="delete" objectTitle=$object->name} {event name='rowButtons'} {#$object->repositoryID}