Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REST API] Add support for pagination in the get-role-mappings #4331

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
102 changes: 54 additions & 48 deletions app/src/main/java/io/apicurio/registry/rest/v3/AdminResourceImpl.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
package io.apicurio.registry.rest.v3;

import io.apicurio.common.apps.config.*;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_FOR_BROWSER;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_NAME;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_PRINCIPAL_ID;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_ROLE_MAPPING;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_RULE;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_RULE_TYPE;
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_UPDATE_ROLE;
import static io.apicurio.registry.util.DtoUtil.appAuthPropertyToRegistry;
import static io.apicurio.registry.util.DtoUtil.registryAuthPropertyToApp;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipInputStream;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.slf4j.Logger;

import io.apicurio.common.apps.config.Dynamic;
import io.apicurio.common.apps.config.DynamicConfigPropertyDef;
import io.apicurio.common.apps.config.DynamicConfigPropertyDto;
import io.apicurio.common.apps.config.DynamicConfigPropertyIndex;
import io.apicurio.common.apps.config.Info;
import io.apicurio.common.apps.logging.Logged;
import io.apicurio.common.apps.logging.audit.Audited;
import io.apicurio.registry.auth.Authorized;
Expand All @@ -10,21 +40,28 @@
import io.apicurio.registry.metrics.health.liveness.ResponseErrorLivenessCheck;
import io.apicurio.registry.metrics.health.readiness.ResponseTimeoutReadinessCheck;
import io.apicurio.registry.rest.MissingRequiredParameterException;
import io.apicurio.registry.rest.v3.beans.*;
import io.apicurio.registry.rest.v3.beans.ArtifactTypeInfo;
import io.apicurio.registry.rest.v3.beans.ConfigurationProperty;
import io.apicurio.registry.rest.v3.beans.DownloadRef;
import io.apicurio.registry.rest.v3.beans.RoleMapping;
import io.apicurio.registry.rest.v3.beans.RoleMappingSearchResults;
import io.apicurio.registry.rest.v3.beans.Rule;
import io.apicurio.registry.rest.v3.beans.UpdateConfigurationProperty;
import io.apicurio.registry.rest.v3.beans.UpdateRole;
import io.apicurio.registry.rest.v3.shared.DataExporter;
import io.apicurio.registry.rules.DefaultRuleDeletionException;
import io.apicurio.registry.rules.RulesProperties;
import io.apicurio.registry.storage.RegistryStorage;
import io.apicurio.registry.storage.dto.DownloadContextDto;
import io.apicurio.registry.storage.dto.DownloadContextType;
import io.apicurio.registry.storage.dto.RoleMappingDto;
import io.apicurio.registry.storage.dto.RoleMappingSearchResultsDto;
import io.apicurio.registry.storage.dto.RuleConfigurationDto;
import io.apicurio.registry.storage.error.ConfigPropertyNotFoundException;
import io.apicurio.registry.storage.error.InvalidPropertyValueException;
import io.apicurio.registry.storage.error.RuleNotFoundException;
import io.apicurio.registry.storage.impexp.EntityInputStream;
import io.apicurio.registry.types.Current;
import io.apicurio.registry.types.RoleType;
import io.apicurio.registry.types.RuleType;
import io.apicurio.registry.types.provider.ArtifactTypeUtilProviderFactory;
import io.apicurio.registry.utils.impexp.Entity;
Expand All @@ -36,24 +73,6 @@
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.slf4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipInputStream;

import static io.apicurio.common.apps.logging.audit.AuditingConstants.*;
import static io.apicurio.registry.util.DtoUtil.appAuthPropertyToRegistry;
import static io.apicurio.registry.util.DtoUtil.registryAuthPropertyToApp;

@ApplicationScoped
@Interceptors({ResponseErrorLivenessCheck.class, ResponseTimeoutReadinessCheck.class})
Expand Down Expand Up @@ -287,16 +306,21 @@ public void createRoleMapping(RoleMapping data) {
}

