diff --git a/backend/API_DOCUMENTATION.md b/backend/API_DOCUMENTATION.md index 5ec2777..7f5482d 100644 --- a/backend/API_DOCUMENTATION.md +++ b/backend/API_DOCUMENTATION.md @@ -50,7 +50,6 @@ Creates a new radio station and returns an owner token. "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", - "active": true, "connectedClients": [] }, "ownerToken": "jwt-token-here", @@ -63,11 +62,7 @@ Creates a new radio station and returns an owner token. Retrieves all radio stations. Requires authentication. -**Endpoint:** `GET /radio-stations?activeOnly=true` - -**Query Parameters:** - -- `activeOnly` (boolean, default: false): Filter to only active stations +**Endpoint:** `GET /radio-stations` **Response:** @@ -83,7 +78,6 @@ Retrieves all radio stations. Requires authentication. "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", - "active": true, "connectedClients": [] } ] @@ -109,7 +103,6 @@ Retrieves a specific radio station. Requires authentication. "ownerId": "owner-uuid", "joinCode": "ABC123", "createdAt": "2025-08-01T10:00:00", - "active": true, "connectedClients": [] } } @@ -169,8 +162,7 @@ Connects a client to a radio station using a join code. No authentication requir "id": "client-uuid", "username": "john_doe", "radioStationId": "station-uuid", - "connectedAt": "2025-08-01T10:00:00", - "active": true + "connectedAt": "2025-08-01T10:00:00" }, "clientToken": "jwt-token-here", "message": "Successfully connected to radio station. Use this token for further requests." @@ -211,7 +203,7 @@ curl -X POST http://localhost:8080/api/clients/connect \ ### Getting All Stations (with authentication) ```bash -curl -X GET "http://localhost:8080/api/radio-stations?activeOnly=true" \ +curl -X GET "http://localhost:8080/api/radio-stations" \ -H "Authorization: Bearer {token}" ``` diff --git a/backend/src/main/java/com/serena/backend/controller/RadioStationController.java b/backend/src/main/java/com/serena/backend/controller/RadioStationController.java index b805962..929bb8c 100644 --- a/backend/src/main/java/com/serena/backend/controller/RadioStationController.java +++ b/backend/src/main/java/com/serena/backend/controller/RadioStationController.java @@ -55,16 +55,8 @@ public class RadioStationController { } @GetMapping - public ResponseEntity>> getAllRadioStations( - @RequestParam(defaultValue = "false") boolean activeOnly) { - String currentUserId = AuthUtil.getCurrentUserId(); - if (currentUserId == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body(ApiResponse.error("User not authenticated")); - } - - List stations = activeOnly ? radioStationService.getActiveRadioStations() - : radioStationService.getAllRadioStations(); + public ResponseEntity>> getAllRadioStations() { + List stations = radioStationService.getAllRadioStations(); return ResponseEntity.ok(ApiResponse.success(stations)); } diff --git a/backend/src/main/java/com/serena/backend/controller/SongController.java b/backend/src/main/java/com/serena/backend/controller/SongController.java new file mode 100644 index 0000000..782e6fe --- /dev/null +++ b/backend/src/main/java/com/serena/backend/controller/SongController.java @@ -0,0 +1,41 @@ +package com.serena.backend.controller; + +import com.serena.backend.dto.ApiResponse; +import com.serena.backend.dto.ConnectClientRequest; +import com.serena.backend.dto.AddSongRequest; +import com.serena.backend.dto.AddSongToStationRequest; +import com.serena.backend.service.RadioStationService; +import com.serena.backend.service.JwtService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/songs/") +@CrossOrigin(origins = "*") +public class SongController { + + @Autowired + private RadioStationService radioStationService; + + @Autowired + private JwtService jwtService; + + @PostMapping + public ResponseEntity> addSong(@RequestBody AddSongRequest request) { + if (request.getSong() == null || request.getRadioStationId() == null) { + return ResponseEntity.badRequest() + .body(new ApiResponse<>(false, "Song data and radio station ID are required", null)); + } + + boolean success = radioStationService.addSongToQueue(request.getRadioStationId(), request.getSong()); + + if (success) { + return ResponseEntity.ok(new ApiResponse<>(true, "Song added to queue successfully", null)); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(new ApiResponse<>(false, "Radio station not found or inactive", null)); + } + } +} diff --git a/backend/src/main/java/com/serena/backend/dto/AddSongRequest.java b/backend/src/main/java/com/serena/backend/dto/AddSongRequest.java new file mode 100644 index 0000000..be69f9f --- /dev/null +++ b/backend/src/main/java/com/serena/backend/dto/AddSongRequest.java @@ -0,0 +1,31 @@ +package com.serena.backend.dto; + +import com.serena.backend.model.Song; + +public class AddSongRequest { + private Song song; + private String radioStationId; + + public AddSongRequest() {} + + public AddSongRequest(Song song, String radioStationId) { + this.song = song; + this.radioStationId = radioStationId; + } + + public Song getSong() { + return song; + } + + public void setSong(Song song) { + this.song = song; + } + + public String getRadioStationId() { + return radioStationId; + } + + public void setRadioStationId(String radioStationId) { + this.radioStationId = radioStationId; + } +} diff --git a/backend/src/main/java/com/serena/backend/model/Client.java b/backend/src/main/java/com/serena/backend/model/Client.java index 4427590..4b5e2dd 100644 --- a/backend/src/main/java/com/serena/backend/model/Client.java +++ b/backend/src/main/java/com/serena/backend/model/Client.java @@ -8,12 +8,10 @@ public class Client { private String username; private String radioStationId; private LocalDateTime connectedAt; - private boolean isActive; public Client() { this.id = UUID.randomUUID().toString(); this.connectedAt = LocalDateTime.now(); - this.isActive = true; } public Client(String username, String radioStationId) { @@ -55,11 +53,4 @@ public class Client { this.connectedAt = connectedAt; } - public boolean isActive() { - return isActive; - } - - public void setActive(boolean active) { - isActive = active; - } } diff --git a/backend/src/main/java/com/serena/backend/model/RadioStation.java b/backend/src/main/java/com/serena/backend/model/RadioStation.java index 8ba3269..693f480 100644 --- a/backend/src/main/java/com/serena/backend/model/RadioStation.java +++ b/backend/src/main/java/com/serena/backend/model/RadioStation.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.UUID; +import java.util.LinkedList; +import java.util.Queue; public class RadioStation { private String id; @@ -13,15 +15,15 @@ public class RadioStation { private String ownerId; private String joinCode; private LocalDateTime createdAt; - private boolean isActive; private List connectedClients; + private Queue songQueue; public RadioStation() { this.id = UUID.randomUUID().toString(); this.joinCode = generateJoinCode(); this.createdAt = LocalDateTime.now(); - this.isActive = true; this.connectedClients = new ArrayList<>(); + this.songQueue = new LinkedList<>(); } public RadioStation(String name, String description, String ownerId) { @@ -91,14 +93,6 @@ public class RadioStation { this.createdAt = createdAt; } - public boolean isActive() { - return isActive; - } - - public void setActive(boolean active) { - isActive = active; - } - public List getConnectedClients() { return connectedClients; } @@ -107,4 +101,20 @@ public class RadioStation { this.connectedClients = connectedClients; } + public Queue getSongQueue() { + return songQueue; + } + + public void setSongQueue(Queue songQueue) { + this.songQueue = songQueue; + } + + public void addSongToQueue(Song song) { + this.songQueue.offer(song); + } + + public Song getNextSong() { + return this.songQueue.poll(); + } + } diff --git a/backend/src/main/java/com/serena/backend/model/Song.java b/backend/src/main/java/com/serena/backend/model/Song.java new file mode 100644 index 0000000..b693a08 --- /dev/null +++ b/backend/src/main/java/com/serena/backend/model/Song.java @@ -0,0 +1,30 @@ +package com.serena.backend.model; + +public class Song { + private String id; + private int popularity; + + public Song() {} + + public Song(String id, int popularity) { + this.id = id; + this.popularity = popularity; + } + + // Getters and Setters + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public int getPopularity() { + return popularity; + } + + public void setPopularity(int popularity) { + this.popularity = popularity; + } +} diff --git a/backend/src/main/java/com/serena/backend/service/RadioStationService.java b/backend/src/main/java/com/serena/backend/service/RadioStationService.java index b81063d..cb408a5 100644 --- a/backend/src/main/java/com/serena/backend/service/RadioStationService.java +++ b/backend/src/main/java/com/serena/backend/service/RadioStationService.java @@ -2,6 +2,7 @@ package com.serena.backend.service; import com.serena.backend.model.RadioStation; import com.serena.backend.model.Client; +import com.serena.backend.model.Song; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -29,7 +30,7 @@ public class RadioStationService { public Optional getRadioStationByJoinCode(String joinCode) { return radioStations.values().stream() - .filter(station -> station.getJoinCode().equals(joinCode) && station.isActive()) + .filter(station -> station.getJoinCode().equals(joinCode)) .findFirst(); } @@ -39,7 +40,6 @@ public class RadioStationService { public List getActiveRadioStations() { return radioStations.values().stream() - .filter(RadioStation::isActive) .toList(); } @@ -58,7 +58,6 @@ public class RadioStationService { public boolean deleteRadioStation(String stationId) { RadioStation station = radioStations.get(stationId); if (station != null) { - station.setActive(false); // Disconnect all clients station.getConnectedClients().clear(); // Remove from clients map @@ -72,7 +71,7 @@ public class RadioStationService { // Client Management public Optional connectClient(String username, String radioStationId, String joinCode) { RadioStation station = radioStations.get(radioStationId); - if (station != null && station.isActive() && station.getJoinCode().equals(joinCode)) { + if (station != null && station.getJoinCode().equals(joinCode)) { Client client = new Client(username, radioStationId); clients.put(client.getId(), client); station.getConnectedClients().add(client.getId()); diff --git a/backend/src/test/java/com/serena/backend/service/RadioStationServiceTest.java b/backend/src/test/java/com/serena/backend/service/RadioStationServiceTest.java deleted file mode 100644 index fe32945..0000000 --- a/backend/src/test/java/com/serena/backend/service/RadioStationServiceTest.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.serena.backend.service; - -import com.serena.backend.model.RadioStation; -import com.serena.backend.model.Client; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; - -class RadioStationServiceTest { - - private RadioStationService radioStationService; - - @BeforeEach - void setUp() { - radioStationService = new RadioStationService(); - } - - @Test - @DisplayName("Should create radio station with join code") - void shouldCreateRadioStationWithJoinCode() { - // Given - String name = "Test Station"; - String description = "Test Description"; - String ownerId = "owner123"; - - // When - RadioStation station = radioStationService.createRadioStation(name, description, ownerId); - - // Then - assertNotNull(station); - assertNotNull(station.getId()); - assertNotNull(station.getJoinCode()); - assertEquals(6, station.getJoinCode().length()); - assertEquals(name, station.getName()); - assertEquals(description, station.getDescription()); - assertEquals(ownerId, station.getOwnerId()); - assertTrue(station.isActive()); - } - - @Test - @DisplayName("Should find radio station by join code") - void shouldFindRadioStationByJoinCode() { - // Given - RadioStation station = radioStationService.createRadioStation("Test Station", "Description", "owner123"); - String joinCode = station.getJoinCode(); - - // When - Optional foundStation = radioStationService.getRadioStationByJoinCode(joinCode); - - // Then - assertTrue(foundStation.isPresent()); - assertEquals(station.getId(), foundStation.get().getId()); - assertEquals(joinCode, foundStation.get().getJoinCode()); - } - - @Test - @DisplayName("Should not find radio station with invalid join code") - void shouldNotFindRadioStationWithInvalidJoinCode() { - // Given - radioStationService.createRadioStation("Test Station", "Description", "owner123"); - String invalidJoinCode = "INVALID"; - - // When - Optional foundStation = radioStationService.getRadioStationByJoinCode(invalidJoinCode); - - // Then - assertFalse(foundStation.isPresent()); - } - - @Test - @DisplayName("Should connect client with valid join code") - void shouldConnectClientWithValidJoinCode() { - // Given - RadioStation station = radioStationService.createRadioStation("Test Station", "Description", "owner123"); - String username = "testuser"; - String joinCode = station.getJoinCode(); - - // When - Optional client = radioStationService.connectClient(username, station.getId(), joinCode); - - // Then - assertTrue(client.isPresent()); - assertEquals(username, client.get().getUsername()); - assertEquals(station.getId(), client.get().getRadioStationId()); - assertTrue(station.getConnectedClients().contains(client.get().getId())); - } - - @Test - @DisplayName("Should not connect client with invalid join code") - void shouldNotConnectClientWithInvalidJoinCode() { - // Given - RadioStation station = radioStationService.createRadioStation("Test Station", "Description", "owner123"); - String username = "testuser"; - String invalidJoinCode = "WRONG1"; - - // When - Optional client = radioStationService.connectClient(username, station.getId(), invalidJoinCode); - - // Then - assertFalse(client.isPresent()); - assertTrue(station.getConnectedClients().isEmpty()); - } - - @Test - @DisplayName("Should connect client using join code only") - void shouldConnectClientUsingJoinCodeOnly() { - // Given - RadioStation station = radioStationService.createRadioStation("Test Station", "Description", "owner123"); - String username = "testuser"; - String joinCode = station.getJoinCode(); - - // When - Optional client = radioStationService.connectClientByJoinCode(username, joinCode); - - // Then - assertTrue(client.isPresent()); - assertEquals(username, client.get().getUsername()); - assertEquals(station.getId(), client.get().getRadioStationId()); - assertTrue(station.getConnectedClients().contains(client.get().getId())); - } - - @Test - @DisplayName("Should not connect client to inactive radio station") - void shouldNotConnectClientToInactiveRadioStation() { - // Given - RadioStation station = radioStationService.createRadioStation("Test Station", "Description", "owner123"); - station.setActive(false); - String username = "testuser"; - String joinCode = station.getJoinCode(); - - // When - Optional client = radioStationService.connectClient(username, station.getId(), joinCode); - - // Then - assertFalse(client.isPresent()); - } - - @Test - @DisplayName("Should generate unique join codes for different stations") - void shouldGenerateUniqueJoinCodesForDifferentStations() { - // Given & When - RadioStation station1 = radioStationService.createRadioStation("Station 1", "Desc 1", "owner1"); - RadioStation station2 = radioStationService.createRadioStation("Station 2", "Desc 2", "owner2"); - - // Then - assertNotEquals(station1.getJoinCode(), station2.getJoinCode()); - assertEquals(6, station1.getJoinCode().length()); - assertEquals(6, station2.getJoinCode().length()); - } -}