Skip to content

Commit d14c1d0

Browse files
authored
Merge pull request #514 from IABTechLab/ian-UID2-3134-add-link-id-regex-field-to-services
add link-id-regex field to services
2 parents 430af4b + 146aa5a commit d14c1d0

File tree

5 files changed

+244
-56
lines changed

5 files changed

+244
-56
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<!-- check micrometer.version vertx-micrometer-metrics consumes before bumping up -->
1717
<micrometer.version>1.12.2</micrometer.version>
1818
<junit-jupiter.version>5.11.2</junit-jupiter.version>
19-
<uid2-shared.version>10.1.0</uid2-shared.version>
19+
<uid2-shared.version>10.3.0</uid2-shared.version>
2020
<okta-jwt.version>0.5.10</okta-jwt.version>
2121
<image.version>${project.version}</image.version>
2222
</properties>

src/main/java/com/uid2/admin/vertx/Endpoints.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public enum Endpoints {
8282
API_SERVICE_ADD("/api/service/add"),
8383
API_SERVICE_UPDATE("/api/service/update"),
8484
API_SERVICE_DELETE("/api/service/delete"),
85+
API_SERVICE_REMOVE_LINK_ID_REGEX("/api/service/remove-link-id-regex"),
8586

8687
API_SHARING_LISTS("/api/sharing/lists"),
8788
API_SHARING_LIST_SITEID("/api/sharing/list/:siteId"),

src/main/java/com/uid2/admin/vertx/service/ServiceService.java

Lines changed: 89 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.slf4j.LoggerFactory;
2121

2222
import java.util.*;
23+
import java.util.regex.Pattern;
24+
import java.util.regex.PatternSyntaxException;
2325
import java.util.stream.Collectors;
2426

2527
import static com.uid2.admin.vertx.Endpoints.*;
@@ -67,6 +69,11 @@ public void setupRoutes(Router router) {
6769
this.handleDelete(ctx);
6870
}
6971
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.SUPER_USER));
72+
router.post(API_SERVICE_REMOVE_LINK_ID_REGEX.toString()).blockingHandler(auth.handle((ctx) -> {
73+
synchronized (writeLock) {
74+
this.handleRemoveLinkIdRegex(ctx);
75+
}
76+
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.PRIVILEGED));
7077
}
7178

7279
private void handleServiceListAll(RoutingContext rc) {
@@ -113,6 +120,7 @@ private void handleServiceAdd(RoutingContext rc) {
113120
Integer siteId = body.getInteger("site_id");
114121
String name = body.getString("name");
115122
JsonArray rolesSpec = body.getJsonArray("roles");
123+
String linkIdRegex = body.getString("link_id_regex");
116124
if (siteId == null || name == null || rolesSpec == null || rolesSpec.isEmpty()) {
117125
ResponseUtil.error(rc, 400, "required parameters: site_id, name, roles");
118126
return;
@@ -147,11 +155,20 @@ private void handleServiceAdd(RoutingContext rc) {
147155
return;
148156
}
149157

158+
if (linkIdRegex != null && !linkIdRegex.isBlank()) {
159+
if (!isValidRegex(linkIdRegex)) {
160+
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
161+
return;
162+
}
163+
} else {
164+
linkIdRegex = null;
165+
}
166+
150167
final List<Service> services = this.serviceProvider.getAllServices()
151168
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
152169
.collect(Collectors.toList());
153170
final int serviceId = 1 + services.stream().mapToInt(Service::getServiceId).max().orElse(0);
154-
Service service = new Service(serviceId, siteId, name, roles);
171+
Service service = new Service(serviceId, siteId, name, roles, linkIdRegex);
155172

156173
services.add(service);
157174

@@ -163,17 +180,17 @@ private void handleServiceAdd(RoutingContext rc) {
163180
}
164181
}
165182

166-
// Can update the site_id, name and roles
183+
// Can update the site_id, name, roles, and link_id_regex
167184
private void handleUpdate(RoutingContext rc) {
168185
try {
186+
serviceProvider.loadContent();
187+
Service service = findServiceFromRequest(rc);
188+
if (service == null) return; // error already handled
189+
169190
JsonObject body = rc.body().asJsonObject();
170-
if (body == null) {
171-
ResponseUtil.error(rc, 400, "json payload required but not provided");
172-
return;
173-
}
174-
Integer serviceId = body.getInteger("service_id");
175191
Integer siteId = body.getInteger("site_id");
176192
String name = body.getString("name");
193+
String linkIdRegex = body.getString("link_id_regex");
177194

178195
JsonArray rolesSpec = null;
179196
if (body.getString("roles") != null && !body.getString("roles").isEmpty()) {
@@ -185,16 +202,7 @@ private void handleUpdate(RoutingContext rc) {
185202
}
186203
}
187204

188-
if (serviceId == null) {
189-
ResponseUtil.error(rc, 400, "required parameters: service_id");
190-
return;
191-
}
192-
193-
final Service service = serviceProvider.getService(serviceId);
194-
if (service == null) {
195-
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
196-
return;
197-
}
205+
int serviceId = service.getServiceId();
198206

199207
// check that this does not create a duplicate service
200208
if (siteHasService(siteId, name, serviceId)) {
@@ -226,6 +234,14 @@ private void handleUpdate(RoutingContext rc) {
226234
service.setRoles(roles);
227235
}
228236

237+
if (linkIdRegex != null && !linkIdRegex.isBlank()) {
238+
if (!isValidRegex(linkIdRegex)) {
239+
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
240+
return;
241+
}
242+
service.setLinkIdRegex(linkIdRegex);
243+
}
244+
229245
if (siteId != null && siteId != 0) {
230246
service.setSiteId(siteId);
231247
}
@@ -234,10 +250,7 @@ private void handleUpdate(RoutingContext rc) {
234250
service.setName(name);
235251
}
236252

237-
final List<Service> services = this.serviceProvider.getAllServices()
238-
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
239-
.collect(Collectors.toList());
240-
253+
List<Service> services = getSortedServices();
241254

242255
storeWriter.upload(services, null);
243256

@@ -248,40 +261,31 @@ private void handleUpdate(RoutingContext rc) {
248261
}
249262

250263
private void handleDelete(RoutingContext rc) {
251-
final int serviceId;
252-
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
253-
if (body == null) {
254-
ResponseUtil.error(rc, 400, "json payload required but not provided");
255-
return;
256-
}
257-
serviceId = body.getInteger("service_id", -1);
258-
if (serviceId == -1) {
259-
ResponseUtil.error(rc, 400, "required parameters: service_id");
260-
return;
261-
}
262-
263264
try {
264265
serviceProvider.loadContent();
265-
266-
Service service = serviceProvider.getService(serviceId);
267-
if (service == null) {
268-
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
269-
return;
270-
}
271-
272-
final List<Service> services = this.serviceProvider.getAllServices()
273-
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
274-
.collect(Collectors.toList());
275-
266+
Service service = findServiceFromRequest(rc);
267+
if (service == null) return; // error already handled
268+
List<Service> services = getSortedServices();
276269
services.remove(service);
277-
278270
storeWriter.upload(services, null);
279-
280271
rc.response().end(toJson(service).encodePrettily());
281272
} catch (Exception e) {
282273
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
283274
}
275+
}
284276

277+
private void handleRemoveLinkIdRegex(RoutingContext rc) {
278+
try {
279+
serviceProvider.loadContent();
280+
Service service = findServiceFromRequest(rc);
281+
if (service == null) return; // error already handled
282+
service.setLinkIdRegex(null);
283+
List<Service> services = getSortedServices();
284+
storeWriter.upload(services, null);
285+
rc.response().end(toJson(service).encodePrettily());
286+
} catch (Exception e) {
287+
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
288+
}
285289
}
286290

287291
private JsonObject toJson(Service s) {
@@ -290,6 +294,7 @@ private JsonObject toJson(Service s) {
290294
jsonObject.put("site_id", s.getSiteId());
291295
jsonObject.put("name", s.getName());
292296
jsonObject.put("roles", s.getRoles());
297+
jsonObject.put("link_id_regex", s.getLinkIdRegex());
293298
return jsonObject;
294299
}
295300

@@ -302,4 +307,42 @@ private boolean siteHasService(Integer siteId, String name, int serviceId) {
302307
&& serviceProvider.getAllServices().stream().anyMatch(s -> s.getServiceId() != serviceId
303308
&& s.getSiteId() == siteId && s.getName().equals(name));
304309
}
310+
311+
312+
private Service findServiceFromRequest(RoutingContext rc) {
313+
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
314+
if (body == null) {
315+
ResponseUtil.error(rc, 400, "json payload required but not provided");
316+
return null;
317+
}
318+
319+
int serviceId = body.getInteger("service_id", -1);
320+
if (serviceId == -1) {
321+
ResponseUtil.error(rc, 400, "required parameters: service_id");
322+
return null;
323+
}
324+
325+
Service service = serviceProvider.getService(serviceId);
326+
if (service == null) {
327+
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
328+
return null;
329+
}
330+
return service;
331+
}
332+
333+
private List<Service> getSortedServices() {
334+
return serviceProvider.getAllServices()
335+
.stream()
336+
.sorted(Comparator.comparingInt(Service::getServiceId))
337+
.collect(Collectors.toList());
338+
}
339+
340+
private boolean isValidRegex(String regex) {
341+
try {
342+
Pattern.compile(regex);
343+
return true;
344+
} catch (PatternSyntaxException e) {
345+
return false;
346+
}
347+
}
305348
}

0 commit comments

Comments
 (0)