diff --git a/resources/views/admin/events/index.php b/resources/views/admin/events/index.php index d4ad667..0cde247 100644 --- a/resources/views/admin/events/index.php +++ b/resources/views/admin/events/index.php @@ -4,16 +4,16 @@ Create New Event - + - + diff --git a/resources/views/auth/login/login.php b/resources/views/auth/login/login.php index add6fd9..c67aeeb 100644 --- a/resources/views/auth/login/login.php +++ b/resources/views/auth/login/login.php @@ -3,13 +3,13 @@
- + diff --git a/src/Cms/Controllers/Admin/EventCategories.php b/src/Cms/Controllers/Admin/EventCategories.php index 78507f5..d7086d2 100644 --- a/src/Cms/Controllers/Admin/EventCategories.php +++ b/src/Cms/Controllers/Admin/EventCategories.php @@ -72,8 +72,8 @@ public function index( Request $request ): string ->withCsrfToken() ->with([ 'categories' => $this->_repository->all(), - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Events.php b/src/Cms/Controllers/Admin/Events.php index 5fdb93d..e6234c8 100644 --- a/src/Cms/Controllers/Admin/Events.php +++ b/src/Cms/Controllers/Admin/Events.php @@ -88,8 +88,8 @@ public function index( Request $request ): string ->withCsrfToken() ->with([ 'events' => $events, - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Media.php b/src/Cms/Controllers/Admin/Media.php index c1f241c..b708d9d 100644 --- a/src/Cms/Controllers/Admin/Media.php +++ b/src/Cms/Controllers/Admin/Media.php @@ -114,8 +114,8 @@ public function index( Request $request ): string 'resources' => $result['resources'], 'nextCursor' => $result['next_cursor'], 'totalCount' => $result['total_count'], - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } @@ -135,8 +135,8 @@ public function index( Request $request ): string 'resources' => [], 'nextCursor' => null, 'totalCount' => 0, - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => 'Failed to load media library. Please try again.' + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => 'Failed to load media library. Please try again.' ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Pages.php b/src/Cms/Controllers/Admin/Pages.php index fb08a76..16b2f2a 100644 --- a/src/Cms/Controllers/Admin/Pages.php +++ b/src/Cms/Controllers/Admin/Pages.php @@ -88,8 +88,8 @@ public function index( Request $request ): string ->withCsrfToken() ->with([ 'pages' => $pages, - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Posts.php b/src/Cms/Controllers/Admin/Posts.php index c5c44cf..c3256c0 100644 --- a/src/Cms/Controllers/Admin/Posts.php +++ b/src/Cms/Controllers/Admin/Posts.php @@ -102,8 +102,8 @@ public function index( Request $request ): string ->withCsrfToken() ->with([ 'posts' => $posts, - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Profile.php b/src/Cms/Controllers/Admin/Profile.php index 65c8a54..8205717 100644 --- a/src/Cms/Controllers/Admin/Profile.php +++ b/src/Cms/Controllers/Admin/Profile.php @@ -82,8 +82,8 @@ public function edit( Request $request ): string ->withCsrfToken() ->with([ 'groupedTimezones' => $groupedTimezones, - FlashMessageType::SUCCESS->value => $this->getSessionManager()->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $this->getSessionManager()->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $this->getSessionManager()->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $this->getSessionManager()->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'edit', 'admin' ); } diff --git a/src/Cms/Controllers/Admin/Users.php b/src/Cms/Controllers/Admin/Users.php index bed5ac7..74b01d5 100644 --- a/src/Cms/Controllers/Admin/Users.php +++ b/src/Cms/Controllers/Admin/Users.php @@ -79,8 +79,8 @@ public function index( Request $request ): string ->withCsrfToken() ->with([ 'users' => $this->_repository->all(), - FlashMessageType::SUCCESS->value => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), - FlashMessageType::ERROR->value => $sessionManager->getFlash( FlashMessageType::ERROR->value ) + FlashMessageType::SUCCESS->viewKey() => $sessionManager->getFlash( FlashMessageType::SUCCESS->value ), + FlashMessageType::ERROR->viewKey() => $sessionManager->getFlash( FlashMessageType::ERROR->value ) ]) ->render( 'index', 'admin' ); } diff --git a/src/Cms/Controllers/Auth/Login.php b/src/Cms/Controllers/Auth/Login.php index 949e931..97dc4e8 100644 --- a/src/Cms/Controllers/Auth/Login.php +++ b/src/Cms/Controllers/Auth/Login.php @@ -75,8 +75,8 @@ public function showLoginForm( Request $request ): string ->title( 'Login' ) ->description( 'Login to ' . $this->getName() ) ->withCsrfToken() - ->with( FlashMessageType::ERROR->value, $this->getSessionManager()->getFlash( 'error' ) ) - ->with( FlashMessageType::SUCCESS->value, $this->getSessionManager()->getFlash( 'success' ) ) + ->with( FlashMessageType::ERROR->viewKey(), $this->getSessionManager()->getFlash( FlashMessageType::ERROR->value ) ) + ->with( FlashMessageType::SUCCESS->viewKey(), $this->getSessionManager()->getFlash( FlashMessageType::SUCCESS->value ) ) ->with( 'RedirectUrl', $redirectUrl ) ->render( 'login', 'auth' ); } diff --git a/src/Cms/Enums/FlashMessageType.php b/src/Cms/Enums/FlashMessageType.php index 0107512..a9aa169 100644 --- a/src/Cms/Enums/FlashMessageType.php +++ b/src/Cms/Enums/FlashMessageType.php @@ -5,6 +5,8 @@ /** * Flash message types used throughout the CMS * + * Provides consistent keys for both session storage and view variables. + * * @package Neuron\Cms\Enums */ enum FlashMessageType: string @@ -13,4 +15,17 @@ enum FlashMessageType: string case ERROR = 'error'; case WARNING = 'warning'; case INFO = 'info'; + + /** + * Get the view variable name for this flash message type + * + * Views expect capitalized variable names (e.g., $Success, $Error) + * while session storage uses lowercase keys (e.g., 'success', 'error') + * + * @return string The capitalized view variable name + */ + public function viewKey(): string + { + return ucfirst( $this->value ); + } } diff --git a/src/Cms/Services/Auth/Authentication.php b/src/Cms/Services/Auth/Authentication.php index cb72eb1..87a911f 100644 --- a/src/Cms/Services/Auth/Authentication.php +++ b/src/Cms/Services/Auth/Authentication.php @@ -38,10 +38,24 @@ public function __construct( /** * Attempt to authenticate a user + * + * Accepts either username or email address for login. + * Automatically detects if the input is an email and searches accordingly. */ public function attempt( string $username, string $password, bool $remember = false ): bool { - $user = $this->_userRepository->findByUsername( $username ); + // Detect if input is an email address + $isEmail = filter_var( $username, FILTER_VALIDATE_EMAIL ); + + // Try to find user by email or username + if( $isEmail ) + { + $user = $this->_userRepository->findByEmail( $username ); + } + else + { + $user = $this->_userRepository->findByUsername( $username ); + } if( !$user ) { diff --git a/tests/Unit/Cms/Enums/FlashMessageTypeTest.php b/tests/Unit/Cms/Enums/FlashMessageTypeTest.php new file mode 100644 index 0000000..a31e934 --- /dev/null +++ b/tests/Unit/Cms/Enums/FlashMessageTypeTest.php @@ -0,0 +1,59 @@ +assertEquals( 'Success', FlashMessageType::SUCCESS->viewKey() ); + $this->assertEquals( 'Error', FlashMessageType::ERROR->viewKey() ); + $this->assertEquals( 'Warning', FlashMessageType::WARNING->viewKey() ); + $this->assertEquals( 'Info', FlashMessageType::INFO->viewKey() ); + } + + /** + * Test that enum values remain lowercase for session storage + * + * The value property should remain lowercase for consistency + * with session flash key storage. + */ + public function testEnumValuesAreLowercase(): void + { + $this->assertEquals( 'success', FlashMessageType::SUCCESS->value ); + $this->assertEquals( 'error', FlashMessageType::ERROR->value ); + $this->assertEquals( 'warning', FlashMessageType::WARNING->value ); + $this->assertEquals( 'info', FlashMessageType::INFO->value ); + } + + /** + * Test that all enum cases exist + * + * Ensures all expected flash message types are defined. + */ + public function testAllCasesExist(): void + { + $cases = FlashMessageType::cases(); + $this->assertCount( 4, $cases ); + + $values = array_map( fn( $case ) => $case->value, $cases ); + $this->assertContains( 'success', $values ); + $this->assertContains( 'error', $values ); + $this->assertContains( 'warning', $values ); + $this->assertContains( 'info', $values ); + } +} diff --git a/tests/Unit/Cms/Services/AuthenticationTest.php b/tests/Unit/Cms/Services/AuthenticationTest.php index 81383ef..f6c9977 100644 --- a/tests/Unit/Cms/Services/AuthenticationTest.php +++ b/tests/Unit/Cms/Services/AuthenticationTest.php @@ -608,4 +608,58 @@ public function testValidateCredentialsWithInvalidPassword(): void $this->assertFalse($result); } + + /** + * Test attempt() with email address instead of username + */ + public function testAttemptWithEmailAddress(): void + { + $user = $this->createTestUser('emailuser', 'TestPass123'); + + // Attempt login using email instead of username + $result = $this->_authentication->attempt($user->getEmail(), 'TestPass123'); + + $this->assertTrue($result); + $this->assertTrue($this->_authentication->check()); + $this->assertEquals('emailuser', $this->_authentication->user()->getUsername()); + } + + /** + * Test attempt() with username still works + */ + public function testAttemptWithUsernameStillWorks(): void + { + $this->createTestUser('usernametest', 'TestPass123'); + + // Attempt login using username (traditional method) + $result = $this->_authentication->attempt('usernametest', 'TestPass123'); + + $this->assertTrue($result); + $this->assertTrue($this->_authentication->check()); + $this->assertEquals('usernametest', $this->_authentication->user()->getUsername()); + } + + /** + * Test attempt() with nonexistent email returns false + */ + public function testAttemptWithNonexistentEmail(): void + { + $result = $this->_authentication->attempt('nobody@example.com', 'TestPass123'); + + $this->assertFalse($result); + $this->assertFalse($this->_authentication->check()); + } + + /** + * Test attempt() with incorrect password using email + */ + public function testAttemptWithEmailAndIncorrectPassword(): void + { + $user = $this->createTestUser('emailpasstest', 'TestPass123'); + + $result = $this->_authentication->attempt($user->getEmail(), 'WrongPassword'); + + $this->assertFalse($result); + $this->assertFalse($this->_authentication->check()); + } }