diff --git a/pom.xml b/pom.xml
index 612bd1e2..c38f606c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
1.12.2
5.11.2
- 10.7.14
+ 10.8.0
0.5.10
${project.version}
diff --git a/src/main/java/com/uid2/admin/vertx/service/ServiceLinkService.java b/src/main/java/com/uid2/admin/vertx/service/ServiceLinkService.java
index 109f7b57..44dee73a 100644
--- a/src/main/java/com/uid2/admin/vertx/service/ServiceLinkService.java
+++ b/src/main/java/com/uid2/admin/vertx/service/ServiceLinkService.java
@@ -162,6 +162,7 @@ private void handleServiceLinkUpdate(RoutingContext rc) {
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
JsonArray rolesJson = body.getJsonArray("roles");
+ Boolean disabled = body.getBoolean("disabled");
if (siteId == null || serviceId == null || linkId == null || linkId.isEmpty()) {
ResponseUtil.error(rc, 400, "required parameters: site_id, service_id, link_id");
@@ -195,6 +196,10 @@ private void handleServiceLinkUpdate(RoutingContext rc) {
serviceLink.setName(name);
}
+ if (disabled != null) {
+ serviceLink.setDisabled(disabled);
+ }
+
if (rolesJson != null && !rolesJson.isEmpty()) {
final Set roles;
try {
@@ -259,6 +264,7 @@ private JsonObject toJson(ServiceLink s) {
jsonObject.put("site_id", s.getSiteId());
jsonObject.put("name", s.getName());
jsonObject.put("roles", s.getRoles());
+ jsonObject.put("disabled", s.isDisabled());
return jsonObject;
}
diff --git a/src/main/java/com/uid2/admin/vertx/service/ServiceService.java b/src/main/java/com/uid2/admin/vertx/service/ServiceService.java
index 0f4f7239..2f989d09 100644
--- a/src/main/java/com/uid2/admin/vertx/service/ServiceService.java
+++ b/src/main/java/com/uid2/admin/vertx/service/ServiceService.java
@@ -191,6 +191,7 @@ private void handleUpdate(RoutingContext rc) {
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
String linkIdRegex = body.getString("link_id_regex");
+ Boolean disabled = body.getBoolean("disabled");
JsonArray rolesSpec = null;
if (body.getString("roles") != null && !body.getString("roles").isEmpty()) {
@@ -242,6 +243,10 @@ private void handleUpdate(RoutingContext rc) {
service.setLinkIdRegex(linkIdRegex);
}
+ if (disabled != null) {
+ service.setDisabled(disabled);
+ }
+
if (siteId != null && siteId != 0) {
service.setSiteId(siteId);
}
@@ -295,6 +300,7 @@ private JsonObject toJson(Service s) {
jsonObject.put("name", s.getName());
jsonObject.put("roles", s.getRoles());
jsonObject.put("link_id_regex", s.getLinkIdRegex());
+ jsonObject.put("disabled", s.isDisabled());
return jsonObject;
}
diff --git a/src/test/java/com/uid2/admin/vertx/ServiceLinkServiceTest.java b/src/test/java/com/uid2/admin/vertx/ServiceLinkServiceTest.java
index 5d8ae1ad..c35df412 100644
--- a/src/test/java/com/uid2/admin/vertx/ServiceLinkServiceTest.java
+++ b/src/test/java/com/uid2/admin/vertx/ServiceLinkServiceTest.java
@@ -13,6 +13,7 @@
import io.vertx.junit5.VertxTestContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
@@ -387,6 +388,34 @@ void updateServiceLink_updateNameOnly_succeeds(Vertx vertx, VertxTestContext tes
});
}
+ @Test
+ void updateServiceLink_updateDisabledOnly_succeeds(Vertx vertx, VertxTestContext testContext) {
+ fakeAuth(Role.MAINTAINER);
+
+ setSites(new Site(123, "name1", false));
+ setServices(new Service(1, 123, "name1", Set.of(Role.MAINTAINER, Role.MAPPER)));
+ ServiceLink existingLink = new ServiceLink("link1", 1, 123, "name1", Set.of(Role.MAPPER));
+ setServiceLinks(existingLink);
+
+ JsonObject jo = new JsonObject();
+ jo.put("link_id", "link1");
+ jo.put("service_id", 1);
+ jo.put("site_id", 123);
+ jo.put("disabled", true);
+
+ ServiceLink expected = new ServiceLink("link1", 1, 123, "name1", Set.of(Role.MAPPER));
+ expected.setDisabled(true);
+
+ post(vertx, testContext, "api/service_link/update", jo.encode(), response -> {
+ assertEquals(200, response.statusCode());
+ checkServiceLinkJson(expected, response.bodyAsJsonObject());
+ verify(serviceStoreWriter, never()).upload(null, null);
+ verify(serviceLinkStoreWriter, times(1)).upload(List.of(expected), null);
+
+ testContext.completeNow();
+ });
+ }
+
@Test
void updateServiceLink_updateRoleOnly_succeeds(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.MAINTAINER);
@@ -442,6 +471,35 @@ void updateServiceLink_updateRoleAndName_succeeds(Vertx vertx, VertxTestContext
});
}
+ @Test
+ void updateServiceLink_updateRoleNameDisabled_succeeds(Vertx vertx, VertxTestContext testContext) {
+ fakeAuth(Role.MAINTAINER);
+
+ setSites(new Site(123, "name1", false));
+ setServices(new Service(1, 123, "name1", Set.of(Role.MAINTAINER, Role.MAPPER, Role.SHARER)));
+ ServiceLink existingLink = new ServiceLink("link1", 1, 123, "name1", Set.of(Role.MAPPER));
+ setServiceLinks(existingLink);
+
+ JsonObject jo = new JsonObject();
+ jo.put("link_id", "link1");
+ jo.put("service_id", 1);
+ jo.put("site_id", 123);
+ jo.put("name", "newname");
+ jo.put("roles", JsonArray.of(Role.MAPPER, Role.SHARER));
+ jo.put("disabled", true);
+
+ ServiceLink expected = new ServiceLink("link1", 1, 123, "newname", Set.of(Role.MAPPER, Role.SHARER), true);
+
+ post(vertx, testContext, "api/service_link/update", jo.encode(), response -> {
+ assertEquals(200, response.statusCode());
+ checkServiceLinkJson(expected, response.bodyAsJsonObject());
+ verify(serviceStoreWriter, never()).upload(null, null);
+ verify(serviceLinkStoreWriter, times(1)).upload(List.of(expected), null);
+
+ testContext.completeNow();
+ });
+ }
+
@Test
void updateServiceLink_roleDoesNotExist_returnsError(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.MAINTAINER);
@@ -622,20 +680,20 @@ void addServiceLink_linkIdRegex_validation(String linkIdRegex, String linkId, bo
private static java.util.stream.Stream linkIdRegexCases() {
return java.util.stream.Stream.of(
- org.junit.jupiter.params.provider.Arguments.of("link[0-9]+", "invalidLink", false),
- org.junit.jupiter.params.provider.Arguments.of("link[0-9]+", "link42", true),
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "XY12345", true), // snowflake valid
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "UID2_ENVIRONMENT", true), // snowflake valid
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "xy12345", false), // snowflake invalid, lowercase
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "X", true), // snowflake valid, minimum length
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "X".repeat(256), true), // snowflake valid, maximum length
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "X".repeat(257), false), // snowflake invalid, exceeds maximum length
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", " XY12345", false), // snowflake invalid, leading whitespace
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "XY12345 ", false), // snowflake invalid, trailing whitespace
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "XY 12345", false), // snowflake invalid, whitespace in the middle
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "", false), // snowflake invalid, empty
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", " ", false), // snowflake invalid, just whitespace
- org.junit.jupiter.params.provider.Arguments.of("^[A-Z0-9_]{1,256}$", "XY_12345", true) // snowflake valid, used underscore
+ Arguments.of("link[0-9]+", "invalidLink", false),
+ Arguments.of("link[0-9]+", "link42", true),
+ Arguments.of("^[A-Z0-9_]{1,256}$", "XY12345", true), // snowflake valid
+ Arguments.of("^[A-Z0-9_]{1,256}$", "UID2_ENVIRONMENT", true), // snowflake valid
+ Arguments.of("^[A-Z0-9_]{1,256}$", "xy12345", false), // snowflake invalid, lowercase
+ Arguments.of("^[A-Z0-9_]{1,256}$", "X", true), // snowflake valid, minimum length
+ Arguments.of("^[A-Z0-9_]{1,256}$", "X".repeat(256), true), // snowflake valid, maximum length
+ Arguments.of("^[A-Z0-9_]{1,256}$", "X".repeat(257), false), // snowflake invalid, exceeds maximum length
+ Arguments.of("^[A-Z0-9_]{1,256}$", " XY12345", false), // snowflake invalid, leading whitespace
+ Arguments.of("^[A-Z0-9_]{1,256}$", "XY12345 ", false), // snowflake invalid, trailing whitespace
+ Arguments.of("^[A-Z0-9_]{1,256}$", "XY 12345", false), // snowflake invalid, whitespace in the middle
+ Arguments.of("^[A-Z0-9_]{1,256}$", "", false), // snowflake invalid, empty
+ Arguments.of("^[A-Z0-9_]{1,256}$", " ", false), // snowflake invalid, just whitespace
+ Arguments.of("^[A-Z0-9_]{1,256}$", "XY_12345", true) // snowflake valid, used underscore
);
}
}
diff --git a/src/test/java/com/uid2/admin/vertx/ServiceServiceTest.java b/src/test/java/com/uid2/admin/vertx/ServiceServiceTest.java
index 36f84260..713a01bc 100644
--- a/src/test/java/com/uid2/admin/vertx/ServiceServiceTest.java
+++ b/src/test/java/com/uid2/admin/vertx/ServiceServiceTest.java
@@ -580,6 +580,26 @@ void updateName(Vertx vertx, VertxTestContext testContext) {
});
}
+ @Test
+ void updateDisabled(Vertx vertx, VertxTestContext testContext) {
+ fakeAuth(Role.PRIVILEGED);
+
+ Service existingService = new Service(1, 123, "name1", Set.of(Role.MAINTAINER));
+ setServices(existingService);
+
+ JsonObject jo = new JsonObject();
+ jo.put("service_id", 1);
+ jo.put("disabled", true);
+
+ post(vertx, testContext, "api/service/update", jo.encode(), response -> {
+ assertEquals(200, response.statusCode());
+ existingService.setDisabled(true);
+ checkServiceJson(existingService, response.bodyAsJsonObject());
+ verify(serviceStoreWriter, times(1)).upload(List.of(existingService), null);
+ testContext.completeNow();
+ });
+ }
+
@Test
void updateSiteId(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.PRIVILEGED);
@@ -600,6 +620,32 @@ void updateSiteId(Vertx vertx, VertxTestContext testContext) {
});
}
+ @Test
+ void updateNameDisabledSiteIdRoles(Vertx vertx, VertxTestContext testContext) {
+ fakeAuth(Role.PRIVILEGED);
+
+ Service existingService = new Service(1, 123, "name1", Set.of(Role.MAINTAINER));
+ setServices(existingService);
+
+ JsonObject jo = new JsonObject();
+ jo.put("service_id", 1);
+ jo.put("site_id", 456);
+ jo.put("name", "newname");
+ jo.put("disabled", true);
+ jo.put("roles", JsonArray.of(Role.MAINTAINER, Role.MAPPER, Role.SHARER));
+
+ post(vertx, testContext, "api/service/update", jo.encode(), response -> {
+ assertEquals(200, response.statusCode());
+ existingService.setSiteId(456);
+ existingService.setName("newname");
+ existingService.setDisabled(true);
+ existingService.setRoles(Set.of(Role.MAINTAINER, Role.MAPPER, Role.SHARER));
+ checkServiceJson(existingService, response.bodyAsJsonObject());
+ verify(serviceStoreWriter, times(1)).upload(List.of(existingService), null);
+ testContext.completeNow();
+ });
+ }
+
@Test
void updateWithEmptyValues(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.PRIVILEGED);
diff --git a/webroot/adm/service-link.html b/webroot/adm/service-link.html
index eacd4379..7e4e6c36 100644
--- a/webroot/adm/service-link.html
+++ b/webroot/adm/service-link.html
@@ -75,6 +75,12 @@ UID2 Env - Service Link Management
]
};
+ const disabledInput = {
+ name: 'disabled',
+ label: 'Disable Service Link',
+ type: 'checkbox'
+ };
+
const operationConfig = {
read: [
{
@@ -141,7 +147,8 @@ UID2 Env - Service Link Management
serviceIdInput,
siteIdInput,
linkNameInput,
- rolesInput
+ rolesInput,
+ disabledInput,
],
apiCall: {
method: 'POST',
@@ -156,7 +163,8 @@ UID2 Env - Service Link Management
service_id: parseInt(inputs.serviceId),
site_id: parseInt(inputs.siteId),
name: inputs.linkName || '',
- roles: rolesArray
+ roles: rolesArray,
+ disabled: typeof inputs.disabled === 'boolean' ? inputs.disabled : undefined,
};
}
}
diff --git a/webroot/adm/service.html b/webroot/adm/service.html
index e549403e..cf3bbc83 100644
--- a/webroot/adm/service.html
+++ b/webroot/adm/service.html
@@ -74,6 +74,12 @@ UID2 Env - Service Management
label: 'Link Id Regex'
};
+ const disabledInput = {
+ name: 'disabled',
+ label: 'Disable Service',
+ type: 'checkbox'
+ };
+
const operationConfig = {
read: [
{
@@ -142,7 +148,8 @@ UID2 Env - Service Management
{...serviceNameInput, required: false},
{...siteIdInput, required: false},
{...rolesInput, required: false},
- linkIdRegexInput
+ linkIdRegexInput,
+ disabledInput
],
apiCall: {
method: 'POST',
@@ -157,6 +164,7 @@ UID2 Env - Service Management
if (rolesArray.length > 0) payload.roles = rolesArray;
if (inputs.linkIdRegex) payload.link_id_regex = inputs.linkIdRegex;
+ if (typeof inputs.disabled === 'boolean') payload.disabled = inputs.disabled;
return payload;
}
}