/**
* @see io.apicurio.registry.rest.v3.AdminResource#listRoleMappings()
* @see io.apicurio.registry.rest.v3.AdminResource#listRoleMappings(java.math.BigInteger, java.math.BigInteger)
*/
@Override
@Authorized(style=AuthorizedStyle.None, level=AuthorizedLevel.Admin)
@RoleBasedAccessApiOperation
public List<RoleMapping> listRoleMappings() {
List<RoleMappingDto> mappings = storage.getRoleMappings();
return mappings.stream().map(dto -> {
return dtoToRoleMapping(dto);
}).collect(Collectors.toList());
public RoleMappingSearchResults listRoleMappings(BigInteger limit, BigInteger offset) {
if (offset == null) {
offset = BigInteger.valueOf(0);
}
if (limit == null) {
limit = BigInteger.valueOf(20);
}

RoleMappingSearchResultsDto dto = storage.searchRoleMappings(offset.intValue(), limit.intValue());
return V3ApiUtil.dtoToRoleMappingSearchResults(dto);
}

/**
Expand All @@ -307,7 +331,7 @@ public List<RoleMapping> listRoleMappings() {
@RoleBasedAccessApiOperation
public RoleMapping getRoleMapping(String principalId) {
RoleMappingDto dto = storage.getRoleMapping(principalId);
return dtoToRoleMapping(dto);
return V3ApiUtil.dtoToRoleMapping(dto);
}

/**
Expand Down Expand Up @@ -352,7 +376,7 @@ public List<ConfigurationProperty> listConfigProperties() {
// on whether the value is actually configured and stored in the DB or not).
return dynamicPropertyIndex.getAcceptedPropertyNames().stream()
.sorted((pname1, pname2) -> pname1.compareTo(pname2))
.map(pname -> propsI.containsKey(pname) ? dtoToConfigurationProperty(dynamicPropertyIndex.getProperty(pname), propsI.get(pname)) : defToConfigurationProperty(dynamicPropertyIndex.getProperty(pname)))
.map(pname -> propsI.containsKey(pname) ? V3ApiUtil.dtoToConfigurationProperty(dynamicPropertyIndex.getProperty(pname), propsI.get(pname)) : defToConfigurationProperty(dynamicPropertyIndex.getProperty(pname)))
.collect(Collectors.toList());
}

Expand All @@ -369,7 +393,7 @@ public ConfigurationProperty getConfigProperty(String propertyName) {
if (dto == null) {
return defToConfigurationProperty(def);
} else {
return dtoToConfigurationProperty(def, dto);
return V3ApiUtil.dtoToConfigurationProperty(def, dto);
}
}

Expand Down Expand Up @@ -401,14 +425,6 @@ public void resetConfigProperty(String propertyName) {
storage.deleteConfigProperty(propertyName);
}

private static RoleMapping dtoToRoleMapping(RoleMappingDto dto) {
RoleMapping mapping = new RoleMapping();
mapping.setPrincipalId(dto.getPrincipalId());
mapping.setRole(RoleType.valueOf(dto.getRole()));
mapping.setPrincipalName(dto.getPrincipalName());
return mapping;
}


private static boolean isNullOrTrue(Boolean value) {
return value == null || value;
Expand All @@ -418,16 +434,6 @@ private String createDownloadHref(String downloadId) {
return "/apis/registry/v3/downloads/" + downloadId;
}

private static ConfigurationProperty dtoToConfigurationProperty(DynamicConfigPropertyDef def, DynamicConfigPropertyDto dto) {
ConfigurationProperty rval = new ConfigurationProperty();
rval.setName(def.getName());
rval.setValue(dto.getValue());
rval.setType(def.getType().getName());
rval.setLabel(def.getLabel());
rval.setDescription(def.getDescription());
return rval;
}

private ConfigurationProperty defToConfigurationProperty(DynamicConfigPropertyDef def) {
String propertyValue = config.getOptionalValue(def.getName(), String.class).orElse(def.getDefaultValue());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ public void deleteGroupById(String groupId) {
* @see io.apicurio.registry.rest.v3.GroupsResource#updateGroupById(java.lang.String, io.apicurio.registry.rest.v3.beans.EditableGroupMetaData)
*/
@Override
@Authorized(style = AuthorizedStyle.GroupOnly, level = AuthorizedLevel.Write)
public void updateGroupById(String groupId, EditableGroupMetaData data) {
requireParameter("groupId", groupId);

Expand Down
61 changes: 58 additions & 3 deletions app/src/main/java/io/apicurio/registry/rest/v3/V3ApiUtil.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
package io.apicurio.registry.rest.v3;

import io.apicurio.registry.rest.v3.beans.*;
import io.apicurio.registry.storage.dto.*;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Optional;
import java.util.stream.Collectors;

import io.apicurio.common.apps.config.DynamicConfigPropertyDef;
import io.apicurio.common.apps.config.DynamicConfigPropertyDto;
import io.apicurio.registry.rest.v3.beans.ArtifactMetaData;
import io.apicurio.registry.rest.v3.beans.ArtifactReference;
import io.apicurio.registry.rest.v3.beans.ArtifactSearchResults;
import io.apicurio.registry.rest.v3.beans.Comment;
import io.apicurio.registry.rest.v3.beans.ConfigurationProperty;
import io.apicurio.registry.rest.v3.beans.GroupMetaData;
import io.apicurio.registry.rest.v3.beans.GroupSearchResults;
import io.apicurio.registry.rest.v3.beans.RoleMapping;
import io.apicurio.registry.rest.v3.beans.RoleMappingSearchResults;
import io.apicurio.registry.rest.v3.beans.SearchedArtifact;
import io.apicurio.registry.rest.v3.beans.SearchedGroup;
import io.apicurio.registry.rest.v3.beans.SearchedVersion;
import io.apicurio.registry.rest.v3.beans.SortOrder;
import io.apicurio.registry.rest.v3.beans.VersionMetaData;
import io.apicurio.registry.rest.v3.beans.VersionSearchResults;
import io.apicurio.registry.storage.dto.ArtifactMetaDataDto;
import io.apicurio.registry.storage.dto.ArtifactReferenceDto;
import io.apicurio.registry.storage.dto.ArtifactSearchResultsDto;
import io.apicurio.registry.storage.dto.ArtifactVersionMetaDataDto;
import io.apicurio.registry.storage.dto.CommentDto;
import io.apicurio.registry.storage.dto.EditableArtifactMetaDataDto;
import io.apicurio.registry.storage.dto.GroupMetaDataDto;
import io.apicurio.registry.storage.dto.GroupSearchResultsDto;
import io.apicurio.registry.storage.dto.RoleMappingDto;
import io.apicurio.registry.storage.dto.RoleMappingSearchResultsDto;
import io.apicurio.registry.storage.dto.VersionSearchResultsDto;
import io.apicurio.registry.types.RoleType;

public final class V3ApiUtil {

private V3ApiUtil() {
Expand Down Expand Up @@ -296,4 +323,32 @@ public static Comment commentDtoToComment(CommentDto dto) {
.value(dto.getValue())
.build();
}

public static RoleMapping dtoToRoleMapping(RoleMappingDto dto) {
RoleMapping mapping = new RoleMapping();
mapping.setPrincipalId(dto.getPrincipalId());
mapping.setRole(RoleType.valueOf(dto.getRole()));
mapping.setPrincipalName(dto.getPrincipalName());
return mapping;
}

public static RoleMappingSearchResults dtoToRoleMappingSearchResults(RoleMappingSearchResultsDto dto) {
RoleMappingSearchResults results = new RoleMappingSearchResults();
results.setCount((int) dto.getCount());
results.setRoleMappings(dto.getRoleMappings().stream().map(rm -> {
return dtoToRoleMapping(rm);
}).collect(Collectors.toList()));
return results;
}

public static ConfigurationProperty dtoToConfigurationProperty(DynamicConfigPropertyDef def, DynamicConfigPropertyDto dto) {
ConfigurationProperty rval = new ConfigurationProperty();
rval.setName(def.getName());
rval.setValue(dto.getValue());
rval.setType(def.getType().getName());
rval.setLabel(def.getLabel());
rval.setDescription(def.getDescription());
return rval;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,13 @@ void updateArtifactRule(String groupId, String artifactId, RuleType rule, RuleCo
*/
List<RoleMappingDto> getRoleMappings() throws RegistryStorageException;

/**
* Search for role mappings.
* @param offset the number of artifacts to skip
* @param limit the result size limit
*/
RoleMappingSearchResultsDto searchRoleMappings(int offset, int limit) throws RegistryStorageException;

/**
* Gets the details of a single role mapping.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,11 @@ public String getRoleForPrincipal(String principalId) throws RegistryStorageExce
public List<RoleMappingDto> getRoleMappings() throws RegistryStorageException {
return delegate.getRoleMappings();
}

@Override
public RoleMappingSearchResultsDto searchRoleMappings(int offset, int limit) throws RegistryStorageException {
return delegate.searchRoleMappings(offset, limit);
}


@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@ToString
public class ArtifactSearchResultsDto {

@Builder.Default
private List<SearchedArtifactDto> artifacts = new ArrayList<>();
private long count;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
@ToString
public class GroupSearchResultsDto {

@Builder.Default
private List<SearchedGroupDto> groups = new ArrayList<SearchedGroupDto>();

private Integer count;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.apicurio.registry.storage.dto;

import java.util.ArrayList;
import java.util.List;

import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
@Setter
@EqualsAndHashCode
@ToString
@RegisterForReflection
public class RoleMappingSearchResultsDto {

@Builder.Default
private List<RoleMappingDto> roleMappings = new ArrayList<>();
private long count;

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@ToString
public class VersionSearchResultsDto {

private long count;
@Builder.Default
private List<SearchedVersionDto> versions = new ArrayList<>();
private long count;
}
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,11 @@ public long countTotalArtifactVersions() {
public List<RoleMappingDto> getRoleMappings() {
return proxy(RegistryStorage::getRoleMappings);
}

@Override
public RoleMappingSearchResultsDto searchRoleMappings(int offset, int limit) throws RegistryStorageException {
return proxy(storage -> storage.searchRoleMappings(offset, limit));
}


@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import io.apicurio.registry.storage.dto.OrderBy;
import io.apicurio.registry.storage.dto.OrderDirection;
import io.apicurio.registry.storage.dto.RoleMappingDto;
import io.apicurio.registry.storage.dto.RoleMappingSearchResultsDto;
import io.apicurio.registry.storage.dto.RuleConfigurationDto;
import io.apicurio.registry.storage.dto.SearchFilter;
import io.apicurio.registry.storage.dto.SearchFilterType;
Expand Down Expand Up @@ -2419,6 +2420,27 @@ public List<RoleMappingDto> getRoleMappings() throws RegistryStorageException {
});
}

@Override
@Transactional
public RoleMappingSearchResultsDto searchRoleMappings(int offset, int limit) throws RegistryStorageException {
log.debug("Searching role mappings.");
return handles.withHandleNoException(handle -> {
String query = sqlStatements.selectRoleMappings() + " LIMIT ? OFFSET ?";
String countQuery = sqlStatements.countRoleMappings();
List<RoleMappingDto> mappings = handle.createQuery(query)
.bind(0, limit)
.bind(1, offset)
.map(RoleMappingDtoMapper.instance)
.list();
Integer count = handle.createQuery(countQuery)
.mapTo(Integer.class)
.one();
return RoleMappingSearchResultsDto.builder()
.count(count)
.roleMappings(mappings)
.build();
});
}

@Override
@Transactional
Expand Down
Loading