feat(backend): make invite share URL base configurable via app.base-url
Replaces hardcoded \"https://yourapp.com\" with a Spring property. - application.yml: app.base-url defaults to http://localhost:5173 - application-docker.yml: reads APP_BASE_URL env var, same default - HouseholdService: injects @Value("${app.base-url}") and uses it in toInviteResponse() to build shareUrl - HouseholdServiceTest: sets field via ReflectionTestUtils in @BeforeEach; adds test asserting shareUrl starts with configured base URL Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import com.recipeapp.recipe.TagRepository;
|
|||||||
import com.recipeapp.recipe.entity.Ingredient;
|
import com.recipeapp.recipe.entity.Ingredient;
|
||||||
import com.recipeapp.recipe.entity.IngredientCategory;
|
import com.recipeapp.recipe.entity.IngredientCategory;
|
||||||
import com.recipeapp.recipe.entity.Tag;
|
import com.recipeapp.recipe.entity.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -38,6 +39,9 @@ public class HouseholdService {
|
|||||||
private final TagRepository tagRepository;
|
private final TagRepository tagRepository;
|
||||||
private final VarietyScoreConfigRepository varietyScoreConfigRepository;
|
private final VarietyScoreConfigRepository varietyScoreConfigRepository;
|
||||||
|
|
||||||
|
@Value("${app.base-url}")
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
private static final SecureRandom RANDOM = new SecureRandom();
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
private static final String CODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
private static final String CODE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
|
||||||
@@ -262,7 +266,7 @@ public class HouseholdService {
|
|||||||
private InviteResponse toInviteResponse(HouseholdInvite invite) {
|
private InviteResponse toInviteResponse(HouseholdInvite invite) {
|
||||||
return new InviteResponse(
|
return new InviteResponse(
|
||||||
invite.getInviteCode(),
|
invite.getInviteCode(),
|
||||||
"https://yourapp.com/join/" + invite.getInviteCode(),
|
baseUrl + "/join/" + invite.getInviteCode(),
|
||||||
invite.getExpiresAt());
|
invite.getExpiresAt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ spring:
|
|||||||
flyway:
|
flyway:
|
||||||
locations: classpath:db/migration,classpath:db/seed
|
locations: classpath:db/migration,classpath:db/seed
|
||||||
out-of-order: true
|
out-of-order: true
|
||||||
|
|
||||||
|
app:
|
||||||
|
base-url: ${APP_BASE_URL:http://localhost:5173}
|
||||||
|
|||||||
@@ -30,3 +30,6 @@ spring:
|
|||||||
|
|
||||||
server:
|
server:
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
|
app:
|
||||||
|
base-url: http://localhost:5173
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -43,6 +45,11 @@ class HouseholdServiceTest {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private HouseholdService householdService;
|
private HouseholdService householdService;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
ReflectionTestUtils.setField(householdService, "baseUrl", "http://localhost:5173");
|
||||||
|
}
|
||||||
|
|
||||||
private UserAccount testUser() {
|
private UserAccount testUser() {
|
||||||
return new UserAccount("sarah@example.com", "Sarah", "hashed");
|
return new UserAccount("sarah@example.com", "Sarah", "hashed");
|
||||||
}
|
}
|
||||||
@@ -132,6 +139,21 @@ class HouseholdServiceTest {
|
|||||||
verify(householdInviteRepository).save(any(HouseholdInvite.class));
|
verify(householdInviteRepository).save(any(HouseholdInvite.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createInviteShouldBuildShareUrlWithConfiguredBaseUrl() {
|
||||||
|
var user = testUser();
|
||||||
|
var household = new Household("Smith family", user);
|
||||||
|
var member = new HouseholdMember(household, user, "planner");
|
||||||
|
|
||||||
|
when(householdMemberRepository.findByUserEmailIgnoreCase("sarah@example.com")).thenReturn(Optional.of(member));
|
||||||
|
when(householdInviteRepository.save(any(HouseholdInvite.class))).thenAnswer(i -> i.getArgument(0));
|
||||||
|
|
||||||
|
InviteResponse result = householdService.createInvite("sarah@example.com");
|
||||||
|
|
||||||
|
assertThat(result.shareUrl()).startsWith("http://localhost:5173/join/");
|
||||||
|
assertThat(result.shareUrl()).endsWith(result.inviteCode());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void acceptInviteShouldAddUserAsMember() {
|
void acceptInviteShouldAddUserAsMember() {
|
||||||
var user = new UserAccount("tom@example.com", "Tom", "hashed");
|
var user = new UserAccount("tom@example.com", "Tom", "hashed");
|
||||||
|
|||||||
Reference in New Issue
Block a user