remove subdomain feature
This commit is contained in:
@@ -44,7 +44,7 @@ public class ExportController {
|
|||||||
SiteStructure structure = llmService.restoreVersion(versions.get(0).getId());
|
SiteStructure structure = llmService.restoreVersion(versions.get(0).getId());
|
||||||
try {
|
try {
|
||||||
byte[] zip = exportService.exportSite(structure);
|
byte[] zip = exportService.exportSite(structure);
|
||||||
String filename = site.getSubdomain() != null ? site.getSubdomain() : site.getName().replaceAll("\\s+", "-");
|
String filename = site.getName().replaceAll("\\s+", "-");
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"attachment; filename=\"" + sanitizeFilename(filename) + "-export.zip\"")
|
"attachment; filename=\"" + sanitizeFilename(filename) + "-export.zip\"")
|
||||||
|
|||||||
@@ -36,18 +36,12 @@ public class SiteController {
|
|||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<SiteResponse> createSite(@AuthenticationPrincipal UserPrincipal principal,
|
public ResponseEntity<SiteResponse> createSite(@AuthenticationPrincipal UserPrincipal principal,
|
||||||
@Valid @RequestBody SiteRequest request) {
|
@Valid @RequestBody SiteRequest request) {
|
||||||
String subdomain = sanitizeSubdomain(request.getSubdomain());
|
|
||||||
if (subdomain != null && siteRepository.existsBySubdomain(subdomain)) {
|
|
||||||
throw new IllegalArgumentException("Subdomain already taken");
|
|
||||||
}
|
|
||||||
|
|
||||||
Site.DeploymentTarget target = parseDeploymentTarget(request.getDeploymentTarget());
|
Site.DeploymentTarget target = parseDeploymentTarget(request.getDeploymentTarget());
|
||||||
|
|
||||||
Site site = Site.builder()
|
Site site = Site.builder()
|
||||||
.userId(principal.id())
|
.userId(principal.id())
|
||||||
.name(request.getName())
|
.name(request.getName())
|
||||||
.description(request.getDescription())
|
.description(request.getDescription())
|
||||||
.subdomain(subdomain)
|
|
||||||
.deploymentTarget(target)
|
.deploymentTarget(target)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -68,16 +62,8 @@ public class SiteController {
|
|||||||
@Valid @RequestBody SiteRequest request) {
|
@Valid @RequestBody SiteRequest request) {
|
||||||
Site site = findSiteForUser(id, principal.id());
|
Site site = findSiteForUser(id, principal.id());
|
||||||
|
|
||||||
String newSubdomain = sanitizeSubdomain(request.getSubdomain());
|
|
||||||
boolean subdomainChanged = (site.getSubdomain() != null && !site.getSubdomain().equals(newSubdomain))
|
|
||||||
|| (site.getSubdomain() == null && newSubdomain != null);
|
|
||||||
if (subdomainChanged && newSubdomain != null && siteRepository.existsBySubdomain(newSubdomain)) {
|
|
||||||
throw new IllegalArgumentException("Subdomain already taken");
|
|
||||||
}
|
|
||||||
|
|
||||||
site.setName(request.getName());
|
site.setName(request.getName());
|
||||||
site.setDescription(request.getDescription());
|
site.setDescription(request.getDescription());
|
||||||
site.setSubdomain(newSubdomain);
|
|
||||||
|
|
||||||
if (request.getDeploymentTarget() != null) {
|
if (request.getDeploymentTarget() != null) {
|
||||||
site.setDeploymentTarget(parseDeploymentTarget(request.getDeploymentTarget()));
|
site.setDeploymentTarget(parseDeploymentTarget(request.getDeploymentTarget()));
|
||||||
@@ -104,17 +90,6 @@ public class SiteController {
|
|||||||
return site;
|
return site;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String sanitizeSubdomain(String subdomain) {
|
|
||||||
if (subdomain == null || subdomain.isBlank()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String cleaned = subdomain.strip().toLowerCase();
|
|
||||||
if (!cleaned.matches("^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$")) {
|
|
||||||
throw new IllegalArgumentException("Subdomain must be 3-63 characters, lowercase alphanumeric with hyphens");
|
|
||||||
}
|
|
||||||
return cleaned;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Site.DeploymentTarget parseDeploymentTarget(String value) {
|
private Site.DeploymentTarget parseDeploymentTarget(String value) {
|
||||||
if (value == null || value.isBlank()) {
|
if (value == null || value.isBlank()) {
|
||||||
return Site.DeploymentTarget.NONE;
|
return Site.DeploymentTarget.NONE;
|
||||||
|
|||||||
@@ -11,7 +11,5 @@ public class SiteRequest {
|
|||||||
|
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
private String subdomain;
|
|
||||||
|
|
||||||
private String deploymentTarget;
|
private String deploymentTarget;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ public class SiteResponse {
|
|||||||
private UUID userId;
|
private UUID userId;
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
private String subdomain;
|
|
||||||
private String publishedUrl;
|
private String publishedUrl;
|
||||||
private SiteStatus status;
|
private SiteStatus status;
|
||||||
private String deploymentTarget;
|
private String deploymentTarget;
|
||||||
@@ -32,7 +31,6 @@ public class SiteResponse {
|
|||||||
.userId(site.getUserId())
|
.userId(site.getUserId())
|
||||||
.name(site.getName())
|
.name(site.getName())
|
||||||
.description(site.getDescription())
|
.description(site.getDescription())
|
||||||
.subdomain(site.getSubdomain())
|
|
||||||
.publishedUrl(site.getPublishedUrl())
|
.publishedUrl(site.getPublishedUrl())
|
||||||
.status(site.getStatus())
|
.status(site.getStatus())
|
||||||
.deploymentTarget(site.getDeploymentTarget().name())
|
.deploymentTarget(site.getDeploymentTarget().name())
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ public class Site {
|
|||||||
@Column(name = "description", length = 1000)
|
@Column(name = "description", length = 1000)
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@Column(name = "subdomain", unique = true)
|
|
||||||
private String subdomain;
|
|
||||||
|
|
||||||
@Column(name = "published_url")
|
@Column(name = "published_url")
|
||||||
private String publishedUrl;
|
private String publishedUrl;
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,9 @@ import com.krrishg.model.Site;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface SiteRepository extends JpaRepository<Site, UUID> {
|
public interface SiteRepository extends JpaRepository<Site, UUID> {
|
||||||
|
|
||||||
List<Site> findByUserIdOrderByCreatedAtDesc(UUID userId);
|
List<Site> findByUserIdOrderByCreatedAtDesc(UUID userId);
|
||||||
|
|
||||||
Optional<Site> findBySubdomain(String subdomain);
|
|
||||||
|
|
||||||
boolean existsBySubdomain(String subdomain);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import com.krrishg.model.SelfHostedConfig;
|
|||||||
import com.krrishg.model.Site;
|
import com.krrishg.model.Site;
|
||||||
import com.krrishg.repository.SelfHostedConfigRepository;
|
import com.krrishg.repository.SelfHostedConfigRepository;
|
||||||
import com.krrishg.repository.SiteRepository;
|
import com.krrishg.repository.SiteRepository;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -14,18 +11,13 @@ import java.util.Optional;
|
|||||||
@Service
|
@Service
|
||||||
public class DomainService {
|
public class DomainService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DomainService.class);
|
|
||||||
|
|
||||||
private final SiteRepository siteRepository;
|
private final SiteRepository siteRepository;
|
||||||
private final SelfHostedConfigRepository selfHostedConfigRepository;
|
private final SelfHostedConfigRepository selfHostedConfigRepository;
|
||||||
private final String siteDomain;
|
|
||||||
|
|
||||||
public DomainService(SiteRepository siteRepository,
|
public DomainService(SiteRepository siteRepository,
|
||||||
SelfHostedConfigRepository selfHostedConfigRepository,
|
SelfHostedConfigRepository selfHostedConfigRepository) {
|
||||||
@Value("${indie.domain}") String siteDomain) {
|
|
||||||
this.siteRepository = siteRepository;
|
this.siteRepository = siteRepository;
|
||||||
this.selfHostedConfigRepository = selfHostedConfigRepository;
|
this.selfHostedConfigRepository = selfHostedConfigRepository;
|
||||||
this.siteDomain = siteDomain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Site> resolveSite(String hostname) {
|
public Optional<Site> resolveSite(String hostname) {
|
||||||
@@ -40,33 +32,6 @@ public class DomainService {
|
|||||||
return siteRepository.findById(config.get().getSiteId());
|
return siteRepository.findById(config.get().getSiteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
String subdomain = extractSubdomain(lower);
|
|
||||||
if (subdomain != null) {
|
|
||||||
return siteRepository.findBySubdomain(subdomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String extractSubdomain(String hostname) {
|
|
||||||
String suffix = "." + siteDomain;
|
|
||||||
if (hostname.endsWith(suffix)) {
|
|
||||||
String subdomain = hostname.substring(0, hostname.indexOf(suffix));
|
|
||||||
if (!subdomain.isEmpty() && !subdomain.contains(".")) {
|
|
||||||
return subdomain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSubdomainAvailable(String subdomain) {
|
|
||||||
return !siteRepository.existsBySubdomain(subdomain);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSiteUrl(Site site) {
|
|
||||||
if (site.getSubdomain() != null) {
|
|
||||||
return "https://" + site.getSubdomain() + "." + siteDomain;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ indie:
|
|||||||
repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/}
|
repos-path: ${INDIE_GIT_REPOS_PATH:/home/krrish/git/sites/}
|
||||||
author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform}
|
author-name: ${INDIE_GIT_AUTHOR_NAME:Indie Platform}
|
||||||
author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local}
|
author-email: ${INDIE_GIT_AUTHOR_EMAIL:git@indie.local}
|
||||||
domain: ${INDIE_SITE_DOMAIN:indie.com}
|
|
||||||
cors:
|
cors:
|
||||||
allowed-origins: ${INDIE_CORS_ORIGINS:http://localhost:4200,http://localhost:3000}
|
allowed-origins: ${INDIE_CORS_ORIGINS:http://localhost:4200,http://localhost:3000}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ class ExportControllerTest {
|
|||||||
.id(siteId)
|
.id(siteId)
|
||||||
.userId(userId)
|
.userId(userId)
|
||||||
.name("My Site")
|
.name("My Site")
|
||||||
.subdomain("my-site")
|
|
||||||
.status(SiteStatus.DRAFT)
|
.status(SiteStatus.DRAFT)
|
||||||
.createdAt(LocalDateTime.now())
|
.createdAt(LocalDateTime.now())
|
||||||
.updatedAt(LocalDateTime.now())
|
.updatedAt(LocalDateTime.now())
|
||||||
@@ -125,17 +124,16 @@ class ExportControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void exportSanitizesFilenameForSiteWithoutSubdomain() throws Exception {
|
void exportSanitizesFilenameWithSpecialCharacters() throws Exception {
|
||||||
Site siteNoSubdomain = Site.builder()
|
Site siteWithSpecialName = Site.builder()
|
||||||
.id(siteId)
|
.id(siteId)
|
||||||
.userId(userId)
|
.userId(userId)
|
||||||
.name("My Cool Site!")
|
.name("My Cool Site!")
|
||||||
.subdomain(null)
|
|
||||||
.status(SiteStatus.DRAFT)
|
.status(SiteStatus.DRAFT)
|
||||||
.createdAt(LocalDateTime.now())
|
.createdAt(LocalDateTime.now())
|
||||||
.updatedAt(LocalDateTime.now())
|
.updatedAt(LocalDateTime.now())
|
||||||
.build();
|
.build();
|
||||||
when(siteRepository.findById(siteId)).thenReturn(Optional.of(siteNoSubdomain));
|
when(siteRepository.findById(siteId)).thenReturn(Optional.of(siteWithSpecialName));
|
||||||
|
|
||||||
GenerationVersion version = GenerationVersion.builder()
|
GenerationVersion version = GenerationVersion.builder()
|
||||||
.id("v1")
|
.id("v1")
|
||||||
|
|||||||
@@ -80,41 +80,22 @@ class SiteControllerTest {
|
|||||||
.userId(userId)
|
.userId(userId)
|
||||||
.name("New Site")
|
.name("New Site")
|
||||||
.description("Description")
|
.description("Description")
|
||||||
.subdomain("new-site")
|
|
||||||
.status(SiteStatus.DRAFT)
|
.status(SiteStatus.DRAFT)
|
||||||
.createdAt(LocalDateTime.now())
|
.createdAt(LocalDateTime.now())
|
||||||
.updatedAt(LocalDateTime.now())
|
.updatedAt(LocalDateTime.now())
|
||||||
.build();
|
.build();
|
||||||
when(siteRepository.existsBySubdomain("new-site")).thenReturn(false);
|
|
||||||
when(siteRepository.save(any(Site.class))).thenReturn(saved);
|
when(siteRepository.save(any(Site.class))).thenReturn(saved);
|
||||||
|
|
||||||
SiteRequest request = new SiteRequest();
|
SiteRequest request = new SiteRequest();
|
||||||
request.setName("New Site");
|
request.setName("New Site");
|
||||||
request.setDescription("Description");
|
request.setDescription("Description");
|
||||||
request.setSubdomain("new-site");
|
|
||||||
|
|
||||||
mockMvc.perform(post("/api/sites")
|
mockMvc.perform(post("/api/sites")
|
||||||
.with(authentication(auth))
|
.with(authentication(auth))
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content(objectMapper.writeValueAsString(request)))
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
.andExpect(status().isCreated())
|
.andExpect(status().isCreated())
|
||||||
.andExpect(jsonPath("$.name").value("New Site"))
|
.andExpect(jsonPath("$.name").value("New Site"));
|
||||||
.andExpect(jsonPath("$.subdomain").value("new-site"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void createSiteReturns400OnDuplicateSubdomain() throws Exception {
|
|
||||||
when(siteRepository.existsBySubdomain("taken")).thenReturn(true);
|
|
||||||
|
|
||||||
SiteRequest request = new SiteRequest();
|
|
||||||
request.setName("Site");
|
|
||||||
request.setSubdomain("taken");
|
|
||||||
|
|
||||||
mockMvc.perform(post("/api/sites")
|
|
||||||
.with(authentication(auth))
|
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
|
||||||
.content(objectMapper.writeValueAsString(request)))
|
|
||||||
.andExpect(status().isBadRequest());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -173,23 +154,19 @@ class SiteControllerTest {
|
|||||||
.id(siteId)
|
.id(siteId)
|
||||||
.userId(userId)
|
.userId(userId)
|
||||||
.name("Old Name")
|
.name("Old Name")
|
||||||
.subdomain("old-sub")
|
|
||||||
.status(SiteStatus.DRAFT)
|
.status(SiteStatus.DRAFT)
|
||||||
.build();
|
.build();
|
||||||
when(siteRepository.findById(siteId)).thenReturn(Optional.of(existing));
|
when(siteRepository.findById(siteId)).thenReturn(Optional.of(existing));
|
||||||
when(siteRepository.existsBySubdomain("new-sub")).thenReturn(false);
|
|
||||||
when(siteRepository.save(any(Site.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
when(siteRepository.save(any(Site.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||||
|
|
||||||
SiteRequest request = new SiteRequest();
|
SiteRequest request = new SiteRequest();
|
||||||
request.setName("New Name");
|
request.setName("New Name");
|
||||||
request.setSubdomain("new-sub");
|
|
||||||
|
|
||||||
mockMvc.perform(put("/api/sites/{id}", siteId)
|
mockMvc.perform(put("/api/sites/{id}", siteId)
|
||||||
.with(authentication(auth))
|
.with(authentication(auth))
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content(objectMapper.writeValueAsString(request)))
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.name").value("New Name"))
|
.andExpect(jsonPath("$.name").value("New Name"));
|
||||||
.andExpect(jsonPath("$.subdomain").value("new-sub"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class SiteResponseTest {
|
|||||||
.userId(userId)
|
.userId(userId)
|
||||||
.name("My Site")
|
.name("My Site")
|
||||||
.description("A test site")
|
.description("A test site")
|
||||||
.subdomain("mysite")
|
|
||||||
.status(SiteStatus.PUBLISHED)
|
.status(SiteStatus.PUBLISHED)
|
||||||
.publishedAt(now)
|
.publishedAt(now)
|
||||||
.createdAt(now)
|
.createdAt(now)
|
||||||
@@ -35,7 +34,6 @@ class SiteResponseTest {
|
|||||||
assertEquals(userId, response.getUserId());
|
assertEquals(userId, response.getUserId());
|
||||||
assertEquals("My Site", response.getName());
|
assertEquals("My Site", response.getName());
|
||||||
assertEquals("A test site", response.getDescription());
|
assertEquals("A test site", response.getDescription());
|
||||||
assertEquals("mysite", response.getSubdomain());
|
|
||||||
assertEquals(SiteStatus.PUBLISHED, response.getStatus());
|
assertEquals(SiteStatus.PUBLISHED, response.getStatus());
|
||||||
assertEquals(now, response.getPublishedAt());
|
assertEquals(now, response.getPublishedAt());
|
||||||
assertEquals(now, response.getCreatedAt());
|
assertEquals(now, response.getCreatedAt());
|
||||||
@@ -54,7 +52,6 @@ class SiteResponseTest {
|
|||||||
SiteResponse response = SiteResponse.from(site);
|
SiteResponse response = SiteResponse.from(site);
|
||||||
|
|
||||||
assertNull(response.getDescription());
|
assertNull(response.getDescription());
|
||||||
assertNull(response.getSubdomain());
|
|
||||||
assertNull(response.getPublishedAt());
|
assertNull(response.getPublishedAt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,30 +60,4 @@ class SiteRepositoryTest {
|
|||||||
assertTrue(sites.isEmpty());
|
assertTrue(sites.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void findBySubdomain() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("Site")
|
|
||||||
.subdomain("mysubdomain")
|
|
||||||
.build();
|
|
||||||
siteRepository.save(site);
|
|
||||||
|
|
||||||
Optional<Site> found = siteRepository.findBySubdomain("mysubdomain");
|
|
||||||
assertTrue(found.isPresent());
|
|
||||||
assertEquals("Site", found.get().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void existsBySubdomain() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("Site")
|
|
||||||
.subdomain("exists-sub")
|
|
||||||
.build();
|
|
||||||
siteRepository.save(site);
|
|
||||||
|
|
||||||
assertTrue(siteRepository.existsBySubdomain("exists-sub"));
|
|
||||||
assertFalse(siteRepository.existsBySubdomain("no-sub"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.krrishg.service;
|
package com.krrishg.service;
|
||||||
|
|
||||||
|
import com.krrishg.model.SelfHostedConfig;
|
||||||
import com.krrishg.model.Site;
|
import com.krrishg.model.Site;
|
||||||
import com.krrishg.model.SiteStatus;
|
import com.krrishg.model.SiteStatus;
|
||||||
import com.krrishg.support.FakeSelfHostedConfigRepository;
|
import com.krrishg.support.FakeSelfHostedConfigRepository;
|
||||||
@@ -14,8 +15,6 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
|
|
||||||
class DomainServiceTest {
|
class DomainServiceTest {
|
||||||
|
|
||||||
private static final String SITE_DOMAIN = "indie.example.com";
|
|
||||||
|
|
||||||
private FakeSiteRepository siteRepository;
|
private FakeSiteRepository siteRepository;
|
||||||
private FakeSelfHostedConfigRepository selfHostedConfigRepository;
|
private FakeSelfHostedConfigRepository selfHostedConfigRepository;
|
||||||
private DomainService domainService;
|
private DomainService domainService;
|
||||||
@@ -24,34 +23,33 @@ class DomainServiceTest {
|
|||||||
void setUp() {
|
void setUp() {
|
||||||
siteRepository = new FakeSiteRepository();
|
siteRepository = new FakeSiteRepository();
|
||||||
selfHostedConfigRepository = new FakeSelfHostedConfigRepository();
|
selfHostedConfigRepository = new FakeSelfHostedConfigRepository();
|
||||||
domainService = new DomainService(siteRepository, selfHostedConfigRepository, SITE_DOMAIN);
|
domainService = new DomainService(siteRepository, selfHostedConfigRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void resolveSiteReturnsSiteWhenSubdomainMatches() {
|
void resolveSiteReturnsSiteForSelfHostedDomain() {
|
||||||
Site site = Site.builder()
|
Site site = Site.builder()
|
||||||
.userId(UUID.randomUUID())
|
.userId(UUID.randomUUID())
|
||||||
.name("My Site")
|
.name("My Site")
|
||||||
.subdomain("mysite")
|
|
||||||
.status(SiteStatus.DRAFT)
|
.status(SiteStatus.DRAFT)
|
||||||
.build();
|
.build();
|
||||||
siteRepository.save(site);
|
siteRepository.save(site);
|
||||||
|
|
||||||
Optional<Site> result = domainService.resolveSite("mysite.indie.example.com");
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.siteId(site.getId())
|
||||||
|
.domain("www.example.com")
|
||||||
|
.build();
|
||||||
|
selfHostedConfigRepository.save(config);
|
||||||
|
|
||||||
|
Optional<Site> result = domainService.resolveSite("www.example.com");
|
||||||
|
|
||||||
assertTrue(result.isPresent());
|
assertTrue(result.isPresent());
|
||||||
assertEquals("mysite", result.get().getSubdomain());
|
assertEquals(site.getId(), result.get().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void resolveSiteReturnsEmptyForUnknownSubdomain() {
|
void resolveSiteReturnsEmptyForUnknownHostname() {
|
||||||
Optional<Site> result = domainService.resolveSite("unknown.indie.example.com");
|
Optional<Site> result = domainService.resolveSite("unknown.example.com");
|
||||||
assertTrue(result.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void resolveSiteReturnsEmptyForNonMatchingHostname() {
|
|
||||||
Optional<Site> result = domainService.resolveSite("example.com");
|
|
||||||
assertTrue(result.isEmpty());
|
assertTrue(result.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,73 +60,8 @@ class DomainServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void resolveSiteReturnsEmptyWhenSubdomainContainsDots() {
|
void resolveSiteReturnsEmptyWhenHostnameIsBlank() {
|
||||||
Site site = Site.builder()
|
Optional<Site> result = domainService.resolveSite(" ");
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("My Site")
|
|
||||||
.subdomain("mysite")
|
|
||||||
.status(SiteStatus.DRAFT)
|
|
||||||
.build();
|
|
||||||
siteRepository.save(site);
|
|
||||||
|
|
||||||
Optional<Site> result = domainService.resolveSite("mysite.staging.indie.example.com");
|
|
||||||
assertTrue(result.isEmpty());
|
assertTrue(result.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void resolveSiteIsCaseInsensitiveOnHostname() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("My Site")
|
|
||||||
.subdomain("mysite")
|
|
||||||
.status(SiteStatus.DRAFT)
|
|
||||||
.build();
|
|
||||||
siteRepository.save(site);
|
|
||||||
|
|
||||||
Optional<Site> result = domainService.resolveSite("MySite.indie.example.com");
|
|
||||||
assertTrue(result.isPresent());
|
|
||||||
assertEquals("mysite", result.get().getSubdomain());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void isSubdomainAvailableReturnsTrueWhenNotTaken() {
|
|
||||||
assertTrue(domainService.isSubdomainAvailable("available"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void isSubdomainAvailableReturnsFalseWhenTaken() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("My Site")
|
|
||||||
.subdomain("taken")
|
|
||||||
.status(SiteStatus.DRAFT)
|
|
||||||
.build();
|
|
||||||
siteRepository.save(site);
|
|
||||||
|
|
||||||
assertFalse(domainService.isSubdomainAvailable("taken"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getSiteUrlReturnsHttpsUrlWithSubdomain() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("My Site")
|
|
||||||
.subdomain("mysite")
|
|
||||||
.status(SiteStatus.DRAFT)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
String url = domainService.getSiteUrl(site);
|
|
||||||
assertEquals("https://mysite.indie.example.com", url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getSiteUrlReturnsNullWhenNoSubdomain() {
|
|
||||||
Site site = Site.builder()
|
|
||||||
.userId(UUID.randomUUID())
|
|
||||||
.name("My Site")
|
|
||||||
.status(SiteStatus.DRAFT)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
assertNull(domainService.getSiteUrl(site));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.krrishg.repository.SiteRepository;
|
|||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class FakeSiteRepository extends InMemoryRepository<Site, UUID> implements SiteRepository {
|
public class FakeSiteRepository extends InMemoryRepository<Site, UUID> implements SiteRepository {
|
||||||
@@ -33,17 +32,4 @@ public class FakeSiteRepository extends InMemoryRepository<Site, UUID> implement
|
|||||||
.sorted(Comparator.comparing(Site::getCreatedAt).reversed())
|
.sorted(Comparator.comparing(Site::getCreatedAt).reversed())
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Site> findBySubdomain(String subdomain) {
|
|
||||||
return store.values().stream()
|
|
||||||
.filter(s -> subdomain.equals(s.getSubdomain()))
|
|
||||||
.findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean existsBySubdomain(String subdomain) {
|
|
||||||
return store.values().stream()
|
|
||||||
.anyMatch(s -> subdomain.equals(s.getSubdomain()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user