From 31c4ffafc178c8049c5ecec569182a1b0b3ebad2 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Wed, 16 Oct 2024 16:03:39 +0300 Subject: [PATCH] Improve DS Tag REST & management API (#1883) * added methods to unassign by multiple ds * deprecated toggle assigments - too complex to undestand * deprecated unassign (management) of single ds - in favour of methods with multiple ds Signed-off-by: Marinov Avgustin --- .../repository/DistributionSetManagement.java | 76 ++++---- .../JpaDistributionSetManagement.java | 139 ++++++++------- .../api/MgmtDistributionSetTagRestApi.java | 163 +++++++++++++----- .../MgmtDistributionSetTagResource.java | 82 +++++---- .../MgmtDistributionSetTagResourceTest.java | 2 +- 5 files changed, 286 insertions(+), 176 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index 20360da22..08ade0025 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -96,6 +96,17 @@ public interface DistributionSetManagement @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) List assignTag(@NotEmpty Collection ids, long tagId); + /** + * Unassign a {@link DistributionSetTag} assignment to given {@link DistributionSet}s. + * + * @param ids to assign for + * @param tagId to assign + * @return list of assigned ds + * @throws EntityNotFoundException if tag with given ID does not exist or (at least one) of the distribution sets. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List unassignTag(@NotEmpty Collection ids, long tagId); + /** * Creates a list of distribution set meta data entries. * @@ -452,25 +463,6 @@ public interface DistributionSetManagement @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) boolean isInUse(long id); - /** - * Toggles {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s by means that if some (or all) of the targets in - * the list have the {@link Tag} not yet assigned, they will be. Only if all - * of theme have the tag already assigned they will be removed instead. - * - * @param ids - * to toggle for - * @param tagName - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - * - * @throws EntityNotFoundException - * if given tag does not exist or (at least one) module - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection ids, @NotNull String tagName); - /** * Unassigns a {@link SoftwareModule} form an existing * {@link DistributionSet}. @@ -491,22 +483,6 @@ public interface DistributionSetManagement @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) DistributionSet unassignSoftwareModule(long id, long moduleId); - /** - * Unassign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}. - * - * @param id - * to unassign for - * @param tagId - * to unassign - * @return the unassigned ds or if no ds is unassigned - * - * @throws EntityNotFoundException - * if set or tag with given ID does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet unassignTag(long id, long tagId); - /** * Updates a distribution set meta data value if corresponding entry exists. * @@ -585,4 +561,34 @@ public interface DistributionSetManagement */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) void invalidate(DistributionSet distributionSet); + + /** + * Toggles {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s by means that if some (or all) of the targets in + * the list have the {@link Tag} not yet assigned, they will be. Only if all + * of theme have the tag already assigned they will be removed instead. + * + * @deprecated since 0.6.0 in favor of assign/unassign + * @param ids to toggle for + * @param tagName to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of the assignment outcome. + * @throws EntityNotFoundException if given tag does not exist or (at least one) module + */ + @Deprecated(forRemoval = true) + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection ids, @NotNull String tagName); + + + /** + * Unassign a {@link DistributionSetTag} assignment to given {@link DistributionSet}. + * + * @deprecated since 0.6.0 in favor of unassignTag(List, long) + * @param id to unassign for + * @param tagId to unassign + * @return the unassigned ds or if no ds is unassigned + * @throws EntityNotFoundException if set or tag with given ID does not exist + */ + @Deprecated(forRemoval = true) + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unassignTag(long id, long tagId); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java index 5d356a6c7..3dad61ba8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaDistributionSetManagement.java @@ -62,7 +62,6 @@ import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository; import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification; import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications; -import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper; import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; @@ -85,7 +84,6 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.orm.jpa.vendor.Database; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; -import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -187,43 +185,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { return distributionSetRepository.countAutoAssignmentsForDistributionSet(id); } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection ids, final String tagName) { - return updateTags( - ids, - () -> distributionSetTagManagement - .getByName(tagName) - .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName)), - (allDs, distributionSetTag) -> { - final List toBeChangedDSs = allDs.stream().filter(set -> set.addTag(distributionSetTag)) - .collect(Collectors.toList()); - - final DistributionSetTagAssignmentResult result; - // un-assignment case - if (toBeChangedDSs.isEmpty()) { - for (final JpaDistributionSet set : allDs) { - if (set.removeTag(distributionSetTag)) { - toBeChangedDSs.add(set); - } - } - result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(), - Collections.emptyList(), - Collections.unmodifiableList( - toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())), - distributionSetTag); - } else { - result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(), - Collections.unmodifiableList( - toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())), - Collections.emptyList(), distributionSetTag); - } - return result; - }); - } - @Override @Transactional @Retryable(include = { @@ -238,13 +199,28 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { }); } + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public List unassignTag(final Collection ids, final long dsTagId) { + return updateTags( + ids, + () -> distributionSetTagManagement.get(dsTagId).orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId)), + (allDs, distributionSetTag) -> { + allDs.forEach(ds -> ds.removeTag(distributionSetTag)); + return Collections.unmodifiableList(distributionSetRepository.saveAll(allDs)); + }); + } + private T updateTags( final Collection dsIds, final Supplier tagSupplier, final BiFunction, DistributionSetTag, T> updater) { - final List allDs = findDistributionSetListWithDetails(dsIds); + final List allDs = dsIds.size() == 1 ? + distributionSetRepository.findById(dsIds.iterator().next()).map(List::of).orElseGet(Collections::emptyList) : + distributionSetRepository.findAll(DistributionSetSpecification.byIds(dsIds)); if (allDs.size() < dsIds.size()) { - throw new EntityNotFoundException(DistributionSet.class, dsIds, - allDs.stream().map(DistributionSet::getId).toList()); + throw new EntityNotFoundException(DistributionSet.class, dsIds, allDs.stream().map(DistributionSet::getId).toList()); } final DistributionSetTag distributionSetTag = tagSupplier.get(); @@ -256,10 +232,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { } } - private List findDistributionSetListWithDetails(final Collection distributionIdSet) { - return distributionSetRepository.findAll(DistributionSetSpecification.byIds(distributionIdSet)); - } - @Override @Transactional @Retryable(include = { @@ -659,25 +631,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { } } - @Override - @Transactional - @Retryable(include = { - ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) - public DistributionSet unassignTag(final long id, final long dsTagId) { - final JpaDistributionSet set = (JpaDistributionSet) getWithDetails(id) - .orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id)); - - final DistributionSetTag distributionSetTag = distributionSetTagManagement.get(dsTagId) - .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId)); - set.removeTag(distributionSetTag); - - final JpaDistributionSet result = distributionSetRepository.save(set); - - // No reason to save the tag - entityManager.detach(distributionSetTag); - return result; - } - @Override @Transactional @Retryable(include = { @@ -865,4 +818,60 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { throw new EntityNotFoundException(DistributionSetTag.class, tagId); } } + + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection ids, final String tagName) { + return updateTags( + ids, + () -> distributionSetTagManagement + .getByName(tagName) + .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName)), + (allDs, distributionSetTag) -> { + final List toBeChangedDSs = allDs.stream().filter(set -> set.addTag(distributionSetTag)) + .collect(Collectors.toList()); + + final DistributionSetTagAssignmentResult result; + // un-assignment case + if (toBeChangedDSs.isEmpty()) { + for (final JpaDistributionSet set : allDs) { + if (set.removeTag(distributionSetTag)) { + toBeChangedDSs.add(set); + } + } + result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(), + Collections.emptyList(), + Collections.unmodifiableList( + toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())), + distributionSetTag); + } else { + result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(), + Collections.unmodifiableList( + toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())), + Collections.emptyList(), distributionSetTag); + } + return result; + }); + } + + @Override + @Transactional + @Retryable(include = { + ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY)) + public DistributionSet unassignTag(final long id, final long dsTagId) { + final JpaDistributionSet set = (JpaDistributionSet) getWithDetails(id) + .orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id)); + + final DistributionSetTag distributionSetTag = distributionSetTagManagement.get(dsTagId) + .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId)); + set.removeTag(distributionSetTag); + + final JpaDistributionSet result = distributionSetRepository.save(set); + + // No reason to save the tag + entityManager.detach(distributionSetTag); + return result; + } } \ No newline at end of file diff --git a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java index 3712d363e..45a7fb3d6 100644 --- a/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java +++ b/hawkbit-rest/hawkbit-mgmt-api/src/main/java/org/eclipse/hawkbit/mgmt/rest/api/MgmtDistributionSetTagRestApi.java @@ -338,49 +338,47 @@ public interface MgmtDistributionSetTagRestApi { String rsqlParam); /** - * Handles the POST request to toggle the assignment of distribution sets by - * the given tag id. + * Handles the POST request to assign distribution sets to the given tag id. * * @param distributionsetTagId * the ID of the distribution set tag to retrieve * @param assignedDSRequestBodies - * list of distribution set ids to be toggled + * list of distribution sets ids to be assigned * - * @return the list of assigned distribution sets and unassigned - * distribution sets. + * @return the list of assigned distribution set. */ - @Operation(summary = "Toggle the assignment of distribution sets by the given tag id", - description = "Handles the POST request of toggle distribution assignment. The request body must " + - "always be a list of distribution set ids.") + @Operation(summary = "Assign distribution set to the given tag id", + description = "Handles the POST request of distribution assignment. Already assigned distribution will " + + "be ignored.") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved"), - @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), - @ApiResponse(responseCode = "401", description = "The request requires user authentication.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "403", - description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + - "data volume restriction applies.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + - "user in another request at the same time. You may retry your modification request.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "415", description = "The request was attempt with a media-type which is not " + - "supported by the server for this resource.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), - @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts " + - "and the client has to wait another second.", - content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))) + @ApiResponse(responseCode = "200", description = "Successfully retrieved"), + @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), + @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", + description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + + "data volume restriction applies.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + + "user in another request at the same time. You may retry your modification request.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "415", description = "The request was attempt with a media-type which is not " + + "supported by the server for this resource.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts " + + "and the client has to wait another second.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))) }) - @PostMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING + "/toggleTagAssignment") - ResponseEntity toggleTagAssignment( + @PostMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING + "/{distributionsetId}") + ResponseEntity assignTag( @PathVariable("distributionsetTagId") Long distributionsetTagId, - List assignedDSRequestBodies); + @PathVariable("distributionsetId") Long distributionsetId); /** * Handles the POST request to assign distribution sets to the given tag id. @@ -423,18 +421,15 @@ public interface MgmtDistributionSetTagRestApi { + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING, consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }) - ResponseEntity> assignDistributionSets( + ResponseEntity> assignTag( @PathVariable("distributionsetTagId") Long distributionsetTagId, List assignedDSRequestBodies); /** - * Handles the DELETE request to unassign one distribution set from the - * given tag id. + * Handles the DELETE request to unassign one distribution set from the given tag id. * - * @param distributionsetTagId - * the ID of the distribution set tag - * @param distributionsetId - * the ID of the distribution set to unassign + * @param distributionsetTagId the ID of the distribution set tag + * @param distributionsetId the ID of the distribution set to unassign * @return http status code */ @Operation(summary = "Unassign one distribution set from the given tag id", @@ -459,9 +454,89 @@ public interface MgmtDistributionSetTagRestApi { "and the client has to wait another second.", content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))) }) - @DeleteMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING - + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING + "/{distributionsetId}") - ResponseEntity unassignDistributionSet(@PathVariable("distributionsetTagId") Long distributionsetTagId, + @DeleteMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING + "/{distributionsetId}") + ResponseEntity unassignTag( + @PathVariable("distributionsetTagId") Long distributionsetTagId, @PathVariable("distributionsetId") Long distributionsetId); + /** + * Handles the DELETE request to unassign one distribution set from the given tag id. + * + * @param distributionsetTagId the ID of the distribution set tag + * @param distributionsetId the ID of the distribution set to unassign + * @return http status code + */ + @Operation(summary = "Unassign multiple distribution sets from the given tag id", + description = "Handles the DELETE request of unassign the given distribution.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully retrieved"), + @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), + @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", + description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + + "data volume restriction applies.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "404", description = "Distribution Set Tag not found.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts " + + "and the client has to wait another second.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))) + }) + @DeleteMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING) + ResponseEntity unassignTag( + @PathVariable("distributionsetTagId") Long distributionsetTagId, + List distributionsetId); + + /** + * Handles the POST request to toggle the assignment of distribution sets by + * the given tag id. + * + * @param distributionsetTagId + * the ID of the distribution set tag to retrieve + * @param assignedDSRequestBodies + * list of distribution set ids to be toggled + * + * @return the list of assigned distribution sets and unassigned + * distribution sets. + */ + @Operation(summary = "[DEPRECATED] Toggle the assignment of distribution sets by the given tag id", + description = "Handles the POST request of toggle distribution assignment. The request body must " + + "always be a list of distribution set ids.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Successfully retrieved"), + @ApiResponse(responseCode = "400", description = "Bad Request - e.g. invalid parameters", + content = @Content(mediaType = "application/json", schema = @Schema(implementation = ExceptionInfo.class))), + @ApiResponse(responseCode = "401", description = "The request requires user authentication.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", + description = "Insufficient permissions, entity is not allowed to be changed (i.e. read-only) or " + + "data volume restriction applies.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "405", description = "The http request method is not allowed on the resource.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "406", description = "In case accept header is specified and not application/json.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "409", description = "E.g. in case an entity is created or modified by another " + + "user in another request at the same time. You may retry your modification request.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "415", description = "The request was attempt with a media-type which is not " + + "supported by the server for this resource.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "429", description = "Too many requests. The server will refuse further attempts " + + "and the client has to wait another second.", + content = @Content(mediaType = "application/json", schema = @Schema(hidden = true))) + }) + @PostMapping(value = MgmtRestConstants.DISTRIBUTIONSET_TAG_V1_REQUEST_MAPPING + + MgmtRestConstants.DISTRIBUTIONSET_TAG_DISTRIBUTIONSETS_REQUEST_MAPPING + "/toggleTagAssignment") + ResponseEntity toggleTagAssignment( + @PathVariable("distributionsetTagId") Long distributionsetTagId, + List assignedDSRequestBodies); } \ No newline at end of file diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java index 81f851429..0e086b284 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResource.java @@ -162,6 +162,57 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes return ResponseEntity.ok(new PagedList<>(rest, findDistrAll.getTotalElements())); } + @Override + public ResponseEntity assignTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @PathVariable("distributionsetId") final Long distributionsetId) { + log.debug("Assign ds {} for ds tag {}", distributionsetId, distributionsetTagId); + this.distributionSetManagement.assignTag(List.of(distributionsetId), distributionsetTagId); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity> assignTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List assignedDSRequestBodies) { + log.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); + final List assignedDs = this.distributionSetManagement + .assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId); + log.debug("Assigned DistributionSet {}", assignedDs.size()); + return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs)); + } + + @Override + public ResponseEntity unassignTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @PathVariable("distributionsetId") final Long distributionsetId) { + log.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId); + this.distributionSetManagement.unassignTag(List.of(distributionsetId), distributionsetTagId); + return ResponseEntity.ok().build(); + } + + @Override + public ResponseEntity unassignTag( + @PathVariable("distributionsetTagId") final Long distributionsetTagId, + @RequestBody final List distributionsetIds) { + log.debug("Unassign DistributionSet {} for ds tag {}", distributionsetIds.size(), distributionsetTagId); + final List assignedDs = this.distributionSetManagement + .unassignTag(distributionsetIds, distributionsetTagId); + log.debug("Unassigned DistributionSet {}", assignedDs.size()); + return ResponseEntity.ok().build(); + } + + private DistributionSetTag findDistributionTagById(final Long distributionsetTagId) { + return distributionSetTagManagement.get(distributionsetTagId) + .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, distributionsetTagId)); + } + + private static List findDistributionSetIds( + final List assignedDistributionSetRequestBodies) { + return assignedDistributionSetRequestBodies.stream() + .map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList()); + } + @Override public ResponseEntity toggleTagAssignment( @PathVariable("distributionsetTagId") final Long distributionsetTagId, @@ -185,35 +236,4 @@ public class MgmtDistributionSetTagResource implements MgmtDistributionSetTagRes return ResponseEntity.ok(tagAssigmentResultRest); } - - @Override - public ResponseEntity> assignDistributionSets( - @PathVariable("distributionsetTagId") final Long distributionsetTagId, - @RequestBody final List assignedDSRequestBodies) { - log.debug("Assign DistributionSet {} for ds tag {}", assignedDSRequestBodies.size(), distributionsetTagId); - final List assignedDs = this.distributionSetManagement - .assignTag(findDistributionSetIds(assignedDSRequestBodies), distributionsetTagId); - log.debug("Assigned DistributionSet {}", assignedDs.size()); - return ResponseEntity.ok(MgmtDistributionSetMapper.toResponseDistributionSets(assignedDs)); - } - - @Override - public ResponseEntity unassignDistributionSet( - @PathVariable("distributionsetTagId") final Long distributionsetTagId, - @PathVariable("distributionsetId") final Long distributionsetId) { - log.debug("Unassign ds {} for ds tag {}", distributionsetId, distributionsetTagId); - this.distributionSetManagement.unassignTag(distributionsetId, distributionsetTagId); - return ResponseEntity.ok().build(); - } - - private DistributionSetTag findDistributionTagById(final Long distributionsetTagId) { - return distributionSetTagManagement.get(distributionsetTagId) - .orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, distributionsetTagId)); - } - - private static List findDistributionSetIds( - final List assignedDistributionSetRequestBodies) { - return assignedDistributionSetRequestBodies.stream() - .map(MgmtAssignedDistributionSetRequestBody::getDistributionSetId).collect(Collectors.toList()); - } } diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java index 9aed80268..91333f579 100644 --- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java +++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTagResourceTest.java @@ -345,7 +345,7 @@ public class MgmtDistributionSetTagResourceTest extends AbstractManagementApiInt @ExpectEvents({ @Expect(type = DistributionSetTagCreatedEvent.class, count = 1), @Expect(type = DistributionSetCreatedEvent.class, count = 2), @Expect(type = DistributionSetUpdatedEvent.class, count = 2) }) - public void assignDistributionSets() throws Exception { + public void assignTag() throws Exception { final DistributionSetTag tag = testdataFactory.createDistributionSetTags(1).get(0); final int setsAssigned = 2; final List sets = testdataFactory.createDistributionSetsWithoutModules(setsAssigned);