Conversation
This commit introduces a comprehensive authentication refactoring: - Created User entity with optional email and defaultName fields - User entity now handles authentication (replaces Player as UserInterface) - Added support for Google and Apple OAuth authentication - Players are now linked to Users and Rooms - A User can have multiple Player instances across different room lobbies Changes include: * New User entity with GoogleId and AppleId for OAuth integration * Player entity refactored to link to User via ManyToOne relationship * Removed UserInterface implementation from Player entity * Updated security configuration to use User entity for authentication * Installed knpuniversity/oauth2-client-bundle with Google and Apple providers * Created OAuthController with Google and Apple authentication endpoints * Updated PlayerController to create User when creating Player * Added database migration for User table and Player.user_id foreign key * Added OAuth environment variables to .env file OAuth endpoints: - GET /oauth/google - Initiate Google OAuth flow - GET /oauth/google/check - Handle Google OAuth callback - GET /oauth/apple - Initiate Apple OAuth flow - GET /oauth/apple/check - Handle Apple OAuth callback
83cd4d1 to
5e18543
Compare
- Add room property to User entity for tracking current room context - Add getCurrentUserPlayer method to PlayerRepository - Update all Voters (PlayerVoter, MissionVoter, RoomVoter) to use getCurrentUserPlayer - Create database migration to add room_id to users table The room property on User tracks which room context the user is currently operating in. This allows for proper authorization checks in Voters by getting the current player based on the user's room context. Changes: - User entity: Added nullable room property with SET NULL on delete - PlayerRepository: Added getCurrentUserPlayer(User) method - DoctrinePlayerRepository: Implemented getCurrentUserPlayer logic - PlayerVoter: Use getCurrentUserPlayer for authorization - MissionVoter: Use getCurrentUserPlayer for authorization - RoomVoter: Use getCurrentUserPlayer for authorization - Migration: Add room_id column to users table with foreign key to room
The /me endpoint now returns the current player based on the user's room context using the getCurrentUserPlayer method. This provides the player associated with the user in their current room. Changes: - /me endpoint uses getCurrentUserPlayer to get the current player - Returns PLAYER_NOT_FOUND_IN_CURRENT_ROOM error if no player found - Maintains same serialization groups and Mercure cookie setup
Players can no longer change their room directly. Instead, users can change their room context through a new UserController endpoint, which will affect which player is returned as the current player. Changes: - User entity: Added avatar property with default value 'captain' - User entity: Added 'patch-user' serialization group to defaultName and avatar - UserController: Created new controller with PATCH /user/me endpoint - Allows updating defaultName, avatar, and room - Room changes affect which player is current via getCurrentUserPlayer - PlayerController: Prevent room changes on players - Throw PLAYER_CANNOT_CHANGE_ROOM error if room change attempted - Removed room change logic and ChangeRoomUseCase call - Removed previousRoom tracking code - Added null check for room in Mercure publish - Migration: Add avatar column to users table This architectural change separates room context (User) from room membership (Player). Users change their active room context, which determines which of their players becomes the current player for authorization and API responses.
The /me endpoint now returns comprehensive user information including: - All user properties (id, email, defaultName, avatar, room) - List of all players belonging to the user - currentPlayer property (only if user has a player in current room context) Changes: - PlayerController: Removed GET /me endpoint - UserController: Added GET /me endpoint - Returns user info with 'me' serialization group - Includes players list - Conditionally adds currentPlayer using getCurrentUserPlayer - Sets Mercure cookie for SSE subscriptions - User entity: Added 'me' group to players property for serialization This provides a single endpoint to get all user context including which player is currently active based on the user's room context.
Changes to User entity: - Renamed defaultName property to name - Updated getter/setter: getName() and setName() - Updated validation messages: NAME_TOO_SHORT, NAME_TOO_LONG Updated all references: - OAuthController: Updated Google and Apple OAuth callbacks to use name - PlayerController: Updated player creation to use setName() Functional tests: - Updated all tests to wrap player assertions in 'currentPlayer' key for /user/me endpoint - 45 test assertions updated across RoomControllerCest, GuessKillerCest, and KillContestCest Migration consolidation: - Consolidated all session migrations into single Version20251108113552.php - Removed Version20251108171358.php (room context) - Removed Version20251108172842.php (avatar) - Updated migration to use 'name' instead of 'default_name' - Single migration now creates users table with all properties: - name, email, roles, google_id, apple_id, room_id, avatar - Links player to user and removes roles from player table This provides a cleaner migration history with a single migration for the entire User entity feature including OAuth, room context, and authorization model.
PlayerController: - createPlayer: Check if user already exists with getUser() before creating new one - Prevents creating duplicate users when user is already authenticated (OAuth flow) MissionController: - Added PlayerRepository dependency - createMission: Use getUser() to get User, then getCurrentUserPlayer() to get player - deleteMission: Use getCurrentUserPlayer() for Mercure publish - Added null safety checks for user and player RoomController: - Added PlayerRepository dependency - createRoom: Use getUser() to get User, then getCurrentUserPlayer() to get player - Added null safety checks for user and player All controllers now properly handle the User-Player separation where: - Authentication returns a User (not Player) - getCurrentUserPlayer() determines the active player based on user's room context - Voters already use this pattern for authorization
When a user updates their room through the UserController.patchUser endpoint, automatically create a new Player instance for that user in the target room if one doesn't already exist. The new player is initialized with the user's name and avatar properties.
The Room entity uses a string type (VARCHAR(5)) for its id, so the users table's room_id foreign key must match this type.
Replace the removed roles system with explicit boolean flags: - Added Player.isAdmin property for room administrators - Added Player.isMaster property for game masters - Updated migration to include is_admin and is_master columns - Updated RoomController.createRoom() to use setIsAdmin() and setIsMaster() instead of non-existent setRoles() method The player creating a room is automatically set as admin, and if the room is game mastered, the player is also set as master with SPECTATING status.
Replace all setRoles() calls with setIsAdmin() and setIsMaster(): - RoomChangeAdminUseCase: Use setIsAdmin(true) for new admin - ResetPlayerUseCase: Reset isAdmin and isMaster to false - Update RoomChangeAdminTest to expect setIsAdmin() call This fixes the unit test failure where setRoles() method no longer exists on Player entity since roles were moved to User entity.
- Created CreatePlayerUseCase to centralize player creation logic - Updated UserController to use CreatePlayerUseCase when joining rooms - Updated RoomControllerCest to use PATCH /user instead of PATCH /player - Updated GuessKillerCest to use PATCH /user instead of PATCH /player - When player IDs are needed, they are now grabbed after joining the room with room filter to ensure we get the correct player instance This aligns with the new architecture where: - Users authenticate (not players) - PATCH /user with room ID creates a new player for that room - Each user can have multiple players across different rooms
- Updated KillContestCest to use PATCH /user for joining rooms - Updated PlayerControllerCest to use PATCH /user for joining/leaving rooms - Updated SecondaryMissionsAndSwitchingCest to use PATCH /user for joining rooms - When player IDs are needed after joining, they are now grabbed with room filter All functional tests now use the new architecture where: - Users PATCH /user with room ID to join a room - This automatically creates a new player for that user in that room - Players can be in multiple rooms (one player instance per room per user)
- Updated CreatePlayerUseCase to not flush automatically (caller controls flushing) - Added CreatePlayerUseCase dependency to RoomController - Refactored RoomController.createRoom() to use CreatePlayerUseCase - Removed redundant player storage (CreatePlayerUseCase already stores the player) This centralizes player creation logic and ensures consistency across the application. The use case no longer flushes automatically, giving callers better transaction control.
Updated all Cest files to access player properties through the 'currentPlayer' key in the response from /user/me endpoint: - GuessKillerCest: Fixed 3 instances where response properties were accessed directly instead of through currentPlayer (target, id) - KillContestCest: Fixed 2 instances (target.id, target.name) - RoomControllerCest: Fixed 2 instances (target.id) Before: $response['target']['id'] After: $response['currentPlayer']['target']['id'] This aligns with the new /user/me response structure where player data is nested under the 'currentPlayer' key.
Major architectural change to make authentication user-based instead of player-based: 1. **User Entity Changes**: - Added token and refreshToken properties (non-persisted) - Added serialization groups for POST /user (post-user, create-user) - Token/refreshToken included in create-user group for response 2. **UserController**: - Added POST /user endpoint (createUser) for user registration - Generates JWT tokens and associates them with User - Added JWT-related dependencies (JWTTokenManagerInterface, etc.) - Implemented LoggerAwareInterface for logging 3. **PlayerController**: - Removed POST /player endpoint (createPlayer method) - Removed JWT-related dependencies (no longer needed) - Cleaned up unused imports 4. **Player Entity**: - Removed token and refreshToken properties - Removed getToken/setToken and getRefreshToken/setRefreshToken methods - Removed 'create-player' serialization group references 5. **Test Helper** (tests/_support/Helper/Api.php): - Updated createPlayerAndUpdateHeaders to call POST /user - Updated createAdminAndUpdateHeaders to call POST /user This completes the separation of User (authentication) from Player (game participation). Users now authenticate once and can have multiple players across different rooms.
- Added cascade: ['remove'] to Room->Players OneToMany relationship - This ensures players are automatically deleted when their room is deleted - Removed RoomDoctrineListener entirely as it's no longer needed - The listener was manually removing players on room deletion, which is now handled by Doctrine's cascade This simplifies the codebase and relies on Doctrine's built-in cascading behavior.
Enhanced the migration to handle data migration from existing players: **Data Migration (up):** 1. For each existing player, creates a corresponding user with: - Same ID as the player - Same name and avatar (defaulting to 'captain' if null) - Same room_id - Default roles: ["ROLE_USER"] 2. Updates users_id_seq to continue after highest player ID 3. Links each player to their user (user_id = player.id) 4. Migrates player roles to new properties: - Sets player.is_admin = true for players with ROLE_ADMIN - Sets player.is_master = true for players with SPECTATING status 5. Makes user_id NOT NULL after data is migrated 6. Drops roles column from player table **Rollback (down):** 1. Adds roles column back to player 2. Migrates is_admin back to ROLE_ADMIN role 3. Removes new columns and relationships 4. Drops users table This ensures seamless migration of existing data to the new User-based authentication architecture.
Added three Apple OAuth environment variables to production deployment: - APPLE_CLIENT_SECRET (from PROD_APPLE_CLIENT_SECRET secret) - APPLE_KEY_FILE_ID (from PROD_APPLE_KEY_FILE_ID secret) - APPLE_TEAM_ID (from PROD_APPLE_TEAM_ID secret) These secrets are now: 1. Exported in the env_vars file for SSH deployment 2. Passed during Docker image build 3. Passed when starting Docker containers This enables Apple Sign In OAuth functionality in production environment.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
This commit introduces a comprehensive authentication refactoring:
Changes include:
OAuth endpoints: