Repository navigation
Feature/member portal and refactoring. #18
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
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4ab33ad
renames config.yaml to neuron.yaml. Updates homepage.
ljonesfl 88fd7d9
more refactoring. adds memmber portal.
ljonesfl dbe46f2
Update resources/app/Initializers/RegistrationInitializer.php
ljonesfl 2b46c1a
Update resources/database/migrate/20250112000000_create_email_verific…
ljonesfl 391055e
Update src/Cms/Auth/EmailVerificationManager.php
ljonesfl a0967f1
adds resend verification token throttling
ljonesfl e28fa69
Merge branch 'feature/member-portal' of github.com:Neuron-PHP/cms int…
ljonesfl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| system: | ||
| timezone: US/Eastern | ||
| base_path: examples | ||
| routes_path: examples/config | ||
|
|
||
| logging: | ||
| destination: \Neuron\Log\Destination\File | ||
| format: \Neuron\Log\Format\PlainText | ||
| file: test.log | ||
| level: debug | ||
|
|
||
| cache: | ||
| enabled: true | ||
| storage: file | ||
| path: cache/views | ||
| ttl: 3600 | ||
| html: true | ||
| markdown: true | ||
| json: false | ||
| xml: false | ||
| # Garbage collection settings (optional, defaults shown) | ||
| # gc_probability: 0.01 # 1% chance to run GC on cache write | ||
| # gc_divisor: 100 # Used with probability for fine-tuning | ||
|
|
||
| views: | ||
| path: views | ||
|
|
||
| site: | ||
| name: 'Neuron' | ||
| url: 'https://neuron.example.com' | ||
| description: 'A modern blogging platform built with Neuron.' | ||
|
|
||
| blog: | ||
| path: 'blog' | ||
| title: 'Neuron Blog' | ||
|
|
||
| # Member Registration and Management Configuration | ||
| member: | ||
| # Enable or disable user registration | ||
| # Set to false to prevent new users from signing up | ||
| registration_enabled: true | ||
|
|
||
| # Default role assigned to new users | ||
| # Options: admin, editor, author, subscriber | ||
| default_role: subscriber | ||
|
|
||
| # Require email verification before users can log in | ||
| # When true, users must verify their email before accessing member areas | ||
| require_email_verification: true | ||
|
|
||
| # Email verification URL path | ||
| # This is appended to the site URL to create the verification link | ||
| verification_url: /verify-email | ||
|
|
||
| # Email verification token expiration time (in minutes) | ||
| # Tokens older than this will be considered invalid | ||
| verification_token_expiration_minutes: 60 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| <?php | ||
|
|
||
| namespace App\Initializers; | ||
|
|
||
| use Neuron\Cms\Auth\EmailVerificationManager; | ||
| use Neuron\Cms\Auth\Filters\MemberAuthenticationFilter; | ||
| use Neuron\Cms\Auth\AuthManager; | ||
| use Neuron\Cms\Auth\PasswordHasher; | ||
| use Neuron\Cms\Repositories\DatabaseEmailVerificationTokenRepository; | ||
| use Neuron\Cms\Repositories\DatabaseUserRepository; | ||
| use Neuron\Cms\Services\Member\RegistrationService; | ||
| use Neuron\Log\Log; | ||
| use Neuron\Patterns\Registry; | ||
| use Neuron\Patterns\IRunnable; | ||
|
|
||
| /** | ||
| * Initialize the member registration system | ||
| * | ||
| * Registers the registration services and member authentication filter | ||
| */ | ||
| class RegistrationInitializer implements IRunnable | ||
| { | ||
| /** | ||
| * Run the initializer | ||
| * @param array $argv | ||
| * @return mixed | ||
| * @throws \Exception | ||
| */ | ||
| public function run( array $argv = [] ): mixed | ||
| { | ||
| // Get Settings from Registry | ||
| $settings = Registry::getInstance()->get( 'Settings' ); | ||
|
|
||
| if( !$settings || !$settings instanceof \Neuron\Data\Setting\SettingManager ) | ||
| { | ||
| Log::error( "Settings not found in Registry, skipping registration initialization" ); | ||
| return null; | ||
| } | ||
|
|
||
| // Get Application from Registry | ||
| $app = Registry::getInstance()->get( 'App' ); | ||
|
|
||
| if( !$app || !$app instanceof \Neuron\Mvc\Application ) | ||
| { | ||
| Log::error( "Application not found in Registry, skipping registration initialization" ); | ||
| return null; | ||
| } | ||
|
|
||
| // Get AuthManager from Registry (must be initialized first by AuthInitializer) | ||
| $authManager = Registry::getInstance()->get( 'AuthManager' ); | ||
|
|
||
| if( !$authManager ) | ||
| { | ||
| Log::error( "AuthManager not found in Registry, skipping registration initialization" ); | ||
| return null; | ||
| } | ||
|
|
||
| // Check if database is configured | ||
| try | ||
| { | ||
| $settingNames = $settings->getSectionSettingNames( 'database' ); | ||
|
|
||
| if( !empty( $settingNames ) ) | ||
| { | ||
| // Initialize registration components | ||
| $userRepository = new DatabaseUserRepository( $settings ); | ||
| $tokenRepository = new DatabaseEmailVerificationTokenRepository( $settings ); | ||
| $passwordHasher = new PasswordHasher(); | ||
|
|
||
| // Get base path for email templates | ||
| $basePath = $settings->get( 'system', 'base_path' ) ?? getcwd(); | ||
|
|
||
| // Get verification URL from settings | ||
| $siteUrl = $settings->get( 'site', 'url' ) ?? 'http://localhost:8000'; | ||
| $verificationPath = $settings->get( 'member', 'verification_url' ) ?? '/verify-email'; | ||
| $verificationUrl = rtrim( $siteUrl, '/' ) . '/' . ltrim( $verificationPath, '/' ); | ||
|
|
||
| // Create EmailVerificationManager | ||
| $verificationManager = new EmailVerificationManager( | ||
| $tokenRepository, | ||
| $userRepository, | ||
| $settings, | ||
| $basePath, | ||
| $verificationUrl | ||
| ); | ||
|
|
||
| // Set token expiration from settings | ||
| $tokenExpiration = $settings->get( 'member', 'verification_token_expiration_minutes' ) ?? 60; | ||
| $verificationManager->setTokenExpirationMinutes( $tokenExpiration ); | ||
|
|
||
| // Get event emitter if available | ||
| $emitter = Registry::getInstance()->get( 'EventEmitter' ); | ||
|
|
||
| // Create RegistrationService | ||
| $registrationService = new RegistrationService( | ||
| $userRepository, | ||
| $passwordHasher, | ||
| $verificationManager, | ||
| $settings, | ||
| $emitter | ||
| ); | ||
|
|
||
| // Create member authentication filter | ||
| $requireVerification = $settings->get( 'member', 'require_email_verification' ) ?? true; | ||
| $memberFilter = new MemberAuthenticationFilter( | ||
| $authManager, | ||
| '/login', | ||
| $requireVerification | ||
| ); | ||
|
|
||
| // Register the member filter with the Router | ||
| $app->getRouter()->registerFilter( 'member', $memberFilter ); | ||
|
|
||
| // Store services in Registry for easy access | ||
| Registry::getInstance()->set( 'EmailVerificationManager', $verificationManager ); | ||
| Registry::getInstance()->set( 'RegistrationService', $registrationService ); | ||
|
|
||
| Log::info( "Registration system initialized successfully" ); | ||
| } | ||
| } | ||
| catch( \Exception $e ) | ||
| { | ||
| Log::error( "Failed to initialize registration system: " . $e->getMessage() ); | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| <?php | ||
|
|
||
| namespace App\Initializers; | ||
|
|
||
| use Neuron\Mvc\Views\ViewDataProvider; | ||
| use Neuron\Patterns\IRunnable; | ||
| use Neuron\Patterns\Registry; | ||
|
|
||
| /** | ||
| * Initialize global view data that should be available in all views. | ||
| * | ||
| * This initializer demonstrates how to use ViewDataProvider to inject | ||
| * commonly-needed data into all views without requiring controllers to | ||
| * manually pass it or views to access the Registry directly. | ||
| * | ||
| * The ViewDataProvider eliminates the need for views to directly access | ||
| * Registry::getInstance(), making views cleaner and more testable. | ||
| * | ||
| * Usage: | ||
| * - Static values are shared once and reused | ||
| * - Callables are executed on each request (lazy evaluation) | ||
| * - All shared data is automatically injected into view templates | ||
| * | ||
| * @package App\Initializers | ||
| */ | ||
| class ViewDataInitializer implements IRunnable | ||
| { | ||
| /** | ||
| * Run the initializer | ||
| * | ||
| * Register global view data that should be available in all views. | ||
| * Customize this method to share your application's global data. | ||
| * | ||
| * @param array $argv | ||
| * @return mixed | ||
| */ | ||
| public function run( array $argv = [] ): mixed | ||
| { | ||
| $registry = Registry::getInstance(); | ||
| $provider = ViewDataProvider::getInstance(); | ||
|
|
||
| // Site name - pulled from Registry 'name' key | ||
| $provider->share( 'siteName', function() use ( $registry ) { | ||
| return $registry->get( 'name' ) ?? 'Neuron CMS'; | ||
| }); | ||
|
|
||
| // Application version | ||
| $provider->share( 'appVersion', function() use ( $registry ) { | ||
| return $registry->get( 'version' ) ?? ''; | ||
| }); | ||
|
|
||
| // Current authenticated user | ||
| $provider->share( 'currentUser', function() use ( $registry ) { | ||
| return $registry->get( 'Auth.User' ); | ||
| }); | ||
|
|
||
| // Theme from settings with sensible defaults per context | ||
| $provider->share( 'theme', function() use ( $registry ) { | ||
| $settings = $registry->get( 'Settings' ); | ||
| return $settings?->get( 'theme', 'default' ) ?? 'sandstone'; | ||
| }); | ||
|
|
||
| // Current year (useful for copyright notices) | ||
| $provider->share( 'currentYear', fn() => date( 'Y' ) ); | ||
|
|
||
| // Check if user is authenticated (convenience helper) | ||
| $provider->share( 'isAuthenticated', function() use ( $registry ) { | ||
| $authManager = $registry->get( 'AuthManager' ); | ||
| return $authManager && $authManager->isAuthenticated(); | ||
| }); | ||
|
|
||
| return null; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.