refactored to make use of the ServiceType enum throughout backend and frontend for typesafety

This commit is contained in:
2026-06-24 23:25:18 +02:00
parent 38c72d1bb8
commit fb64a7787f
24 changed files with 278 additions and 263 deletions
@@ -2,5 +2,5 @@ package com.vaessl.app.connection;
import java.time.Instant;
public record AuthResponse(String serviceType, Instant expiresAt) {
public record AuthResponse(ServiceType serviceType, Instant expiresAt) {
}
@@ -53,19 +53,24 @@ public class ConnectionController {
Collections.list(session.getAttributeNames()).stream()
.filter(k -> k.endsWith(SessionKeys.CONNECTION_ID_SUFFIX))
.forEach(k -> {
String serviceType = k.replace(SessionKeys.CONNECTION_ID_SUFFIX, "");
Long id = (Long) session.getAttribute(k);
ConnectionStatusResponse status =
connectionService.getConnectionStatus(serviceType, id);
if (status != null)
statuses.add(status);
String name = k.replace(SessionKeys.CONNECTION_ID_SUFFIX, "");
try {
ServiceType serviceType = ServiceType.valueOf(name);
Long id = (Long) session.getAttribute(k);
ConnectionStatusResponse status =
connectionService.getConnectionStatus(serviceType, id);
if (status != null)
statuses.add(status);
} catch (IllegalArgumentException _) {
// stale session key from an old or removed service type — skip it
}
});
return ResponseEntity.ok(statuses);
}
@DeleteMapping("/connections/{serviceType}")
public ResponseEntity<Void> logout(@PathVariable("serviceType") String serviceType,
public ResponseEntity<Void> logout(@PathVariable("serviceType") ServiceType serviceType,
HttpServletRequest httpReq) {
HttpSession session = httpReq.getSession(false);
@@ -3,9 +3,10 @@ package com.vaessl.app.connection;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
public record ConnectionRequest(@NotBlank(message = "App URL is mandatory") String appUrl,
@NotBlank(message = "Service type is mandatory") String serviceType,
@NotNull(message = "Service type is mandatory") ServiceType serviceType,
String username, String password, String apiKey,
@JsonProperty(defaultValue = "false") Boolean stayLoggedIn) {
@@ -15,7 +16,7 @@ public record ConnectionRequest(@NotBlank(message = "App URL is mandatory") Stri
}
}
public ConnectionRequest(String appUrl, String serviceType, String username,
public ConnectionRequest(String appUrl, ServiceType serviceType, String username,
String password, Boolean stayLoggedIn) {
this(appUrl, serviceType, username, password, null, stayLoggedIn);
}
@@ -12,7 +12,7 @@ import com.vaessl.app.exception.WrongServiceTypeException;
@Service
public class ConnectionService {
private final Map<String, ConnectionProvider> providerRegistry;
private final Map<ServiceType, ConnectionProvider> providerRegistry;
private final ConnectionRepository cRepository;
@@ -48,7 +48,7 @@ public class ConnectionService {
return new LoginResult(saved.getId(), response.expiresAt());
}
public ConnectionStatusResponse getConnectionStatus(String serviceType, Long connectionId) {
public ConnectionStatusResponse getConnectionStatus(ServiceType serviceType, Long connectionId) {
ConnectionEntity entity = cRepository.findById(connectionId).orElse(null);
if (entity == null)
return null;
@@ -57,7 +57,7 @@ public class ConnectionService {
Instant expiresAt = (provider != null) ? provider.getTokenExpiry(entity) : null;
boolean connected = expiresAt == null || expiresAt.isAfter(Instant.now());
return new ConnectionStatusResponse(serviceType, entity.getAppUrl(), entity.getUsername(),
return new ConnectionStatusResponse(serviceType.name(), entity.getAppUrl(), entity.getUsername(),
expiresAt, connected);
}
}
@@ -44,8 +44,8 @@ public class HomeboxConnectionProvider implements ConnectionProvider {
}
@Override
public String getServiceType() {
return "HOMEBOX";
public ServiceType getServiceType() {
return ServiceType.HOMEBOX;
}
@Override
@@ -6,5 +6,5 @@ public interface ServiceProvider {
* Returns the service type key used to look up this provider in a registry, e.g.
* {@code "HOMEBOX"}.
*/
String getServiceType();
ServiceType getServiceType();
}
@@ -1,14 +1,5 @@
package com.vaessl.app.connection;
import lombok.Getter;
@Getter
public enum ServiceType {
HOMEBOX("HOMEBOX");
private final String value;
private ServiceType(String value) {
this.value = value;
}
HOMEBOX;
}
@@ -6,7 +6,7 @@ public final class SessionKeys {
private SessionKeys() {}
public static String connectionId(String serviceType) {
return serviceType + CONNECTION_ID_SUFFIX;
public static String connectionId(ServiceType serviceType) {
return serviceType.name() + CONNECTION_ID_SUFFIX;
}
}
@@ -12,20 +12,15 @@ import org.springframework.web.client.RestClient;
import com.vaessl.app.connection.ConnectionEntity;
import com.vaessl.app.connection.ConnectionRepository;
import com.vaessl.app.connection.HomeboxEntity;
import com.vaessl.app.connection.ServiceType;
import com.vaessl.app.exception.ConnectionNotFoundException;
import com.vaessl.app.exception.RemoteApiException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.vaessl.app.connection.Endpoint.*;
@Component
public class HomeboxSearchProvider implements SearchProvider {
// TODO: Remove logger before merge
private static final Logger log = LoggerFactory.getLogger(HomeboxSearchProvider.class);
private final RestClient.Builder restClientBuilder;
private final ConnectionRepository cRepository;
@@ -37,8 +32,8 @@ public class HomeboxSearchProvider implements SearchProvider {
}
@Override
public String getServiceType() {
return "HOMEBOX";
public ServiceType getServiceType() {
return ServiceType.HOMEBOX;
}
@Override
@@ -71,8 +66,6 @@ public class HomeboxSearchProvider implements SearchProvider {
return new SearchResponse(id, title, description, extraSearchResponseData);
}).toList();
log.info("Search results for query '{}': {}", request.query(), items);
return new PageImpl<>(items, pageable, hbResponse.total());
}
@@ -1,7 +1,9 @@
package com.vaessl.app.search;
import com.vaessl.app.connection.ServiceType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
public record SearchRequest(@NotBlank String appUrl, @NotBlank String username, String query,
@NotBlank String serviceType) {
@NotNull ServiceType serviceType) {
}
@@ -7,13 +7,13 @@ import java.util.stream.Collectors;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.vaessl.app.connection.ServiceType;
import com.vaessl.app.exception.WrongServiceTypeException;
@Service
public class SearchService {
private final Map<String, SearchProvider> providerRegistry;
private final Map<ServiceType, SearchProvider> providerRegistry;
public SearchService(List<SearchProvider> providers) {
this.providerRegistry = Map.copyOf(providers.stream()