Compare commits
No commits in common. "77b94e69880e4da241ce9cddcbbd6d6831c8d57c" and "c088cb2253320a51a2239f21db15f989a967c3e6" have entirely different histories.
77b94e6988
...
c088cb2253
@ -6,8 +6,6 @@ import app.mealsmadeeasy.api.ai.OcrService;
|
|||||||
import app.mealsmadeeasy.api.auth.AuthService;
|
import app.mealsmadeeasy.api.auth.AuthService;
|
||||||
import app.mealsmadeeasy.api.auth.LoginException;
|
import app.mealsmadeeasy.api.auth.LoginException;
|
||||||
import app.mealsmadeeasy.api.recipe.body.RecipeDraftUpdateBody;
|
import app.mealsmadeeasy.api.recipe.body.RecipeDraftUpdateBody;
|
||||||
import app.mealsmadeeasy.api.recipe.job.RecipeInferJobHandler;
|
|
||||||
import app.mealsmadeeasy.api.recipe.view.RecipeDraftView;
|
|
||||||
import app.mealsmadeeasy.api.user.User;
|
import app.mealsmadeeasy.api.user.User;
|
||||||
import app.mealsmadeeasy.api.user.UserCreateException;
|
import app.mealsmadeeasy.api.user.UserCreateException;
|
||||||
import app.mealsmadeeasy.api.user.UserService;
|
import app.mealsmadeeasy.api.user.UserService;
|
||||||
@ -16,21 +14,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
|
||||||
import org.springframework.util.MimeTypeUtils;
|
import org.springframework.util.MimeTypeUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.awaitility.Awaitility.await;
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
@ -58,12 +52,6 @@ public class RecipeDraftsControllerIntegrationTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ObjectMapper objectMapper;
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
@MockitoBean
|
|
||||||
private OcrService ocrService;
|
|
||||||
|
|
||||||
@MockitoBean
|
|
||||||
private InferenceService inferenceService;
|
|
||||||
|
|
||||||
private static final String TEST_PASSWORD = "test";
|
private static final String TEST_PASSWORD = "test";
|
||||||
|
|
||||||
private User seedUser() {
|
private User seedUser() {
|
||||||
@ -189,6 +177,12 @@ public class RecipeDraftsControllerIntegrationTests {
|
|||||||
@Nested
|
@Nested
|
||||||
public class AiDraftTestsWithMocks {
|
public class AiDraftTestsWithMocks {
|
||||||
|
|
||||||
|
@MockitoBean
|
||||||
|
private OcrService ocrService;
|
||||||
|
|
||||||
|
@MockitoBean
|
||||||
|
private InferenceService inferenceService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenAiDraft_returnsDraft() throws Exception {
|
public void whenAiDraft_returnsDraft() throws Exception {
|
||||||
final User owner = seedUser();
|
final User owner = seedUser();
|
||||||
@ -196,7 +190,7 @@ public class RecipeDraftsControllerIntegrationTests {
|
|||||||
"sourceFile",
|
"sourceFile",
|
||||||
"recipe.jpeg",
|
"recipe.jpeg",
|
||||||
MimeTypeUtils.IMAGE_JPEG_VALUE,
|
MimeTypeUtils.IMAGE_JPEG_VALUE,
|
||||||
this.getClass().getResourceAsStream("/recipe.jpeg")
|
AiDraftTestsWithMocks.class.getResourceAsStream("recipe.jpeg")
|
||||||
);
|
);
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
multipart("/recipe-drafts/ai")
|
multipart("/recipe-drafts/ai")
|
||||||
@ -211,46 +205,6 @@ public class RecipeDraftsControllerIntegrationTests {
|
|||||||
.andExpect(jsonPath("$.owner.username", is(owner.getUsername())));
|
.andExpect(jsonPath("$.owner.username", is(owner.getUsername())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void pollingAfterAiDraft_returnsDraftWithInference() throws Exception {
|
|
||||||
Mockito.when(ocrService.readMarkdown(Mockito.any())).thenReturn("# Recipe");
|
|
||||||
Mockito.when(inferenceService.extract(
|
|
||||||
Mockito.any(),
|
|
||||||
Mockito.any(),
|
|
||||||
Mockito.any()
|
|
||||||
)).thenReturn(new RecipeInferJobHandler.RecipeExtraction("Recipe", List.of()));
|
|
||||||
|
|
||||||
final User owner = seedUser();
|
|
||||||
final MockMultipartFile sourceFile = new MockMultipartFile(
|
|
||||||
"sourceFile",
|
|
||||||
"recipe.jpeg",
|
|
||||||
MimeTypeUtils.IMAGE_JPEG_VALUE,
|
|
||||||
this.getClass().getResourceAsStream("/recipe.jpeg")
|
|
||||||
);
|
|
||||||
final MvcResult result = mockMvc.perform(
|
|
||||||
multipart("/recipe-drafts/ai")
|
|
||||||
.file(sourceFile)
|
|
||||||
.param("sourceFileName", sourceFile.getOriginalFilename())
|
|
||||||
.header("Authorization", "Bearer " + getAccessToken(owner))
|
|
||||||
).andReturn();
|
|
||||||
final UUID draftId = objectMapper.readValue(
|
|
||||||
result.getResponse().getContentAsString(),
|
|
||||||
RecipeDraftView.class
|
|
||||||
).id();
|
|
||||||
await().atMost(3, TimeUnit.SECONDS).untilAsserted(() -> {
|
|
||||||
mockMvc.perform(
|
|
||||||
get("/recipe-drafts/{id}", draftId)
|
|
||||||
.header("Authorization", "Bearer " + getAccessToken(owner))
|
|
||||||
)
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.state", is(RecipeDraft.State.ENTER_DATA.toString())))
|
|
||||||
.andExpect(jsonPath("$.lastInference", is(notNullValue())))
|
|
||||||
.andExpect(jsonPath("$.lastInference.inferredAt", is(notNullValue())))
|
|
||||||
.andExpect(jsonPath("$.lastInference.title", is("Recipe")))
|
|
||||||
.andExpect(jsonPath("$.lastInference.rawText", is("# Recipe")));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RecipeDraftUpdateBody getTestRecipeDraftUpdateBody() {
|
private static RecipeDraftUpdateBody getTestRecipeDraftUpdateBody() {
|
||||||
|
|||||||
@ -12,7 +12,6 @@ public class RecipesEndpointAuthConfigurator implements EndpointAuthConfigurator
|
|||||||
@Override
|
@Override
|
||||||
public void configure(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
public void configure(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
||||||
registry.requestMatchers(HttpMethod.GET, "/recipes/**").permitAll();
|
registry.requestMatchers(HttpMethod.GET, "/recipes/**").permitAll();
|
||||||
registry.requestMatchers(HttpMethod.POST, "/recipes").permitAll(); // search
|
|
||||||
registry.requestMatchers(HttpMethod.POST, "/recipes/**").authenticated();
|
registry.requestMatchers(HttpMethod.POST, "/recipes/**").authenticated();
|
||||||
registry.requestMatchers(HttpMethod.PUT, "/recipes/**").authenticated();
|
registry.requestMatchers(HttpMethod.PUT, "/recipes/**").authenticated();
|
||||||
registry.requestMatchers(HttpMethod.DELETE, "/recipes/**").authenticated();
|
registry.requestMatchers(HttpMethod.DELETE, "/recipes/**").authenticated();
|
||||||
|
|||||||
@ -10,8 +10,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RecipeDraftToViewConverter {
|
public class RecipeDraftToViewConverter {
|
||||||
@ -22,17 +20,6 @@ public class RecipeDraftToViewConverter {
|
|||||||
final @Nullable ImageView mainImageView = recipeDraft.getMainImage() != null
|
final @Nullable ImageView mainImageView = recipeDraft.getMainImage() != null
|
||||||
? this.imageToViewConverter.convert(recipeDraft.getMainImage(), viewer, false)
|
? this.imageToViewConverter.convert(recipeDraft.getMainImage(), viewer, false)
|
||||||
: null;
|
: null;
|
||||||
final @Nullable RecipeDraftView.RecipeDraftInferenceView lastInference = recipeDraft.getInferences() != null
|
|
||||||
? recipeDraft.getInferences().stream()
|
|
||||||
.max(Comparator.comparing(RecipeDraft.RecipeDraftInference::getInferredAt))
|
|
||||||
.map(inference -> RecipeDraftView.RecipeDraftInferenceView.builder()
|
|
||||||
.inferredAt(inference.getInferredAt())
|
|
||||||
.title(inference.getTitle())
|
|
||||||
.rawText(inference.getRawText())
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.orElse(null)
|
|
||||||
: null;
|
|
||||||
return RecipeDraftView.builder()
|
return RecipeDraftView.builder()
|
||||||
.id(recipeDraft.getId())
|
.id(recipeDraft.getId())
|
||||||
.created(recipeDraft.getCreated())
|
.created(recipeDraft.getCreated())
|
||||||
@ -47,7 +34,6 @@ public class RecipeDraftToViewConverter {
|
|||||||
.ingredients(recipeDraft.getIngredients())
|
.ingredients(recipeDraft.getIngredients())
|
||||||
.owner(UserInfoView.from(recipeDraft.getOwner()))
|
.owner(UserInfoView.from(recipeDraft.getOwner()))
|
||||||
.mainImage(mainImageView)
|
.mainImage(mainImageView)
|
||||||
.lastInference(lastInference)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import app.mealsmadeeasy.api.recipe.RecipeDraft;
|
|||||||
import app.mealsmadeeasy.api.recipe.RecipeService;
|
import app.mealsmadeeasy.api.recipe.RecipeService;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -33,14 +32,12 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RecipeInferJobHandler implements JobHandler<RecipeInferJobPayload> {
|
public class RecipeInferJobHandler implements JobHandler<RecipeInferJobPayload> {
|
||||||
|
|
||||||
@ApiStatus.Internal
|
private record RecipeExtraction(
|
||||||
public record RecipeExtraction(
|
|
||||||
@JsonProperty(required = true) String title,
|
@JsonProperty(required = true) String title,
|
||||||
@JsonProperty(required = true) List<IngredientExtraction> ingredients
|
@JsonProperty(required = true) List<IngredientExtraction> ingredients
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ApiStatus.Internal
|
private record IngredientExtraction(
|
||||||
public record IngredientExtraction(
|
|
||||||
String amount,
|
String amount,
|
||||||
@JsonProperty(required = true) String name,
|
@JsonProperty(required = true) String name,
|
||||||
String notes
|
String notes
|
||||||
|
|||||||
@ -24,15 +24,5 @@ public record RecipeDraftView(
|
|||||||
@Nullable String rawText,
|
@Nullable String rawText,
|
||||||
@Nullable List<RecipeDraft.IngredientDraft> ingredients,
|
@Nullable List<RecipeDraft.IngredientDraft> ingredients,
|
||||||
UserInfoView owner,
|
UserInfoView owner,
|
||||||
@Nullable ImageView mainImage,
|
@Nullable ImageView mainImage
|
||||||
@Nullable RecipeDraftInferenceView lastInference
|
|
||||||
) {
|
|
||||||
|
|
||||||
@Builder
|
|
||||||
public record RecipeDraftInferenceView(
|
|
||||||
OffsetDateTime inferredAt,
|
|
||||||
String title,
|
|
||||||
String rawText
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user