Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Simple slug route | ||
| $router->get('/{slug}', fn($params) => (new ArticleController())->show($params)); | ||
|
|
||
| // Admin | ||
| $router->get('/admin', fn() => (new DashboardController())->index()); |
There was a problem hiding this comment.
Catch-all slug hides /admin dashboard route
The catch‑all GET route /{slug} is registered before the admin routes, so a request to /admin is consumed by the slug handler (and attempts to render an article) before the DashboardController can run. After login you redirect to /admin, but that path will 404 as an article instead of showing the dashboard, effectively blocking access to the admin landing page.
Useful? React with 👍 / 👎.
| $data = $this->articleDataFromRequest(false); | ||
| $id = Article::create($data); | ||
| if ($data['include_id_tail']) { | ||
| $data['slug'] = rtrim($data['slug'], '-') . '-' . $id; | ||
| Article::update($id, $data); |
There was a problem hiding this comment.
Slug with ID tail can violate unique constraint when creating duplicates
When “include id tail” is selected, the create flow inserts the article with the unmodified slug and only appends the ID afterward. Because articles.slug is UNIQUE, creating a second post that reuses an existing slug expecting it to become slug-<id> will fail on the initial insert with a duplicate key error before the suffix is added, preventing those posts from being created.
Useful? React with 👍 / 👎.
| public static function findBySlug(string $slug): ?array | ||
| { | ||
| $sql = 'SELECT a.*, c.name as category_name FROM articles a LEFT JOIN categories c ON c.id = a.category_id WHERE a.slug = :slug'; | ||
| $stmt = Database::getInstance()->prepare($sql); | ||
| $stmt->execute([':slug' => $slug]); | ||
| $article = $stmt->fetch(); |
There was a problem hiding this comment.
Draft articles exposed via public slug route
The frontend slug lookup retrieves articles without filtering by status, so any draft or unpublished post is publicly reachable (and counted in stats) if someone guesses or retains its slug, even though listing queries filter to status = published. The slug fetch for public views should enforce published status to avoid exposing drafts.
Useful? React with 👍 / 👎.
Summary
Testing
Codex Task