-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/blog editor upgrade #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
WalkthroughThis PR modernizes the CMS by integrating EditorJS as the rich-text editor for posts, implementing an event-driven architecture for authentication and maintenance workflows, updating package dependencies, and migrating namespace references from Changes
Sequence DiagramsequenceDiagram
participant User as User (Browser)
participant Editor as EditorJS Instance
participant Form as Post Form
participant Server as Server/Controller
participant Model as Post Model
participant DB as Database
participant Renderer as EditorJsRenderer
participant View as Blog View
User->>Editor: Edit/Create Post Content
Editor->>Editor: Capture JSON blocks
Editor->>Form: Update hidden field (content-json)
User->>Form: Submit Form
Form->>Server: POST with content-json
Server->>Model: setContent(jsonString)
Model->>Model: Decode JSON & extract plain text
Model->>Model: Store _contentRaw & _body
Server->>DB: Save Post
DB-->>Server: Saved
rect rgb(200, 220, 240)
Note over Server,View: Content Display Flow
Server->>Renderer: render(contentRaw)
Renderer->>Renderer: Parse EditorJS blocks
Renderer->>Renderer: Apply ShortcodeParser
Renderer->>Renderer: Apply WidgetRenderer
Renderer-->>Server: Rendered HTML
Server->>View: Pass renderedContent
View->>View: Apply CSS styling
View-->>User: Display formatted post
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/Cms/Services/Auth/Authentication.php (1)
226-249: Fix infinite recursion on stale sessions inuser()/logout()In
user():if( !$user ) { // Clear stale session if user no longer exists $this->logout(); }If the session contains a
user_idfor a user that has been deleted, this callslogout(), which in turn calls$this->check()and$this->user(), triggering the same path again and causing infinite recursion (now with additional event logic on each loop).Instead of delegating to
logout(), clear the stale session inline:- $user = $this->_userRepository->findById( $userId ); - - if( !$user ) - { - // Clear stale session if user no longer exists - $this->logout(); - } - - return $user; + $user = $this->_userRepository->findById( $userId ); + + if( !$user ) + { + // Clear stale session and remember-me cookie without recursion + $this->_sessionManager->destroy(); + + if( isset( $_COOKIE['remember_token'] ) ) + { + setcookie( 'remember_token', '', time() - 3600, '/', '', true, true ); + } + + return null; + } + + return $user;This preserves the intended behavior (dropping an invalid session and remember-me cookie) without risking a stack overflow or runaway event emissions when the underlying user record is missing.
src/Cms/Controllers/Blog.php (1)
87-93: "Not found" post will have empty content for rendering.When a post is not found, a dummy Post object is created with
setBody()but the new rendering pipeline usesgetContent()which will return the default empty EditorJS structure{"blocks":[]}. This means the "not found" message won't be displayed.Update the "not found" post to use the new content structure:
if( !$post ) { $post = new Post(); $post->setTitle( 'Article Not Found' ); - $post->setBody( 'The requested article does not exist.' ); + $post->setContent( json_encode([ + 'blocks' => [ + [ + 'type' => 'paragraph', + 'data' => ['text' => 'The requested article does not exist.'] + ] + ] + ]) ); $post->setSlug( $slug ); }
🧹 Nitpick comments (16)
resources/views/http_codes/500.php (2)
8-20: Inline styles are appropriate for error pages.Using inline styles ensures the page displays correctly even if external stylesheets fail to load, which is a good practice for error pages.
Optional: Consider adding responsive design for smaller screens:
.centered { text-align: center; - margin-top: 100px; /* Adjust this value as needed */ + margin-top: 10vh; + padding: 0 15px; } .centered-text { text-align: center; margin-top: 20px; font-size: 16px; color: #666; + padding: 0 15px; }
1-6: Consider adding accessibility attributes and user escape hatches.The error page would benefit from:
- ARIA landmark roles for screen readers
- A link back to the home page or contact information
-<div class="row"> - <div class="col"> +<div class="row" role="main"> + <div class="col"> <h1 class="centered">Something went wrong on our end.</h1> <p class="centered-text">The server encountered an unexpected error. Please try again later.</p> + <p class="centered-text"><a href="/" style="color: #0066cc;">Return to Home</a></p> </div> </div>src/Cms/Repositories/DatabaseCategoryRepository.php (1)
211-217: GROUP BY may break on PostgreSQL
allWithPostCount()selectsc.*but groups only byc.id; PostgreSQL’s stricter GROUP BY rules will reject this query. If you intend this repository to work against PostgreSQL (per the class doc), you’ll need to either:
- Group by all selected
categoriescolumns, or- Select only grouped/aggregated columns.
Please confirm whether PostgreSQL is a supported target in your deployments; if so, consider adjusting the SELECT/GROUP BY to be portable.
composer.json (1)
15-27: Dependency updates align with the Settings refactor; confirm version rangesThe move to
neuron-php/mvc: "0.9.*"and addition ofneuron-php/data: "0.9.*"andneuron-php/scaffolding: "0.8.*"fit the new Settings namespace and tooling story.One nuance:
"0.9.*"can allow earlier 0.9.x releases than^0.9.5would have; in practice Composer will usually pick the latest matching version, but if you depend on features/bugfixes introduced in later 0.9.x, you may prefer a caret or a higher minimum.Please make sure
composer.lockis updated and CI (including migrations/tests that touch Settings) passes with these new constraints. If you want to avoid accidentally downgrading, consider tightening the constraints (e.g.,^0.9.5/^0.9.0) before merging.src/Cms/Repositories/DatabasePostRepository.php (1)
84-103: Verify handling of the newcontent_rawcolumn in postsThe new migration adds a non‑nullable
content_rawcolumn intended for Editor.js JSON, but this repository currently:
- Inserts/updates only
body/excerpt(nocontent_rawin the column/value lists), and- Does not include
content_rawin the$dataarray passed toPost::fromArray().Because the DB default will populate
content_raw, this won’t break inserts, but any Editor.js JSON stored on the entity may not be persisted or hydrated unless other layers handle it.Please double‑check how the
Postmodel exposes raw Editor.js content (e.g.,getContentRaw()/setContentRaw()or similar), and consider extending:
- the INSERT/UPDATE statements, and
mapRowToPost()’s$dataarray
to read/writecontent_rawif that field is meant to be first‑class in the domain.Also applies to: 141-168, 440-455
src/Cms/Services/Auth/PasswordResetter.php (1)
106-110: LGTM! Event emissions enhance observability.The addition of
PasswordResetRequestedEventandPasswordResetCompletedEventprovides valuable audit trails for password reset workflows. The fallback to'unknown'for$_SERVER['REMOTE_ADDR']appropriately handles CLI and testing contexts.Consider importing the event classes at the top of the file rather than using fully qualified names for improved readability:
+use Neuron\Cms\Events\PasswordResetRequestedEvent; +use Neuron\Cms\Events\PasswordResetCompletedEvent; +use Neuron\Application\CrossCutting\Event;Then use:
- \Neuron\Application\CrossCutting\Event::emit( new \Neuron\Cms\Events\PasswordResetRequestedEvent( + Event::emit( new PasswordResetRequestedEvent(Also applies to: 175-179
resources/views/admin/posts/edit.php (2)
24-31: Harden handling of existing EditorJS content JSON before initializationCurrent parsing only falls back on JSON syntax errors; valid-but-unexpected JSON (e.g.
"null"or an object withoutblocks) will flow intodataand may confuse EditorJS.You can defensively ensure a valid
blocksarray after parsing:-let existingContent; -try { - existingContent = JSON.parse(existingContentJson); -} catch (error) { - console.error('Failed to parse existing content:', error); - existingContent = { blocks: [] }; -} +let existingContent; +try { + existingContent = JSON.parse(existingContentJson); + + // Ensure we always pass a valid Editor.js data structure + if( !existingContent || !Array.isArray( existingContent.blocks ) ) + { + existingContent = { blocks: [] }; + } +} catch (error) { + console.error('Failed to parse existing content:', error); + existingContent = { blocks: [] }; +}This keeps the editor resilient to legacy or malformed
content_rawvalues while preserving your existing fallback behavior.Also applies to: 93-103, 104-109
82-90: Consider pinning EditorJS CDN versions and reducingsave()frequencyThe EditorJS integration and submit flow look solid. Two optional robustness points:
- The
@latestCDN URLs can introduce breaking changes when a new major EditorJS (or tool) version ships. Consider pinning to a specific major/minor version (e.g.@2.xor an exact version) and upgrading deliberately.onChangecurrently callseditor.save()on every change, which is relatively heavy. If this becomes a performance issue for long posts, you could debounce/throttle the save into#content-jsonor rely solely on the submit handler to serialize content.Both are optional, but would make the editor behavior more predictable in production.
Also applies to: 145-149, 151-163
tests/Cms/Services/Post/CreatorTest.php (1)
45-69: Centralize EditorJS content JSON in a helper/fixture for test readabilityThe tests correctly assert both
getContentRaw()and the derivedgetBody(). The same EditorJS JSON pattern ({"blocks":[{"type":"paragraph","data":{"text":"Body"}}]}and variants) is repeated across multiple tests, though.To keep things DRY and easier to tweak later, consider extracting small helpers/constants, e.g.:
private function makeEditorJsContent(string $text = 'Body'): string { return json_encode([ 'blocks' => [ [ 'type' => 'paragraph', 'data' => ['text' => $text], ], ], ]); }Then use
makeEditorJsContent('Test body content')/makeEditorJsContent()throughout the tests instead of hardcoding JSON strings.Also applies to: 90-95, 118-123, 148-153, 177-182, 218-223, 263-273, 297-305
src/Cms/Maintenance/MaintenanceManager.php (1)
61-82: Emit maintenance events without risking core enable/disable operationsThe new enabled/disabled events are wired in cleanly, and the optional
$disabledByargument keeps the public API backward compatible.One robustness refinement to consider: if any event listener hooked into
MaintenanceModeEnabledEvent/MaintenanceModeDisabledEventthrows, callers ofenable()/disable()will see an exception even though the maintenance file has already been written or deleted. To keep state changes reliable, you might wrap the emits:- $result = $this->writeMaintenanceFile( $data ); - - // Emit maintenance mode enabled event - if( $result ) - { - \Neuron\Application\CrossCutting\Event::emit( new \Neuron\Cms\Events\MaintenanceModeEnabledEvent( - $data['enabled_by'], - $message - ) ); - } + $result = $this->writeMaintenanceFile( $data ); + + // Emit maintenance mode enabled event (non-fatal) + if( $result ) + { + try + { + \Neuron\Application\CrossCutting\Event::emit( + new \Neuron\Cms\Events\MaintenanceModeEnabledEvent( + $data['enabled_by'], + $message + ) + ); + } + catch( \Throwable $e ) + { + // Optional: log but do not affect enable() result + } + }and similarly in
disable(). That keeps maintenance mode toggling deterministic even if downstream listeners misbehave.Also applies to: 87-107
src/Cms/Services/Auth/Authentication.php (1)
41-59: Event emissions for login attempts look good; consider small refactorsThe new
UserLoginFailedEvent,UserLoginEvent, andUserLogoutEventhooks are well-placed and give you good observability over auth flows. A couple of low-friction refinements:
- The four failure branches emit
UserLoginFailedEventwith only thereasondiffering. You could extract a small private helper likeemitLoginFailed(string $username, string $reason): voidto reduce duplication and keep changes localized if you later enrich the payload.- In
login(), you callmicrotime( true )both when settinglogin_timein the session and when emittingUserLoginEvent. Reusing a single timestamp would keep those values perfectly aligned:- // Store user ID in session - $this->_sessionManager->set( 'user_id', $user->getId() ); - $this->_sessionManager->set( 'user_role', $user->getRole() ); - $this->_sessionManager->set( 'login_time', microtime( true ) ); + // Store user ID in session + $this->_sessionManager->set( 'user_id', $user->getId() ); + $this->_sessionManager->set( 'user_role', $user->getRole() ); + $loginTime = microtime( true ); + $this->_sessionManager->set( 'login_time', $loginTime ); @@ - // Emit user login event - \Neuron\Application\CrossCutting\Event::emit( new \Neuron\Cms\Events\UserLoginEvent( - $user, - $_SERVER['REMOTE_ADDR'] ?? 'unknown', - microtime( true ) - ) ); + // Emit user login event + \Neuron\Application\CrossCutting\Event::emit( new \Neuron\Cms\Events\UserLoginEvent( + $user, + $_SERVER['REMOTE_ADDR'] ?? 'unknown', + $loginTime + ) );Overall the behavior is sound; these are just to keep things DRY and metrics-friendly.
Also applies to: 61-85, 87-110, 134-156, 161-201
tests/Cms/Services/Post/UpdaterTest.php (1)
39-42: Mirror CreatorTest by centralizing EditorJS JSON for updatesThese tests correctly validate that
Updater::update()preserves both the raw EditorJS JSON (getContentRaw()) and the derived body text (getBody()), and that other fields (slug, status, categories, tags, etc.) behave as expected.As in
CreatorTest, you might want to centralize the repeated JSON snippets into a small helper (on this class or a shared trait) so any future changes to your EditorJS block shape only need to be made in one place.Also applies to: 54-70, 97-99, 127-128, 171-172, 218-219, 254-255, 285-286, 321-322
resources/views/admin/posts/create.php (1)
131-142: Consider potential issues with programmatic form submission.The submit handler prevents the default form submission, saves editor content, then calls
e.target.submit(). This bypasses normal HTML5 validation and could cause issues if there are other submit handlers or validation logic.Consider using FormData to submit the form programmatically while maintaining validation:
-document.getElementById('post-form').addEventListener('submit', async (e) => { - e.preventDefault(); - - try { - const savedData = await editor.save(); - document.getElementById('content-json').value = JSON.stringify(savedData); - e.target.submit(); - } catch (error) { - console.error('Error saving editor content:', error); - alert('Error preparing content. Please try again.'); - } -}); +document.getElementById('post-form').addEventListener('submit', async (e) => { + // Don't prevent default initially - let HTML5 validation run first + if (!e.target.checkValidity()) { + return; // Let browser handle validation + } + + e.preventDefault(); + + try { + const savedData = await editor.save(); + document.getElementById('content-json').value = JSON.stringify(savedData); + e.target.submit(); + } catch (error) { + console.error('Error saving editor content:', error); + alert('Error preparing content. Please try again.'); + } +});src/Cms/Controllers/Blog.php (1)
106-108: Add error handling for content rendering.The renderer should handle malformed JSON or rendering errors gracefully to prevent the page from breaking when post content is invalid.
Wrap the rendering in a try-catch block:
- // Render content from Editor.js JSON - $content = $post->getContent(); - $renderedContent = $this->_renderer->render( $content ); + // Render content from Editor.js JSON + $content = $post->getContent(); + try { + $renderedContent = $this->_renderer->render( $content ); + } catch (\Exception $e) { + error_log("Error rendering post content for slug '{$slug}': " . $e->getMessage()); + $renderedContent = '<p>Content temporarily unavailable.</p>'; + }src/Cms/Models/Post.php (2)
125-128: Add error handling for malformed JSON in getContent().If
_contentRawcontains invalid JSON,json_decode()will returnnulland the??operator will correctly return the default, but this happens silently. Consider logging the error for debugging.public function getContent(): array { - return json_decode( $this->_contentRaw, true ) ?? ['blocks' => []]; + $decoded = json_decode( $this->_contentRaw, true ); + if ($decoded === null && json_last_error() !== JSON_ERROR_NONE) { + error_log("Invalid JSON in Post content_raw (ID: {$this->_id}): " . json_last_error_msg()); + } + return $decoded ?? ['blocks' => []]; }
607-646: Consider XSS risks in extractPlainText() for 'raw' block type.Line 633 includes raw HTML from
rawblocks without sanitization when extracting plain text. Whilestrip_tags()is applied at line 640, malicious HTML could still be present in the intermediate processing.Since this is meant to be plain text extraction, consider whether
rawblocks should be included at all, or strip tags immediately:$blockText = match( $block['type'] ) { 'paragraph', 'header' => $block['data']['text'] ?? '', 'list' => isset( $block['data']['items'] ) && is_array( $block['data']['items'] ) ? implode( "\n", $block['data']['items'] ) : '', 'quote' => $block['data']['text'] ?? '', 'code' => $block['data']['code'] ?? '', - 'raw' => $block['data']['html'] ?? '', + 'raw' => strip_tags($block['data']['html'] ?? ''), // Strip tags immediately for raw HTML default => '' }; if( $blockText !== '' ) { // Strip HTML tags from text $blockText = strip_tags( $blockText ); $text[] = trim( $blockText ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (61)
composer.json(2 hunks)resources/app/Initializers/AuthInitializer.php(1 hunks)resources/app/Initializers/MaintenanceInitializer.php(1 hunks)resources/app/Initializers/PasswordResetInitializer.php(1 hunks)resources/app/Initializers/RegistrationInitializer.php(1 hunks)resources/database/migrate/20251119224525_add_content_raw_to_posts.php(1 hunks)resources/views/admin/posts/create.php(3 hunks)resources/views/admin/posts/edit.php(3 hunks)resources/views/blog/show.php(2 hunks)resources/views/http_codes/500.php(1 hunks)src/Bootstrap.php(1 hunks)src/Cms/Cli/Commands/Generate/EmailCommand.php(0 hunks)src/Cms/Cli/Commands/Generate/stubs/email.stub(0 hunks)src/Cms/Cli/Commands/Install/InstallCommand.php(1 hunks)src/Cms/Cli/Commands/Maintenance/EnableCommand.php(1 hunks)src/Cms/Cli/Commands/Queue/InstallCommand.php(0 hunks)src/Cms/Cli/Provider.php(0 hunks)src/Cms/Controllers/Admin/Categories.php(1 hunks)src/Cms/Controllers/Admin/Profile.php(1 hunks)src/Cms/Controllers/Admin/Users.php(1 hunks)src/Cms/Controllers/Blog.php(4 hunks)src/Cms/Controllers/Content.php(4 hunks)src/Cms/Database/ConnectionFactory.php(1 hunks)src/Cms/Email/helpers.php(1 hunks)src/Cms/Events/EmailVerifiedEvent.php(1 hunks)src/Cms/Events/MaintenanceModeDisabledEvent.php(1 hunks)src/Cms/Events/MaintenanceModeEnabledEvent.php(1 hunks)src/Cms/Events/PasswordResetCompletedEvent.php(1 hunks)src/Cms/Events/PasswordResetRequestedEvent.php(1 hunks)src/Cms/Events/UserLoginEvent.php(1 hunks)src/Cms/Events/UserLoginFailedEvent.php(1 hunks)src/Cms/Events/UserLogoutEvent.php(1 hunks)src/Cms/Maintenance/MaintenanceConfig.php(1 hunks)src/Cms/Maintenance/MaintenanceManager.php(1 hunks)src/Cms/Models/Post.php(5 hunks)src/Cms/Repositories/DatabaseCategoryRepository.php(1 hunks)src/Cms/Repositories/DatabaseEmailVerificationTokenRepository.php(1 hunks)src/Cms/Repositories/DatabasePageRepository.php(1 hunks)src/Cms/Repositories/DatabasePasswordResetTokenRepository.php(1 hunks)src/Cms/Repositories/DatabasePostRepository.php(1 hunks)src/Cms/Repositories/DatabaseTagRepository.php(1 hunks)src/Cms/Repositories/DatabaseUserRepository.php(1 hunks)src/Cms/Services/Auth/Authentication.php(5 hunks)src/Cms/Services/Auth/EmailVerifier.php(2 hunks)src/Cms/Services/Auth/PasswordResetter.php(3 hunks)src/Cms/Services/Email/Sender.php(1 hunks)src/Cms/Services/Member/RegistrationService.php(1 hunks)src/Cms/Services/Post/Creator.php(3 hunks)src/Cms/Services/Post/Updater.php(3 hunks)tests/Cms/BlogControllerTest.php(1 hunks)tests/Cms/Cli/Commands/Install/InstallCommandTest.php(1 hunks)tests/Cms/ContentControllerTest.php(1 hunks)tests/Cms/Maintenance/MaintenanceConfigTest.php(1 hunks)tests/Cms/Repositories/DatabaseEmailVerificationTokenRepositoryTest.php(1 hunks)tests/Cms/Repositories/DatabaseUserRepositoryTest.php(1 hunks)tests/Cms/Services/AuthenticationTest.php(1 hunks)tests/Cms/Services/EmailVerifierTest.php(1 hunks)tests/Cms/Services/PasswordResetterTest.php(1 hunks)tests/Cms/Services/Post/CreatorTest.php(9 hunks)tests/Cms/Services/Post/UpdaterTest.php(10 hunks)tests/Cms/Services/RegistrationServiceTest.php(1 hunks)
💤 Files with no reviewable changes (4)
- src/Cms/Cli/Provider.php
- src/Cms/Cli/Commands/Generate/EmailCommand.php
- src/Cms/Cli/Commands/Queue/InstallCommand.php
- src/Cms/Cli/Commands/Generate/stubs/email.stub
🧰 Additional context used
🧬 Code graph analysis (15)
src/Cms/Events/PasswordResetRequestedEvent.php (2)
src/Cms/Events/EmailVerifiedEvent.php (2)
__construct(29-33)getName(35-38)src/Cms/Events/PasswordResetCompletedEvent.php (2)
__construct(30-35)getName(37-40)
resources/views/admin/posts/create.php (1)
src/Cms/View/helpers.php (1)
route_path(70-79)
src/Cms/Events/MaintenanceModeDisabledEvent.php (2)
src/Cms/Events/EmailVerifiedEvent.php (2)
__construct(29-33)getName(35-38)src/Cms/Events/MaintenanceModeEnabledEvent.php (2)
__construct(30-35)getName(37-40)
src/Cms/Events/UserLoginEvent.php (3)
src/Cms/Events/EmailVerifiedEvent.php (2)
__construct(29-33)getName(35-38)src/Cms/Events/UserLoginFailedEvent.php (2)
__construct(31-38)getName(40-43)src/Cms/Events/UserLogoutEvent.php (2)
__construct(30-35)getName(37-40)
src/Cms/Events/UserLoginFailedEvent.php (3)
src/Cms/Events/EmailVerifiedEvent.php (2)
__construct(29-33)getName(35-38)src/Cms/Events/UserLoginEvent.php (2)
__construct(31-37)getName(39-42)src/Cms/Events/UserLogoutEvent.php (2)
__construct(30-35)getName(37-40)
src/Cms/Maintenance/MaintenanceManager.php (2)
src/Cms/Events/MaintenanceModeEnabledEvent.php (1)
MaintenanceModeEnabledEvent(24-41)src/Cms/Events/MaintenanceModeDisabledEvent.php (1)
MaintenanceModeDisabledEvent(24-39)
tests/Cms/Services/Post/CreatorTest.php (2)
src/Cms/Controllers/Content.php (1)
getTitle(141-144)src/Cms/Models/Post.php (2)
getTitle(74-77)getContentRaw(133-136)
src/Cms/Events/MaintenanceModeEnabledEvent.php (2)
src/Cms/Events/EmailVerifiedEvent.php (2)
__construct(29-33)getName(35-38)src/Cms/Events/MaintenanceModeDisabledEvent.php (2)
__construct(29-33)getName(35-38)
src/Cms/Services/Post/Creator.php (1)
src/Cms/Models/Post.php (1)
setContent(142-147)
src/Cms/Services/Auth/EmailVerifier.php (2)
src/Cms/Events/EmailVerifiedEvent.php (1)
EmailVerifiedEvent(24-39)src/Cms/Services/Auth/Authentication.php (1)
user(226-249)
resources/views/admin/posts/edit.php (2)
src/Cms/View/helpers.php (1)
route_path(70-79)src/Cms/Models/Post.php (2)
getId(57-60)getContentRaw(133-136)
src/Cms/Services/Auth/Authentication.php (6)
src/Cms/Events/UserLoginFailedEvent.php (1)
UserLoginFailedEvent(23-44)src/Cms/Models/User.php (2)
isLockedOut(332-340)isActive(187-190)src/Cms/Auth/SessionManager.php (1)
set(99-103)src/Cms/Events/UserLoginEvent.php (1)
UserLoginEvent(24-43)src/Cms/Controllers/Auth/Login.php (1)
logout(139-143)src/Cms/Events/UserLogoutEvent.php (1)
UserLogoutEvent(24-41)
resources/database/migrate/20251119224525_add_content_raw_to_posts.php (1)
src/Cms/Services/Post/Updater.php (1)
update(48-83)
tests/Cms/Services/Post/UpdaterTest.php (2)
src/Cms/Models/Post.php (5)
setContent(142-147)getTitle(74-77)getContentRaw(133-136)getBody(108-111)getStatus(246-249)src/Cms/Repositories/DatabasePostRepository.php (1)
update(127-187)
src/Cms/Services/Post/Updater.php (1)
src/Cms/Models/Post.php (1)
setContent(142-147)
🔇 Additional comments (54)
src/Cms/Maintenance/MaintenanceConfig.php (1)
5-5: Namespace migration is complete and verified.The import change from
Neuron\Data\SettingtoNeuron\Data\Settingson line 5 is correct. Verification confirms no remaining old namespace references exist in the codebase, and the new namespace is consistently used across 20 files (production code and tests).src/Cms/Cli/Commands/Maintenance/EnableCommand.php (1)
8-8: Yaml settings source namespace update looks correctThe Yaml import now targets
Neuron\Data\Settings\Source\Yaml, which matches how it’s used inloadConfiguration()and aligns with the Settings namespace migration; no further changes needed here as long as the installedneuron-php/dataversion exposes this namespace.src/Cms/Services/Email/Sender.php (1)
7-7: SettingManager import aligned with Settings namespaceSwitching to
Neuron\Data\Settings\SettingManageris consistent with the property/ctor type hints and the rest of the Settings migration; the email config access remains unchanged.src/Cms/Services/Member/RegistrationService.php (1)
9-9: RegistrationService now correctly targets Settings\SettingManagerThe import of
Neuron\Data\Settings\SettingManagermatches the constructor and property types and keeps the member settings lookups intact.src/Cms/Controllers/Admin/Categories.php (1)
11-11: Categories controller import updated to Settings\SettingManagerThe controller now imports
Neuron\Data\Settings\SettingManager, keeping it consistent with the rest of the Settings namespace migration in the project.tests/Cms/Maintenance/MaintenanceConfigTest.php (1)
6-6: Test Yaml source import matches new Settings namespaceUsing
Neuron\Data\Settings\Source\Yamlin this test is consistent with the production MaintenanceConfig usage and the broader Settings namespace move.src/Cms/Repositories/DatabaseEmailVerificationTokenRepository.php (1)
7-7: Repository constructor now depends on Settings\SettingManagerThe repository correctly imports
Neuron\Data\Settings\SettingManagerand passes it toConnectionFactory::createFromSettings(), keeping database configuration behavior unchanged under the new namespace.tests/Cms/Repositories/DatabaseEmailVerificationTokenRepositoryTest.php (1)
8-8: Test mock updated to Settings\SettingManagerThe test now mocks
Neuron\Data\Settings\SettingManager, matching the repository’s constructor signature and ensuring the database config wiring remains valid.tests/Cms/ContentControllerTest.php (1)
6-6: In-memory settings source switched to Settings\Source\MemoryThe test now uses
Neuron\Data\Settings\Source\Memory, which is consistent with the Settings namespace refactor and how the controller reads settings via the Registry.src/Cms/Repositories/DatabaseUserRepository.php (1)
7-7: Repository constructor now aligned withSettingsnamespaceThe repository’s dependency on
SettingManageris correctly switched to theNeuron\Data\Settingsnamespace, keeping the constructor type-hint andConnectionFactory::createFromSettings()usage consistent.Please run your user-related tests (e.g.,
DatabaseUserRepositoryTest, auth flows) to confirm there are no remaining references to the oldNeuron\Data\Setting\SettingManagertype.src/Cms/Repositories/DatabasePageRepository.php (1)
8-8: Page repositorySettingManagerimport migrated cleanlyThe constructor’s
SettingManagerdependency now points atNeuron\Data\Settings\SettingManager, matching the rest of the PR’s namespace migration without altering any repository behavior.Confirm that any code instantiating
DatabasePageRepository(controllers/services) is also using the updatedSettings-namespaceSettingManagerinstance from the container/registry.src/Cms/Repositories/DatabaseTagRepository.php (1)
7-7: Tag repository settings dependency updated to new namespace
DatabaseTagRepositorynow correctly importsNeuron\Data\Settings\SettingManagerwhile keeping the constructor contract and internals the same, so behavior should be unaffected.As part of your test run, ensure any install/seed or tag-related CLI flows still resolve the correct
SettingManagerimplementation.tests/Cms/Cli/Commands/Install/InstallCommandTest.php (1)
8-9: Install command test imports aligned withSettingsnamespaceThe test now imports
Neuron\Data\Settings\SettingManagerandNeuron\Data\Settings\Source\Yaml, matching the production code’s updated namespaces and avoiding mismatch with the newer data/settings package layout.If these imports are no longer needed by the test, they can be safely removed in a later cleanup pass once static analysis (e.g., phpstan/psalm) is green.
src/Cms/Controllers/Admin/Users.php (1)
13-13: Admin Users controller now consistent withSettings-based repositoriesThe controller’s import of
Neuron\Data\Settings\SettingManagermatches the updated constructor dependency ofDatabaseUserRepository, keeping the Registry-provided'Settings'instance aligned with the repository’s expected type.Please verify that the Registry is registering an instance of the new
Neuron\Data\Settings\SettingManagerclass under the'Settings'key in your bootstrap/initializer code.src/Bootstrap.php (1)
4-5: Bootstrap imports updated to new data library namespaces
VersionandYamlnow import fromNeuron\Data\Objects\VersionandNeuron\Data\Settings\Source\Yaml, which matches the reorganized data library structure without changing theboot()logic.After updating composer dependencies, run a full application bootstrap (and any bootstrap-related tests) to confirm there are no unresolved references to the old
Neuron\Data\Object\VersionorNeuron\Data\Setting\Source\Yamlclasses.src/Cms/Controllers/Admin/Profile.php (1)
10-10: Admin Profile controller settings import matches repository expectationsThe profile controller’s import now targets
Neuron\Data\Settings\SettingManager, aligning its dependency graph with the updatedDatabaseUserRepositoryand the broader Settings namespace migration.As with the Users controller, double‑check that the Registry’s
'Settings'entry is an instance of the newSettings\SettingManagerto avoid subtle type mismatches at runtime.src/Cms/Database/ConnectionFactory.php (1)
5-5: Namespace migration verified as completeThe import change to
Neuron\Data\Settings\SettingManageris correct and actively used. Verification confirms:
- No lingering references to the old
Neuron\Data\Settingnamespace exist- The type hint in
createFromSettings()(line 26) properly references the newSettingManagerclass- The method implementation correctly delegates to
createFromConfig()as expectedThe migration is consistent and safe to merge.
src/Cms/Repositories/DatabaseCategoryRepository.php (1)
7-7: Settings namespace update is consistentSwitching to
Neuron\Data\Settings\SettingManagerhere matches the broader Settings namespace refactor and should be a no‑op at runtime as long as the updated neuron‑php/data dependency is installed.Please run the test suite after
composer updatewith the new dependencies to confirm there are no autoloading or wiring issues aroundSettingManager.tests/Cms/Repositories/DatabaseUserRepositoryTest.php (1)
8-8: Updated SettingManager import in tests looks goodUsing
Neuron\Data\Settings\SettingManagerin the mocks keeps the test suite aligned with the refactored Settings namespace; behavior remains unchanged because the class is mocked.After updating dependencies, please run this test class to ensure the new namespace resolves correctly under your autoloader.
src/Cms/Repositories/DatabasePostRepository.php (1)
10-10: Settings namespace import updated correctlyReferencing
Neuron\Data\Settings\SettingManagerhere keeps this repository in sync with the Settings refactor and ConnectionFactory usage; the constructor contract remains the same.After dependency updates, please run a small smoke test that instantiates
DatabasePostRepositoryvia your usual bootstrap path to confirm the new namespace resolves as expected.src/Cms/Email/helpers.php (1)
4-4: Email helpers now reference the new Settings namespaceUpdating the type to
Neuron\Data\Settings\ISettingSourcekeeps these helpers compatible with the refactored Settings package without changing their runtime behavior.Please ensure the updated Settings package is present in all environments where these helpers are used (including CLI contexts) and that any existing call sites still pass a compatible settings source.
resources/database/migrate/20251119224525_add_content_raw_to_posts.php (1)
13-22: Migration forcontent_rawis straightforward; verify adapter support for optionsAdding
content_rawas non‑nullable TEXT with a default empty Editor.js document is reasonable and should keep existing rows valid.The use of
'after' => 'body'and'comment' => 'Editor.js JSON content'is typically MySQL‑specific in Phinx; depending on how strictly you target SQLite/PostgreSQL as well, those options may be ignored or could need adapter‑specific handling.Please confirm that this migration runs cleanly against all database engines you support (especially in CI and local dev). If you see adapter‑specific issues, you may want to conditionally set
after/commentor drop them for non‑MySQL adapters.src/Cms/Events/EmailVerifiedEvent.php (1)
24-38: EmailVerifiedEvent implementation looks solidThe event cleanly encapsulates the verified
Uservia a readonly promoted property and exposes a clear, stable name ('email.verified') for subscribers. The design is consistent with the other event classes in this PR.src/Cms/Events/MaintenanceModeEnabledEvent.php (1)
24-40: MaintenanceModeEnabledEvent is consistent with the event modelReadonly constructor‑promoted properties for
enabledByandmessageplus a stable name'maintenance.enabled'match the existing disabled‑event pattern and give listeners all relevant context.src/Cms/Events/UserLoginEvent.php (1)
24-42: UserLoginEvent structure is consistent and ready for consumersThe event payload (User, IP, timestamp) and name
user.loginalign with the other event types you’ve added and give downstream listeners enough context without extra coupling. No issues spotted.src/Cms/Controllers/Content.php (2)
3-4: Version loading via factory is a clean upgradeSwitching to
Factories\Version::fromFile("../.version.json")while keeping the broad\Exceptioncatch preserves existing behavior and centralizes version deserialization in the data library. As long as the working directory is stable for web/CLI entry points, this looks good.Also applies to: 51-55, 85-94
201-213: Defaulting markdown page route toindeximproves resilienceUsing
$request->getRouteParameter('page') ?? 'index'avoids failures when the route omitspageand matches the typical “root markdown page” expectation. Just confirm your router/front-controller has anindex.md(or equivalent) to back this default.src/Cms/Repositories/DatabasePasswordResetTokenRepository.php (1)
5-8: Settings namespace refactor is consistentUsing
Neuron\Data\Settings\SettingManagerhere matches the broader Settings namespace migration and keeps the existing constructor contract intact. No repository behavior changes introduced.Also applies to: 23-32
tests/Cms/Services/PasswordResetterTest.php (1)
11-13: Test settings imports now align with production namespacesUpdating to
Settings\Source\MemoryandSettings\SettingManagerkeeps the test configuration in sync with the data layer refactor. The in-memory setup logic remains the same and should continue to exercise PasswordResetter as before.Also applies to: 34-42
tests/Cms/Services/EmailVerifierTest.php (1)
10-12: EmailVerifier tests correctly track the Settings namespace changeThe move to
Neuron\Data\Settings\Source\MemoryandSettings\SettingManagermirrors the production code and leaves the test behavior intact (test-mode email, same keys). Looks good.Also applies to: 31-39
resources/app/Initializers/RegistrationInitializer.php (1)
31-38: Registration initializer now guards against the correct Settings manager typeSwitching the instanceof check to
\Neuron\Data\Settings\SettingManagermatches the new Settings namespace and preserves the early-exit behavior when configuration isn’t wired. No additional issues here.src/Cms/Services/Auth/EmailVerifier.php (1)
10-11: I'll help you verify the review comment about email verification event emission safety. Let me start by exploring the codebase to understand how the Event::emit() method handles missing emitters and listener failures.
<function_calls>
#!/bin/bashFind the Event class definition
rg -n "class Event" --type=php
Find emit method definitions
rg -n "function emit|public function emit" --type=php -A 5
</function_calls>src/Cms/Services/Post/Creator.php (1)
35-40: Confirmed: API change is complete and well-implemented internally, but lacks external documentationThe migration is thorough within the repository:
- Post model correctly implements
setContent()with EditorJS JSON, auto-extracting plain text to_bodyfor backward compatibility- Creator service properly uses
setContent()- Admin form is fully updated with Editor.js frontend that serializes to EditorJS JSON
- Database schema includes
content_rawcolumn for JSON storage- Tests pass EditorJS JSON correctly
However, this package is publicly distributed via Composer (
"neuron-php/cms"library type), making Creator::create() a public API. The breaking change—requiring EditorJS JSON instead of rendered body strings—lacks a migration guide or changelog. No backward compatibility wrapper exists.tests/Cms/Services/RegistrationServiceTest.php (1)
10-11: LGTM! Namespace migration applied correctly.The import paths have been updated to use the new
Neuron\Data\Settingsnamespace, aligning with the project-wide refactoring.resources/app/Initializers/PasswordResetInitializer.php (1)
9-9: LGTM! Namespace migration applied correctly.The import path has been updated to use the new
Neuron\Data\Settings\SettingManagernamespace.src/Cms/Cli/Commands/Install/InstallCommand.php (1)
9-10: LGTM! Namespace migration applied correctly.The import paths have been updated to use the new
Neuron\Data\Settingsnamespace.tests/Cms/Services/AuthenticationTest.php (1)
11-11: LGTM! Namespace migration applied correctly.The import path has been updated to use the new
Neuron\Data\Settings\SettingManagernamespace.tests/Cms/BlogControllerTest.php (1)
13-14: LGTM! Namespace migration applied correctly.The import paths have been updated to use the new
Neuron\Data\Settingsnamespace.resources/app/Initializers/AuthInitializer.php (1)
32-32: LGTM! Type check updated for namespace migration.The instanceof check has been updated to reference the new
Neuron\Data\Settings\SettingManagernamespace.resources/views/blog/show.php (2)
51-160: LGTM! Comprehensive styling for EditorJS content.The CSS additions provide proper styling for post content and EditorJS widgets, including headings, lists, blockquotes, code blocks, images, and custom widgets.
39-39: I'll help you verify the concerns raised in the review comment. Let me search the codebase for the Blog controller and examine how$renderedContentis set.
<function_calls>
#!/bin/bashFind the Blog controller
fd -t f -i "blog" --type=php | head -20
</function_calls>Let me search more specifically for the Blog controller:
<function_calls>
#!/bin/bashSearch for Blog controller class definition
rg -n "class Blog" --type=php -A 5
</function_calls>Now let me search for where the show view is rendered:
<function_calls>
#!/bin/bashSearch for show view rendering and renderedContent variable
rg -n "renderedContent|show.php|blog/show" --type=php -B 3 -A 3
</function_calls>Let me also check the structure of the resources/views/blog directory:
<function_calls>
#!/bin/bashList files in blog views directory
fd -t f "show.php" && echo "---" && fd -t f "blog" resources/views/ 2>/dev/null | head -10
</function_calls>Let me check the full repository structure to understand the layout:
<function_calls>
#!/bin/bashGet an overview of the repository structure
git ls-files | grep -E "(controller|blog)" | head -20
</function_calls>src/Cms/Services/Auth/PasswordResetter.php (1)
10-10: LGTM! Namespace migration applied correctly.The import path has been updated to use the new
Neuron\Data\Settings\SettingManagernamespace.resources/app/Initializers/MaintenanceInitializer.php (1)
45-59: Updated Settings manager namespace check looks correctSwitching the instanceof check to
\Neuron\Data\Settings\SettingManageraligns this initializer with the new Settings namespace without changing runtime behavior. No further changes needed here.src/Cms/Events/PasswordResetCompletedEvent.php (1)
24-40: PasswordResetCompletedEvent structure and naming are consistentReadonly payload (User + IP) and the
password.reset_completedname match the existing event style in this module. Good to go.src/Cms/Events/PasswordResetRequestedEvent.php (1)
24-40: PasswordResetRequestedEvent aligns with the existing event modelReadonly User + IP payload and the
password.reset_requestedname follow the same pattern as your other events. Looks good as a foundation for security monitoring and auditing.src/Cms/Events/UserLogoutEvent.php (1)
1-41: LGTM!The event class is well-structured with clear documentation, follows the established event pattern, and properly uses constructor property promotion. The inclusion of
sessionDurationis a valuable addition for analytics.src/Cms/Controllers/Blog.php (1)
40-44: LGTM! Well-structured dependency initialization.The renderer initialization properly chains dependencies (WidgetRenderer → ShortcodeParser → EditorJsRenderer), creating a clean content processing pipeline.
src/Cms/Events/UserLoginFailedEvent.php (1)
1-44: LGTM!The event class is well-designed for security monitoring and audit trails. The inclusion of
reason,ip, andtimestampprovides comprehensive context for failed login attempts, which is essential for security analysis and compliance.src/Cms/Events/MaintenanceModeDisabledEvent.php (1)
8-39: LGTM! Event structure is appropriate.The event class is well-documented and follows the established pattern. Using a string for
$disabledBy(username/identifier) is consistent with the EnabledEvent and provides flexibility.src/Cms/Services/Post/Updater.php (1)
39-62: LGTM! Clean migration to EditorJS content handling.The parameter rename from
$bodyto$contentand the corresponding method call change fromsetBody()tosetContent()properly reflect the shift to EditorJS JSON format. The updated docblock clearly documents this change.src/Cms/Models/Post.php (3)
156-169: LGTM! Good error handling for JSON encoding.The
setContentArray()method properly handles JSON encoding failures with an explicit exception, which is better than silent failures. The use of\JsonExceptionis appropriate.
501-523: Well-designed content handling in fromArray().The method properly handles both
content_rawandcontentkeys, and supports both string and array formats for each. This provides good flexibility for different data sources while maintaining backward compatibility.
625-635: Use match expression correctly handles EditorJS block types.The match expression properly extracts text from various EditorJS block types. The handling of list items with
implode()and the fallback to empty string for unknown types is appropriate.resources/views/admin/posts/create.php (1)
104-108: The image upload endpoint handler for/admin/upload/imageis not implemented in the codebase.While the codebase has a robust CSRF protection system in place (CsrfFilter and CsrfToken service), the actual route handler for the
/admin/upload/imageendpoint referenced in the frontend editor configuration (create.php and edit.php) could not be located. The endpoint is configured in the views but no corresponding PHP route handler exists insrc/Cms/Controllers/or elsewhere.Recommendation: Implement the
/admin/upload/imageroute handler and ensure it is protected with the CsrfFilter to validate CSRF tokens before processing uploads.
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/image@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@latest"></script> | ||
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/raw@latest"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pin CDN script versions instead of using @latest.
Using @latest for CDN dependencies can lead to breaking changes being introduced automatically when new versions are released, potentially causing production issues without warning.
Replace the @latest tags with specific version numbers:
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/image@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@latest"></script>
-<script src="https://cdn.jsdelivr.net/npm/@editorjs/raw@latest"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2.28.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/header@2.7.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/list@1.8.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/image@2.8.1"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@2.5.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/code@2.8.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@1.3.0"></script>
+<script src="https://cdn.jsdelivr.net/npm/@editorjs/raw@2.4.0"></script>📝 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.
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/header@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/list@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/image@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/code@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/raw@latest"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2.28.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/header@2.7.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/list@1.8.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/image@2.8.1"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/quote@2.5.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/code@2.8.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/delimiter@1.3.0"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/@editorjs/raw@2.4.0"></script> |
🤖 Prompt for AI Agents
In resources/views/admin/posts/create.php around lines 75 to 82, the CDN script
tags use @latest which risks unplanned breaking changes; replace each @latest
with a specific, tested semantic version (e.g., exact x.y.z values) for
Editor.js and its plugins, update any README or asset notes to record chosen
versions, and consider adding subresource integrity or locking via a package
manager/build tool so future updates are explicit and audited.
|
|
||
| namespace Neuron\Cms\Events; | ||
|
|
||
| use Neuron\Cms\Models\User; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused import.
The User class is imported but not used in this event class. The $disabledBy property is a string, not a User object.
-use Neuron\Cms\Models\User;
use Neuron\Events\IEvent;📝 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.
| use Neuron\Cms\Models\User; | |
| use Neuron\Events\IEvent; |
🤖 Prompt for AI Agents
In src/Cms/Events/MaintenanceModeDisabledEvent.php around line 5, the file
imports Neuron\Cms\Models\User but never uses it (the $disabledBy property is a
string). Remove the unused import line and confirm there are no remaining
references to the User class in this file.
Upgrades the blog editor to be a block based editor.
A ton of refactoring.
Summary by CodeRabbit
New Features
Style
Chores
✏️ Tip: You can customize this high-level summary in your review settings.