Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/com/uid2/admin/vertx/Endpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public enum Endpoints {
API_SERVICE_ADD("/api/service/add"),
API_SERVICE_UPDATE("/api/service/update"),
API_SERVICE_DELETE("/api/service/delete"),
API_SERVICE_REMOVE_LINK_ID_REGEX("/api/service/remove-link-id-regex"),

API_SHARING_LISTS("/api/sharing/lists"),
API_SHARING_LIST_SITEID("/api/sharing/list/:siteId"),
Expand Down
135 changes: 89 additions & 46 deletions src/main/java/com/uid2/admin/vertx/service/ServiceService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

import static com.uid2.admin.vertx.Endpoints.*;
Expand Down Expand Up @@ -67,6 +69,11 @@ public void setupRoutes(Router router) {
this.handleDelete(ctx);
}
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.SUPER_USER));
router.post(API_SERVICE_REMOVE_LINK_ID_REGEX.toString()).blockingHandler(auth.handle((ctx) -> {
synchronized (writeLock) {
this.handleRemoveLinkIdRegex(ctx);
}
}, new AuditParams(Collections.emptyList(), List.of("service_id")), Role.PRIVILEGED));
}

private void handleServiceListAll(RoutingContext rc) {
Expand Down Expand Up @@ -113,6 +120,7 @@ private void handleServiceAdd(RoutingContext rc) {
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
JsonArray rolesSpec = body.getJsonArray("roles");
String linkIdRegex = body.getString("link_id_regex");
if (siteId == null || name == null || rolesSpec == null || rolesSpec.isEmpty()) {
ResponseUtil.error(rc, 400, "required parameters: site_id, name, roles");
return;
Expand Down Expand Up @@ -147,11 +155,20 @@ private void handleServiceAdd(RoutingContext rc) {
return;
}

if (linkIdRegex != null && !linkIdRegex.isBlank()) {
if (!isValidRegex(linkIdRegex)) {
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
return;
}
} else {
linkIdRegex = null;
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());
final int serviceId = 1 + services.stream().mapToInt(Service::getServiceId).max().orElse(0);
Service service = new Service(serviceId, siteId, name, roles);
Service service = new Service(serviceId, siteId, name, roles, linkIdRegex);

services.add(service);

Expand All @@ -163,17 +180,17 @@ private void handleServiceAdd(RoutingContext rc) {
}
}

// Can update the site_id, name and roles
// Can update the site_id, name, roles, and link_id_regex
private void handleUpdate(RoutingContext rc) {
try {
serviceProvider.loadContent();
Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled

JsonObject body = rc.body().asJsonObject();
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return;
}
Integer serviceId = body.getInteger("service_id");
Integer siteId = body.getInteger("site_id");
String name = body.getString("name");
String linkIdRegex = body.getString("link_id_regex");

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

if (serviceId == null) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return;
}

final Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return;
}
int serviceId = service.getServiceId();

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

if (linkIdRegex != null && !linkIdRegex.isBlank()) {
if (!isValidRegex(linkIdRegex)) {
ResponseUtil.error(rc, 400, "invalid parameter: link_id_regex; not a valid regex");
return;
}
service.setLinkIdRegex(linkIdRegex);
}

if (siteId != null && siteId != 0) {
service.setSiteId(siteId);
}
Expand All @@ -234,10 +250,7 @@ private void handleUpdate(RoutingContext rc) {
service.setName(name);
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());

List<Service> services = getSortedServices();

storeWriter.upload(services, null);

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

private void handleDelete(RoutingContext rc) {
final int serviceId;
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return;
}
serviceId = body.getInteger("service_id", -1);
if (serviceId == -1) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return;
}

try {
serviceProvider.loadContent();

Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return;
}

final List<Service> services = this.serviceProvider.getAllServices()
.stream().sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());

Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled
List<Service> services = getSortedServices();
services.remove(service);

storeWriter.upload(services, null);

rc.response().end(toJson(service).encodePrettily());
} catch (Exception e) {
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
}
}

private void handleRemoveLinkIdRegex(RoutingContext rc) {
try {
serviceProvider.loadContent();
Service service = findServiceFromRequest(rc);
if (service == null) return; // error already handled
service.setLinkIdRegex(null);
List<Service> services = getSortedServices();
storeWriter.upload(services, null);
rc.response().end(toJson(service).encodePrettily());
} catch (Exception e) {
ResponseUtil.errorInternal(rc, "Internal Server Error", e);
}
}

private JsonObject toJson(Service s) {
Expand All @@ -290,6 +294,7 @@ private JsonObject toJson(Service s) {
jsonObject.put("site_id", s.getSiteId());
jsonObject.put("name", s.getName());
jsonObject.put("roles", s.getRoles());
jsonObject.put("link_id_regex", s.getLinkIdRegex());
return jsonObject;
}

Expand All @@ -302,4 +307,42 @@ private boolean siteHasService(Integer siteId, String name, int serviceId) {
&& serviceProvider.getAllServices().stream().anyMatch(s -> s.getServiceId() != serviceId
&& s.getSiteId() == siteId && s.getName().equals(name));
}


private Service findServiceFromRequest(RoutingContext rc) {
JsonObject body = rc.body() != null ? rc.body().asJsonObject() : null;
if (body == null) {
ResponseUtil.error(rc, 400, "json payload required but not provided");
return null;
}

int serviceId = body.getInteger("service_id", -1);
if (serviceId == -1) {
ResponseUtil.error(rc, 400, "required parameters: service_id");
return null;
}

Service service = serviceProvider.getService(serviceId);
if (service == null) {
ResponseUtil.error(rc, 404, "failed to find a service for service_id: " + serviceId);
return null;
}
return service;
}

private List<Service> getSortedServices() {
return serviceProvider.getAllServices()
.stream()
.sorted(Comparator.comparingInt(Service::getServiceId))
.collect(Collectors.toList());
}

private boolean isValidRegex(String regex) {
try {
Pattern.compile(regex);
return true;
} catch (PatternSyntaxException e) {
return false;
}
}
}
Loading
Loading