diff --git a/mflix/server/java-spring/.env.example b/mflix/server/java-spring/.env.example index 627b54b..049e6e9 100644 --- a/mflix/server/java-spring/.env.example +++ b/mflix/server/java-spring/.env.example @@ -2,9 +2,11 @@ # Replace with your MongoDB Atlas connection string or local MongoDB URI MONGODB_URI=mongodb+srv://:@.mongodb.net/sample_mflix?retryWrites=true&w=majority -# Voyage AI Configuration +# Optional: Voyage AI Configuration # API key for Voyage AI embedding model (required for Vector Search) -VOYAGE_API_KEY=your_voyage_api_key +# Get your API key from https://www.voyageai.com/ +# Uncomment the following line to enable vector search +# VOYAGE_API_KEY=your-api-key # Server Configuration # Port on which the Spring Boot application will run diff --git a/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/config/DatabaseVerification.java b/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/config/DatabaseVerification.java index 752168f..9369fc7 100644 --- a/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/config/DatabaseVerification.java +++ b/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/config/DatabaseVerification.java @@ -138,17 +138,24 @@ private void verifyMoviesCollection() { */ private void createTextSearchIndex(MongoCollection moviesCollection) { try { - // Check if the text search index already exists - boolean indexExists = false; + // Check if any text search index already exists + // MongoDB only allows one text index per collection, so we check for any text index + // not just one with our specific name + boolean textIndexExists = false; + String existingTextIndexName = null; + for (Document index : moviesCollection.listIndexes()) { - if (TEXT_INDEX_NAME.equals(index.getString("name"))) { - indexExists = true; - logger.info("Text search index '{}' already exists", TEXT_INDEX_NAME); + Document key = index.get("key", Document.class); + if (key != null && key.containsKey("_fts")) { + // _fts is the internal field MongoDB uses for text indexes + textIndexExists = true; + existingTextIndexName = index.getString("name"); + logger.info("Text search index '{}' already exists on movies collection", existingTextIndexName); break; } } - if (!indexExists) { + if (!textIndexExists) { // Create compound text index on plot, title, and fullplot fields // The background option allows the index to be built without blocking other operations IndexOptions indexOptions = new IndexOptions() diff --git a/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/service/MovieServiceImpl.java b/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/service/MovieServiceImpl.java index 624fa36..f86bbb5 100644 --- a/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/service/MovieServiceImpl.java +++ b/mflix/server/java-spring/src/main/java/com/mongodb/samplemflix/service/MovieServiceImpl.java @@ -819,9 +819,10 @@ public List vectorSearchMovies(String query, Integer limit) } // Check if Voyage API key is configured - if (voyageApiKey == null || voyageApiKey.trim().isEmpty()) { + if (voyageApiKey == null || voyageApiKey.trim().isEmpty() || + voyageApiKey.equals("your_voyage_api_key")) { throw new ValidationException( - "Vector search unavailable: VOYAGE_API_KEY not configured. Please add your API key to the application.properties file" + "Vector search unavailable: VOYAGE_API_KEY not configured. Please add your Voyage AI API key to the .env file" ); } @@ -978,6 +979,10 @@ private List generateVoyageEmbedding(String text, String apiKey) throws // Check for successful response if (response.statusCode() != 200) { + // Handle authentication errors specifically + if (response.statusCode() == 401) { + throw new IOException("Invalid Voyage AI API key. Please check your VOYAGE_API_KEY in the .env file"); + } throw new IOException("Voyage AI API returned status code " + response.statusCode() + ": " + response.body()); } diff --git a/mflix/server/java-spring/src/test/java/com/mongodb/samplemflix/service/MovieServiceTest.java b/mflix/server/java-spring/src/test/java/com/mongodb/samplemflix/service/MovieServiceTest.java index d68e202..6773e0b 100644 --- a/mflix/server/java-spring/src/test/java/com/mongodb/samplemflix/service/MovieServiceTest.java +++ b/mflix/server/java-spring/src/test/java/com/mongodb/samplemflix/service/MovieServiceTest.java @@ -745,6 +745,16 @@ void testVectorSearchMovies_MissingApiKey() { assertThrows(ValidationException.class, () -> movieService.vectorSearchMovies("test query", 10)); } + @Test + @DisplayName("Should throw ValidationException when API key is placeholder value in vector search") + void testVectorSearchMovies_PlaceholderApiKey() { + // Arrange + ReflectionTestUtils.setField(movieService, "voyageApiKey", "your_voyage_api_key"); + + // Act & Assert + assertThrows(ValidationException.class, () -> movieService.vectorSearchMovies("test query", 10)); + } + @Test @DisplayName("Should enforce limit constraints in vector search") void testVectorSearchMovies_LimitConstraints() {