diff --git a/.github/workflows/block-merge-freeze.yml b/.github/workflows/block-merge-freeze.yml index bbbe1ab..f28a021 100644 --- a/.github/workflows/block-merge-freeze.yml +++ b/.github/workflows/block-merge-freeze.yml @@ -29,11 +29,29 @@ jobs: steps: - name: Register server reference to fallback to master branch - run: | - server_ref="$(if [ '${{ github.base_ref }}' = 'main' ]; then echo -n 'master'; else echo -n '${{ github.base_ref }}'; fi)" - echo "server_ref=$server_ref" >> $GITHUB_ENV + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const baseRef = context.payload.pull_request.base.ref + if (baseRef === 'main' || baseRef === 'master') { + core.exportVariable('server_ref', 'master'); + console.log('Setting server_ref to master'); + } else { + const regex = /^stable(\d+)$/ + const match = baseRef.match(regex) + if (match) { + core.exportVariable('server_ref', match[0]); + console.log('Setting server_ref to ' + match[0]); + } else { + console.log('Not based on master/main/stable*, so skipping freeze check'); + } + } + - name: Download version.php from ${{ env.server_ref }} + if: ${{ env.server_ref != '' }} run: curl 'https://raw.githubusercontent.com/nextcloud/server/${{ env.server_ref }}/version.php' --output version.php - name: Run check + if: ${{ env.server_ref != '' }} run: cat version.php | grep 'OC_VersionString' | grep -i -v 'RC' diff --git a/.github/workflows/dependabot-approve-merge.yml b/.github/workflows/dependabot-approve-merge.yml index efe8bfe..ed902d9 100644 --- a/.github/workflows/dependabot-approve-merge.yml +++ b/.github/workflows/dependabot-approve-merge.yml @@ -9,7 +9,7 @@ name: Dependabot on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] branches: - main - master @@ -24,7 +24,7 @@ concurrency: jobs: auto-approve-merge: - if: github.actor == 'dependabot[bot]' || github.actor == 'renovate[bot]' + if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'renovate[bot]' runs-on: ubuntu-latest-low permissions: # for hmarr/auto-approve-action to approve PRs diff --git a/.github/workflows/lint-info-xml.yml b/.github/workflows/lint-info-xml.yml index ed6b4fe..25b6550 100644 --- a/.github/workflows/lint-info-xml.yml +++ b/.github/workflows/lint-info-xml.yml @@ -24,13 +24,15 @@ jobs: name: info.xml lint steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Download schema - run: wget https://raw.githubusercontent.com/nextcloud/server/master/resources/app-info-shipped.xsd + run: wget https://raw.githubusercontent.com/nextcloud/appstore/master/nextcloudappstore/api/v1/release/info.xsd - name: Lint info.xml uses: ChristophWurst/xmllint-action@36f2a302f84f8c83fceea0b9c59e1eb4a616d3c1 # v1.2 with: xml-file: ./appinfo/info.xml - xml-schema-file: ./app-info-shipped.xsd + xml-schema-file: ./info.xsd diff --git a/.github/workflows/lint-php-cs.yml b/.github/workflows/lint-php-cs.yml index 5108348..5333846 100644 --- a/.github/workflows/lint-php-cs.yml +++ b/.github/workflows/lint-php-cs.yml @@ -25,16 +25,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Get php version id: versions uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 - - name: Set up php${{ steps.versions.outputs.php-available }} - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + - name: Set up php${{ steps.versions.outputs.php-min }} + uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2 with: - php-version: ${{ steps.versions.outputs.php-available }} + php-version: ${{ steps.versions.outputs.php-min }} extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite coverage: none ini-file: development @@ -42,7 +44,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install dependencies - run: composer i + run: | + composer remove nextcloud/ocp --dev --no-scripts + composer i - name: Lint run: composer run cs:check || ( echo 'Please run `composer run cs:fix` to format your code' && exit 1 ) diff --git a/.github/workflows/lint-php.yml b/.github/workflows/lint-php.yml index 104fed6..6ddc133 100644 --- a/.github/workflows/lint-php.yml +++ b/.github/workflows/lint-php.yml @@ -24,7 +24,10 @@ jobs: php-versions: ${{ steps.versions.outputs.php-versions }} steps: - name: Checkout app - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + - name: Get version matrix id: versions uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.0.0 @@ -40,10 +43,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Set up php ${{ matrix.php-versions }} - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2 with: php-version: ${{ matrix.php-versions }} extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite diff --git a/.github/workflows/phpunit-sqlite.yml b/.github/workflows/phpunit-sqlite.yml index be9e332..4a5143c 100644 --- a/.github/workflows/phpunit-sqlite.yml +++ b/.github/workflows/phpunit-sqlite.yml @@ -25,7 +25,9 @@ jobs: server-max: ${{ steps.versions.outputs.branches-max-list }} steps: - name: Checkout app - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Get version matrix id: versions @@ -73,30 +75,35 @@ jobs: steps: - name: Set app env + if: ${{ env.APP_NAME == '' }} run: | # Split and keep last echo "APP_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV - name: Checkout server - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: + persist-credentials: false submodules: true repository: nextcloud/server ref: ${{ matrix.server-versions }} - name: Checkout app - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: + persist-credentials: false path: apps/${{ env.APP_NAME }} - name: Set up php ${{ matrix.php-versions }} - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2 with: php-version: ${{ matrix.php-versions }} # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite coverage: none ini-file: development + # Temporary workaround for missing pcntl_* in PHP 8.3 + ini-values: disable_functions= env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -110,7 +117,9 @@ jobs: # Only run if phpunit config file exists if: steps.check_composer.outputs.files_exists == 'true' working-directory: apps/${{ env.APP_NAME }} - run: composer i + run: | + composer remove nextcloud/ocp --dev --no-scripts + composer i - name: Set up Nextcloud env: diff --git a/.github/workflows/pr-feedback.yml b/.github/workflows/pr-feedback.yml index 6a01fa0..f4c0477 100644 --- a/.github/workflows/pr-feedback.yml +++ b/.github/workflows/pr-feedback.yml @@ -15,12 +15,17 @@ on: schedule: - cron: '30 1 * * *' +permissions: + contents: read + pull-requests: write + jobs: pr-feedback: + if: ${{ github.repository_owner == 'nextcloud' }} runs-on: ubuntu-latest steps: - name: The get-github-handles-from-website action - uses: marcelklehr/get-github-handles-from-website-action@a739600f6b91da4957f51db0792697afbb2f143c # v1.0.0 + uses: marcelklehr/get-github-handles-from-website-action@06b2239db0a48fe1484ba0bfd966a3ab81a08308 # v1.0.1 id: scrape with: website: 'https://nextcloud.com/team/' @@ -31,7 +36,7 @@ jobs: blocklist=$(curl https://raw.githubusercontent.com/nextcloud/.github/master/non-community-usernames.txt | paste -s -d, -) echo "blocklist=$blocklist" >> "$GITHUB_OUTPUT" - - uses: marcelklehr/pr-feedback-action@1883b38a033fb16f576875e0cf45f98b857655c4 + - uses: nextcloud/pr-feedback-action@f0cab224dea8e1f282f9451de322f323c78fc7a5 # main with: feedback-message: | Hello there, @@ -45,6 +50,6 @@ jobs: (If you believe you should not receive this message, you can add yourself to the [blocklist](https://github.com/nextcloud/.github/blob/master/non-community-usernames.txt).) days-before-feedback: 14 - start-date: '2024-04-30' + start-date: '2025-06-12' exempt-authors: '${{ steps.blocklist.outputs.blocklist }},${{ steps.scrape.outputs.users }}' exempt-bots: true diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index e925890..114a022 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -14,6 +14,9 @@ concurrency: group: psalm-${{ github.head_ref || github.run_id }} cancel-in-progress: true +permissions: + contents: read + jobs: static-analysis: runs-on: ubuntu-latest @@ -21,24 +24,36 @@ jobs: name: static-psalm-analysis steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: Get php version id: versions uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 + - name: Check enforcement of minimum PHP version ${{ steps.versions.outputs.php-min }} in psalm.xml + run: grep 'phpVersion="${{ steps.versions.outputs.php-min }}' psalm.xml + - name: Set up php${{ steps.versions.outputs.php-available }} - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2 with: php-version: ${{ steps.versions.outputs.php-available }} extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite coverage: none ini-file: development + # Temporary workaround for missing pcntl_* in PHP 8.3 + ini-values: disable_functions= env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Install dependencies - run: composer i + run: | + composer remove nextcloud/ocp --dev --no-scripts + composer i + + - name: Install nextcloud/ocp + run: composer require --dev nextcloud/ocp:dev-${{ steps.versions.outputs.branches-max }} --ignore-platform-reqs --with-dependencies - name: Run coding standards check - run: composer run psalm + run: composer run psalm -- --threads=1 --monochrome --no-progress --output-format=github diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml index 95eaba8..95a8626 100644 --- a/.github/workflows/reuse.yml +++ b/.github/workflows/reuse.yml @@ -11,12 +11,17 @@ name: REUSE Compliance Check on: [pull_request] +permissions: + contents: read + jobs: reuse-compliance-check: - runs-on: ubuntu-latest + runs-on: ubuntu-latest-low steps: - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false - name: REUSE Compliance Check - uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0 + uses: fsfe/reuse-action@bb774aa972c2a89ff34781233d275075cbddf542 # v5.0.0 diff --git a/.github/workflows/update-nextcloud-ocp.yml b/.github/workflows/update-nextcloud-ocp.yml index bbeec0c..d7ba4a3 100644 --- a/.github/workflows/update-nextcloud-ocp.yml +++ b/.github/workflows/update-nextcloud-ocp.yml @@ -13,6 +13,10 @@ on: schedule: - cron: "5 2 * * 0" +permissions: + contents: read + issues: write + jobs: update-nextcloud-ocp: runs-on: ubuntu-latest @@ -20,21 +24,22 @@ jobs: strategy: fail-fast: false matrix: - branches: ['main', 'master', 'stable30', 'stable29', 'stable28'] + branches: ['main', 'master', 'stable31', 'stable30'] name: update-nextcloud-ocp-${{ matrix.branches }} steps: - id: checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: + persist-credentials: false ref: ${{ matrix.branches }} submodules: true continue-on-error: true - name: Set up php8.2 if: steps.checkout.outcome == 'success' - uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2 with: php-version: 8.2 # https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html#prerequisites-for-manual-installation @@ -103,7 +108,7 @@ jobs: - name: Create Pull Request if: steps.checkout.outcome == 'success' - uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: token: ${{ secrets.COMMAND_BOT_PAT }} commit-message: 'chore(dev-deps): Bump nextcloud/ocp package' diff --git a/appinfo/info.xml b/appinfo/info.xml index 8ee89ac..50f9717 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -21,7 +21,6 @@ Joas Schilling Survey_Client - tools diff --git a/lib/Collector.php b/lib/Collector.php index 0f47838..f03d319 100644 --- a/lib/Collector.php +++ b/lib/Collector.php @@ -18,6 +18,8 @@ use OCA\Survey_Client\Categories\Stats; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Services\IAppConfig; +use OCP\AppFramework\Utility\ITimeFactory; use OCP\Http\Client\IClientService; use OCP\IConfig; use OCP\IDBConnection; @@ -27,32 +29,20 @@ class Collector { public const SURVEY_SERVER_URL = 'https://surveyserver.nextcloud.com/'; /** @var ICategory[] */ - protected $categories; - - /** @var IClientService */ - protected $clientService; - - /** @var IConfig */ - protected $config; - - /** @var IDBConnection */ - protected $connection; - - /** @var IniGetWrapper */ - protected $phpIni; - - /** @var IL10N */ - protected $l; - - public function __construct(IClientService $clientService, IConfig $config, IDBConnection $connection, IniGetWrapper $phpIni, IL10N $l) { - $this->clientService = $clientService; - $this->config = $config; - $this->connection = $connection; - $this->phpIni = $phpIni; - $this->l = $l; + protected array $categories; + + public function __construct( + protected IClientService $clientService, + protected IConfig $config, + protected IAppConfig $appConfig, + protected IDBConnection $connection, + protected IniGetWrapper $phpIni, + protected IL10N $l, + protected ITimeFactory $timeFactory, + ) { } - protected function registerCategories() { + protected function registerCategories(): void { $this->categories[] = new Server( $this->config, $this->l @@ -85,9 +75,9 @@ protected function registerCategories() { } /** - * @return array + * @return array */ - public function getCategories() { + public function getCategories(): array { $this->registerCategories(); $categories = []; @@ -95,7 +85,7 @@ public function getCategories() { foreach ($this->categories as $category) { $categories[$category->getCategory()] = [ 'displayName' => $category->getDisplayName(), - 'enabled' => $this->config->getAppValue('survey_client', $category->getCategory(), 'yes') === 'yes', + 'enabled' => $this->appConfig->getAppValueBool($category->getCategory(), true), ]; } @@ -103,14 +93,14 @@ public function getCategories() { } /** - * @return array + * @return array{id: string, items: array} */ public function getReport() { $this->registerCategories(); $tuples = []; foreach ($this->categories as $category) { - if ($this->config->getAppValue('survey_client', $category->getCategory(), 'yes') === 'yes') { + if ($this->appConfig->getAppValueBool($category->getCategory(), true)) { foreach ($category->getData() as $key => $value) { $tuples[] = [ $category->getCategory(), @@ -150,8 +140,8 @@ public function sendReport(): DataResponse { } if ($response->getStatusCode() === Http::STATUS_OK) { - $this->config->setAppValue('survey_client', 'last_sent', (string)time()); - $this->config->setAppValue('survey_client', 'last_report', json_encode($report)); + $this->appConfig->setAppValueInt('last_sent', $this->timeFactory->getTime()); + $this->appConfig->setAppValueString('last_report', json_encode($report), true); return new DataResponse( $report ); diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php index 6e314ab..19952f1 100644 --- a/lib/Settings/AdminSettings.php +++ b/lib/Settings/AdminSettings.php @@ -7,8 +7,10 @@ namespace OCA\Survey_Client\Settings; +use OCA\Survey_Client\BackgroundJobs\MonthlyReport; use OCA\Survey_Client\Collector; use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Services\IAppConfig; use OCP\BackgroundJob\IJobList; use OCP\IConfig; use OCP\IDateTimeFormatter; @@ -16,53 +18,34 @@ use OCP\Settings\ISettings; class AdminSettings implements ISettings { - - /** @var Collector */ - private $collector; - - /** @var IConfig */ - private $config; - - /** @var IL10N */ - private $l; - - /** @var IDateTimeFormatter */ - private $dateTimeFormatter; - - /** @var IJobList */ - private $jobList; - - public function __construct(Collector $collector, - IConfig $config, - IL10N $l, - IDateTimeFormatter $dateTimeFormatter, - IJobList $jobList, + public function __construct( + protected Collector $collector, + protected IConfig $config, + protected IAppConfig $appConfig, + protected IL10N $l, + protected IDateTimeFormatter $dateTimeFormatter, + protected IJobList $jobList, ) { - $this->collector = $collector; - $this->config = $config; - $this->l = $l; - $this->dateTimeFormatter = $dateTimeFormatter; - $this->jobList = $jobList; } /** * @return TemplateResponse */ - public function getForm() { - $lastSentReportTime = (int)$this->config->getAppValue('survey_client', 'last_sent', '0'); + public function getForm(): TemplateResponse { + $lastSentReportTime = $this->appConfig->getAppValueInt('last_sent'); if ($lastSentReportTime === 0) { $lastSentReportDate = $this->l->t('Never'); } else { $lastSentReportDate = $this->dateTimeFormatter->formatDate($lastSentReportTime); } - $lastReport = $this->config->getAppValue('survey_client', 'last_report', ''); + $lastReport = $this->appConfig->getAppValueString('last_report', lazy: true); if ($lastReport !== '') { $lastReport = json_encode(json_decode($lastReport, true), JSON_PRETTY_PRINT); } $parameters = [ - 'is_enabled' => $this->jobList->has('OCA\Survey_Client\BackgroundJobs\MonthlyReport', null), + 'is_enabled' => $this->jobList->has(MonthlyReport::class, null), 'last_sent' => $lastSentReportDate, 'last_report' => $lastReport, 'categories' => $this->collector->getCategories() @@ -74,7 +57,7 @@ public function getForm() { /** * @return string the section ID, e.g. 'sharing' */ - public function getSection() { + public function getSection(): string { return 'survey_client'; } @@ -83,7 +66,7 @@ public function getSection() { * the admin section. The forms are arranged in ascending order of the * priority values. It is required to return a value between 0 and 100. */ - public function getPriority() { + public function getPriority(): int { return 50; } }