From 6fd7ec53df9f2349cbca888d1195ecec87a6c8d1 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Mon, 23 Dec 2024 14:06:10 -0600 Subject: [PATCH 1/5] Fix approve/reject APIs issue where it would expect additional packageIds params --- .../rest/v2/WorkflowController.java | 3 +- .../workflow/CancelPackageRequestBody.java | 49 +++++++++++++++++++ .../workflow/ReviewPackageRequestBody.java | 14 +----- 3 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/model/rest/workflow/CancelPackageRequestBody.java diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/WorkflowController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/WorkflowController.java index 5860e2425b..5d8936cb31 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/WorkflowController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/WorkflowController.java @@ -45,7 +45,6 @@ import java.util.List; import java.util.regex.Pattern; -import static java.util.Collections.emptyList; import static org.apache.commons.collections4.CollectionUtils.emptyIfNull; import static org.craftercms.studio.controller.rest.v2.RequestConstants.*; import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*; @@ -170,7 +169,7 @@ public Result reject(@Valid @PathVariable @NotEmpty @ValidSiteId String site, @V @PostMapping(PATH_PARAM_SITE + CANCEL) public Result cancel(@Valid @PathVariable @NotEmpty @ValidSiteId String site, - @Valid @RequestBody ReviewPackageRequestBody cancelPackageRequest) + @Valid @RequestBody CancelPackageRequestBody cancelPackageRequest) throws ServiceLayerException, AuthenticationException { workflowService.cancelPackages(site, cancelPackageRequest.getPackageIds(), cancelPackageRequest.getComment()); Result result = new Result(); diff --git a/src/main/java/org/craftercms/studio/model/rest/workflow/CancelPackageRequestBody.java b/src/main/java/org/craftercms/studio/model/rest/workflow/CancelPackageRequestBody.java new file mode 100644 index 0000000000..c6559ecd75 --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/rest/workflow/CancelPackageRequestBody.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.rest.workflow; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; + +import java.util.List; + +/** + * Request body for cancelling + */ +public class CancelPackageRequestBody { + + @NotBlank + private String comment; + @NotEmpty + private List packageIds; + + public @NotBlank String getComment() { + return comment; + } + + public void setComment(@NotBlank String comment) { + this.comment = comment; + } + + public List getPackageIds() { + return packageIds; + } + + public void setPackageIds(List packageIds) { + this.packageIds = packageIds; + } +} diff --git a/src/main/java/org/craftercms/studio/model/rest/workflow/ReviewPackageRequestBody.java b/src/main/java/org/craftercms/studio/model/rest/workflow/ReviewPackageRequestBody.java index ed25c35a29..45fb851799 100644 --- a/src/main/java/org/craftercms/studio/model/rest/workflow/ReviewPackageRequestBody.java +++ b/src/main/java/org/craftercms/studio/model/rest/workflow/ReviewPackageRequestBody.java @@ -17,19 +17,14 @@ package org.craftercms.studio.model.rest.workflow; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; - -import java.util.List; /** - * Request body for reviewing a package (reject, cancel, approve) + * Request body for reviewing a package (reject, approve) */ public class ReviewPackageRequestBody { @NotBlank private String comment; - @NotEmpty - private List packageIds; public @NotBlank String getComment() { return comment; @@ -39,11 +34,4 @@ public void setComment(@NotBlank String comment) { this.comment = comment; } - public List getPackageIds() { - return packageIds; - } - - public void setPackageIds(List packageIds) { - this.packageIds = packageIds; - } } From 2cb6a38620153e05240ae624b53061e6668e222f Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Mon, 23 Dec 2024 14:12:06 -0600 Subject: [PATCH 2/5] Fix empty path list query when trying to publish directories with no changes --- .../internal/PublishServiceInternalImpl.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java index 3235d8d59b..2996ce278d 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java @@ -59,8 +59,7 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.*; -import static org.apache.commons.collections4.CollectionUtils.emptyIfNull; -import static org.apache.commons.collections4.CollectionUtils.union; +import static org.apache.commons.collections4.CollectionUtils.*; import static org.apache.commons.lang3.ArrayUtils.contains; import static org.apache.commons.lang3.StringUtils.defaultIfEmpty; import static org.apache.tika.io.FilenameUtils.getName; @@ -386,7 +385,7 @@ private PublishItem createPublishItem(final String path, * - Include children if requested */ private void createPublishItemsFromPaths(final Site site, final Collection publishRequestPaths, - final Map publishItemsByPath) { + final Map publishItemsByPath) throws InvalidParametersException { if (isEmpty(publishRequestPaths)) { return; } @@ -404,15 +403,17 @@ private void createPublishItemsFromPaths(final Site site, final Collection statesByPath = itemServiceInternal.getItemStates(site.getSiteId(), allPaths); - publishItemsByPath.putAll( - allPaths.stream() - .filter(path -> !publishItemsByPath.containsKey(path)) - .map(path -> { - long itemState = statesByPath.get(path).getState(); - return createPublishItem(path, isNew(itemState) ? ADD : UPDATE, true); - }) - .collect(toMap(PublishItem::getPath, item -> item))); + if (isNotEmpty(allPaths)) { + Map statesByPath = itemServiceInternal.getItemStates(site.getSiteId(), allPaths); + publishItemsByPath.putAll( + allPaths.stream() + .filter(path -> !publishItemsByPath.containsKey(path)) + .map(path -> { + long itemState = statesByPath.get(path).getState(); + return createPublishItem(path, isNew(itemState) ? ADD : UPDATE, true); + }) + .collect(toMap(PublishItem::getPath, item -> item))); + } } /** From f324c19a68d19162f6890aded14016b596ec8835 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Tue, 24 Dec 2024 13:55:43 -0600 Subject: [PATCH 3/5] API tweaks Separate API to retrieve publish package items Publish API path and response status code update --- src/main/api/studio-api.yaml | 115 ++++++++---------- .../v2/service/publish/PublishService.java | 1 - .../controller/rest/v2/PublishController.java | 57 +++++---- .../rest/v2/RequestMappingConstants.java | 1 + .../rest/publish/PublishPackageDetails.java | 44 ------- 5 files changed, 86 insertions(+), 132 deletions(-) delete mode 100644 src/main/java/org/craftercms/studio/model/rest/publish/PublishPackageDetails.java diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 8605618e48..5d7c367899 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -6353,7 +6353,7 @@ paths: '500': $ref: '#/components/responses/InternalServerError' - /api/2/publish/{siteId}: + /api/2/publish/{siteId}/package: post: tags: - publishing @@ -6396,8 +6396,8 @@ paths: type: string description: package comment responses: - '200': - description: OK + '201': + description: Created content: application/json: schema: @@ -6532,6 +6532,50 @@ paths: summary: Get package details description: 'Required permission "get_publishing_queue"' operationId: getPublishPackage + parameters: + - name: siteId + in: path + description: site ID + required: true + schema: + type: string + - name: packageId + in: path + description: package ID + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + $ref: '#/components/schemas/ApiResponse' + package: + $ref: '#/components/schemas/PublishPackage' + progress: + $ref: '#/components/schemas/PublishTaskProgress' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + + /api/2/publish/{siteId}/package/{packageId}/items: + get: + tags: + - publishing + summary: Get publish package items + description: 'Required permission "get_publishing_queue"' + operationId: getPublishPackageItems parameters: - name: siteId in: path @@ -6590,8 +6634,8 @@ paths: description: Limit for pagination required: false schema: - type: integer - format: int32 + type: integer + format: int32 responses: '200': description: OK @@ -6599,56 +6643,16 @@ paths: application/json: schema: type: object - properties: - response: - $ref: '#/components/schemas/ApiResponse' allOf: - $ref: '#/components/schemas/PaginatedResponse' - - $ref: '#/components/schemas/PublishPackageDetails' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '404': - $ref: '#/components/responses/NotFound' - '500': - $ref: '#/components/responses/InternalServerError' - - /api/2/publish/{siteId}/package/{packageId}/status: - get: - tags: - - publishing - summary: Get package status without the actual items list - description: 'Required permission "get_publishing_queue"' - operationId: getPublishPackageStatus - parameters: - - name: siteId - in: path - description: site ID - required: true - schema: - type: string - - name: packageId - in: path - description: package ID - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: OK - content: - application/json: - schema: - type: object properties: response: $ref: '#/components/schemas/ApiResponse' - package: - $ref: '#/components/schemas/PublishPackage' - progress: - $ref: '#/components/schemas/PublishTaskProgress' + items: + type: array + description: list of items to be published + items: + $ref: '#/components/schemas/PublishItem' '400': $ref: '#/components/responses/BadRequest' '401': @@ -9487,17 +9491,6 @@ components: - state - publishingTarget - PublishPackageDetails: - type: object - properties: - package: - $ref: '#/components/schemas/PublishPackage' - items: - type: array - description: list of items to be published - items: - $ref: '#/components/schemas/PublishItem' - PublishItem: type: object properties: diff --git a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java index 3996d00ab3..7ff75033ef 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java @@ -28,7 +28,6 @@ import org.craftercms.studio.api.v2.exception.publish.PublishPackageNotFoundException; import org.craftercms.studio.impl.v2.publish.Publisher; import org.craftercms.studio.model.publish.PublishingTarget; -import org.craftercms.studio.model.rest.publish.PublishPackageDetails; import java.io.IOException; import java.time.Instant; diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java index ffeec78336..5b0af907bf 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java @@ -40,7 +40,11 @@ import org.craftercms.studio.model.rest.PaginatedResultList; import org.craftercms.studio.model.rest.Result; import org.craftercms.studio.model.rest.ResultOne; -import org.craftercms.studio.model.rest.publish.*; +import org.craftercms.studio.model.rest.publish.AvailablePublishingTargets; +import org.craftercms.studio.model.rest.publish.CalculatePublishPackageRequest; +import org.craftercms.studio.model.rest.publish.EnablePublisherRequest; +import org.craftercms.studio.model.rest.publish.PublishPackageRequest; +import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -48,7 +52,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import static java.util.Collections.emptyList; @@ -59,6 +62,7 @@ import static org.craftercms.studio.controller.rest.v2.RequestConstants.*; import static org.craftercms.studio.controller.rest.v2.RequestMappingConstants.*; import static org.craftercms.studio.controller.rest.v2.ResultConstants.*; +import static org.craftercms.studio.model.rest.ApiResponse.CREATED; import static org.craftercms.studio.model.rest.ApiResponse.OK; import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; @@ -113,37 +117,37 @@ public PaginatedResultList getPublishPackages(@ValidSiteId @Path } @GetMapping(PATH_PARAM_SITE + PACKAGE + PATH_PARAM_PACKAGE) - public PublishPackageDetails getPublishPackage(@PathVariable @ValidSiteId String site, - @PathVariable @Positive long packageId, - @RequestParam(name = REQUEST_PARAM_PATH, required = false) String path, - @RequestParam(name = REQUEST_PARAM_SYSTEM_TYPE, required = false) List systemTypes, - @RequestParam(name = REQUEST_PARAM_INTERNAL_NAME, required = false) String internalName, - @RequestParam(name = REQUEST_PARAM_OFFSET, required = false, - defaultValue = "0") @PositiveOrZero int offset, - @RequestParam(name = REQUEST_PARAM_LIMIT, required = false, - defaultValue = "10") @PositiveOrZero int limit) + public ResultOne getPublishPackage(@PathVariable @ValidSiteId String site, + @PathVariable @Positive long packageId) throws SiteNotFoundException, PublishPackageNotFoundException { PublishPackage publishPackage = publishService.getPackage(site, packageId); + ResultOne result = new ResultOne<>(); + result.setEntity(RESULT_KEY_PACKAGE, publishPackage); + // TODO: add the package status (progress) to the response + result.setResponse(OK); + return result; + } + + @GetMapping(PATH_PARAM_SITE + PACKAGE + PATH_PARAM_PACKAGE + ITEMS) + public PaginatedResultList getPublishPackageItems(@PathVariable @ValidSiteId String site, + @PathVariable @Positive long packageId, + @RequestParam(name = REQUEST_PARAM_PATH, required = false) String path, + @RequestParam(name = REQUEST_PARAM_SYSTEM_TYPE, required = false) List systemTypes, + @RequestParam(name = REQUEST_PARAM_INTERNAL_NAME, required = false) String internalName, + @RequestParam(name = REQUEST_PARAM_OFFSET, required = false, + defaultValue = "0") @PositiveOrZero int offset, + @RequestParam(name = REQUEST_PARAM_LIMIT, required = false, + defaultValue = "10") @PositiveOrZero int limit) { Collection items = emptyList(); int totalItemCount = publishService.getPublishPackageItemCount(site, packageId, path, systemTypes, internalName); if (totalItemCount > 0) { items = publishService.getPublishPackageItems(site, packageId, path, systemTypes, internalName, offset, limit); } - PublishPackageDetails result = new PublishPackageDetails(publishPackage, items); - result.setTotal(totalItemCount); + PaginatedResultList result = new PaginatedResultList<>(); + result.setEntities(RESULT_KEY_ITEMS, items); result.setOffset(offset); result.setLimit(limit); - result.setResponse(OK); - return result; - } - - @GetMapping(PATH_PARAM_SITE + PACKAGE + PATH_PARAM_PACKAGE + STATUS) - public ResultOne getPublishPackageStatus(@PathVariable @ValidSiteId String site, @PathVariable @Positive long packageId) - throws PublishPackageNotFoundException, SiteNotFoundException { - // TODO: add the package status (progress) to the response - PublishPackage publishPackage = publishService.getPackage(site, packageId); - ResultOne result = new ResultOne<>(); - result.setEntity(RESULT_KEY_PACKAGE, publishPackage); + result.setTotal(totalItemCount); result.setResponse(OK); return result; } @@ -202,14 +206,15 @@ public Result enablePublisher(@PathVariable @NotEmpty @ValidSiteId String site, return result; } - @PostMapping(PATH_PARAM_SITE) + @ResponseStatus(HttpStatus.CREATED) + @PostMapping(PATH_PARAM_SITE + PACKAGE) public ResultOne publish(@PathVariable @NotEmpty @ValidSiteId String site, @Validated @RequestBody PublishPackageRequest request) throws ServiceLayerException, UserNotFoundException, AuthenticationException { long packageId = submitPublishPackage(site, request); ResultOne result = new ResultOne<>(); - result.setResponse(OK); + result.setResponse(CREATED); result.setEntity(RESULT_KEY_PACKAGE_ID, packageId); return result; } diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java index d5daf987ff..3fd29c0f5f 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java @@ -109,6 +109,7 @@ public final class RequestMappingConstants { public static final String HAS_INITIAL_PUBLISH = "/has_initial_publish"; public static final String ENABLE_PUBLISHER = "/enable"; public static final String PATH_PARAM_PACKAGE = "/{packageId}"; + public static final String ITEMS = "/items"; public static final String CALCULATE = "/calculate"; /** Dependency Controller */ diff --git a/src/main/java/org/craftercms/studio/model/rest/publish/PublishPackageDetails.java b/src/main/java/org/craftercms/studio/model/rest/publish/PublishPackageDetails.java deleted file mode 100644 index 12c9992910..0000000000 --- a/src/main/java/org/craftercms/studio/model/rest/publish/PublishPackageDetails.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.craftercms.studio.model.rest.publish; - -import com.fasterxml.jackson.annotation.JsonProperty; -import org.craftercms.studio.api.v2.dal.publish.PublishItemWithMetadata; -import org.craftercms.studio.api.v2.dal.publish.PublishPackage; -import org.craftercms.studio.model.rest.PaginatedResultList; - -import java.util.Collection; - -import static org.craftercms.studio.controller.rest.v2.ResultConstants.RESULT_KEY_ITEMS; - -/** - * Contains a {@link PublishPackage} general information and also its {@link PublishItemWithMetadata}s - */ -public class PublishPackageDetails extends PaginatedResultList { - - private final PublishPackage publishPackage; - - public PublishPackageDetails(final PublishPackage publishPackage, final Collection items) { - this.publishPackage = publishPackage; - setEntities(RESULT_KEY_ITEMS, items); - } - - @JsonProperty("package") - public PublishPackage getPublishPackage() { - return publishPackage; - } -} From f04b30e6f469639b3e1c0c77de00c718ade4abe5 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 26 Dec 2024 13:45:00 -0600 Subject: [PATCH 4/5] RequirePackageExists annotation --- .../api/v2/annotation/publish/PackageId.java | 34 +++++++++ .../publish/RequirePackageExists.java | 34 +++++++++ ...RequirePackageExistsAnnotationHandler.java | 74 +++++++++++++++++++ .../studio/api/v2/dal/publish/PublishDAO.java | 9 +++ .../v2/service/publish/PublishService.java | 3 +- .../controller/rest/v2/PublishController.java | 3 +- .../service/publish/PublishServiceImpl.java | 19 +++-- .../internal/PublishServiceInternalImpl.java | 17 +---- .../crafter/studio/security/common.xml | 4 + .../studio/api/v2/dal/publish/PublishDAO.xml | 9 +++ 10 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/api/v2/annotation/publish/PackageId.java create mode 100644 src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExists.java create mode 100644 src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExistsAnnotationHandler.java diff --git a/src/main/java/org/craftercms/studio/api/v2/annotation/publish/PackageId.java b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/PackageId.java new file mode 100644 index 0000000000..a6ec9f9659 --- /dev/null +++ b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/PackageId.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.api.v2.annotation.publish; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Annotation to mark the parameter containing a publish package id + */ +@Inherited +@Target({PARAMETER, ANNOTATION_TYPE}) +@Retention(RUNTIME) +public @interface PackageId { +} diff --git a/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExists.java b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExists.java new file mode 100644 index 0000000000..0227241c19 --- /dev/null +++ b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExists.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.api.v2.annotation.publish; + +import org.craftercms.studio.api.v2.annotation.RequireSiteExists; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to mark the method or class that requires a package to exist + * Notice that this annotation extends @{@link RequireSiteExists} + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@RequireSiteExists +public @interface RequirePackageExists { +} diff --git a/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExistsAnnotationHandler.java b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExistsAnnotationHandler.java new file mode 100644 index 0000000000..44b4086e6b --- /dev/null +++ b/src/main/java/org/craftercms/studio/api/v2/annotation/publish/RequirePackageExistsAnnotationHandler.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.api.v2.annotation.publish; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.craftercms.commons.aop.AopUtils; +import org.craftercms.studio.api.v2.annotation.SiteId; +import org.craftercms.studio.api.v2.annotation.StudioAnnotationUtils; +import org.craftercms.studio.api.v2.dal.publish.PublishDAO; +import org.craftercms.studio.api.v2.exception.publish.PublishPackageNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.Order; + +import java.beans.ConstructorProperties; +import java.lang.reflect.Method; + +/** + * Handles the {@link RequirePackageExists} annotation. + * Checks if the publish package exists in a site. + */ +@Aspect +@Order(10) +public class RequirePackageExistsAnnotationHandler { + private static final Logger logger = LoggerFactory.getLogger(RequirePackageExistsAnnotationHandler.class); + + private final PublishDAO publishDao; + + @ConstructorProperties({"publishDao"}) + public RequirePackageExistsAnnotationHandler(final PublishDAO publishDao) { + this.publishDao = publishDao; + } + + // This method matches: + // - methods declared on classes annotated with RequirePackageExists + // - methods declared on classes meta-annotated with RequirePackageExists (only one level deep). e.g.: @RequirePackageExists, which is annotated with @RequirePackageExists + // - methods annotated with RequirePackageExists + // - methods meta-annotated with RequirePackageExists (only one level deep) + @Around("@within(RequirePackageExists) || " + + "within(@RequirePackageExists *) || " + + "within(@(@RequirePackageExists *) *) || " + + "@annotation(RequirePackageExists) || " + + "execution(@(@RequirePackageExists *) * *(..))") + public Object requirePackageExists(ProceedingJoinPoint pjp) throws Throwable { + Method method = AopUtils.getActualMethod(pjp); + String siteId = StudioAnnotationUtils.getAnnotationValue(pjp, method, SiteId.class, String.class); + Long packageId = StudioAnnotationUtils.getAnnotationValue(pjp, method, PackageId.class, Long.class); + + if (packageId == null) { + logger.debug("Method '{}.{}' is annotated with @RequirePackageExists but does not have a @PackageId parameter. " + + "This annotation will be ignored.", method.getDeclaringClass().getName(), method.getName()); + } else if (!publishDao.packageExists(siteId, packageId)) { + throw new PublishPackageNotFoundException(siteId, packageId); + } + return pjp.proceed(); + } + +} diff --git a/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java index 24e6066cbe..01599c988e 100644 --- a/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java +++ b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java @@ -197,6 +197,15 @@ Collection getNextPublishPackages(@Param(APPROVAL_STATES) List */ PublishPackage getById(@Param(SITE_ID) final long siteId, @Param(PACKAGE_ID) final long packageId); + /** + * Indicate if a package exists for a site + * + * @param siteId the site id + * @param packageId the package id + * @return true if the package exists, false otherwise + */ + boolean packageExists(@Param(SITE_ID) final String siteId, @Param(PACKAGE_ID) final long packageId); + /** * Update a package */ diff --git a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java index 7ff75033ef..bbb7a1312a 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java @@ -110,7 +110,8 @@ Collection getPublishPackageItems(String siteId, long p * @param internalName internal name to filter package items by * @return publish package item list */ - int getPublishPackageItemCount(String siteId, long packageId, String path, List systemType, String internalName); + int getPublishPackageItemCount(String siteId, long packageId, String path, List systemType, String internalName) + throws SiteNotFoundException, PublishPackageNotFoundException; /** * Get available publishing targets for given site diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java index 5b0af907bf..13dffa3083 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java @@ -137,7 +137,8 @@ public PaginatedResultList getPublishPackageItems(@Path @RequestParam(name = REQUEST_PARAM_OFFSET, required = false, defaultValue = "0") @PositiveOrZero int offset, @RequestParam(name = REQUEST_PARAM_LIMIT, required = false, - defaultValue = "10") @PositiveOrZero int limit) { + defaultValue = "10") @PositiveOrZero int limit) + throws PublishPackageNotFoundException, SiteNotFoundException { Collection items = emptyList(); int totalItemCount = publishService.getPublishPackageItemCount(site, packageId, path, systemTypes, internalName); if (totalItemCount > 0) { diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java index 41f33a4547..5dd40a2cb0 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java @@ -25,6 +25,8 @@ import org.craftercms.studio.api.v2.annotation.RequireSiteExists; import org.craftercms.studio.api.v2.annotation.RequireSiteReady; import org.craftercms.studio.api.v2.annotation.SiteId; +import org.craftercms.studio.api.v2.annotation.publish.PackageId; +import org.craftercms.studio.api.v2.annotation.publish.RequirePackageExists; import org.craftercms.studio.api.v2.dal.publish.PublishItem; import org.craftercms.studio.api.v2.dal.publish.PublishItemWithMetadata; import org.craftercms.studio.api.v2.dal.publish.PublishPackage; @@ -70,9 +72,9 @@ public Collection getPublishPackages(@SiteId final String siteId } @Override - @RequireSiteExists + @RequirePackageExists @HasPermission(type = DefaultPermission.class, action = PERMISSION_GET_PUBLISHING_QUEUE) - public Collection getPublishPackageItems(@SiteId String siteId, long packageId, + public Collection getPublishPackageItems(@SiteId String siteId, @PackageId long packageId, String path, Collection systemTypes, String internalName, int offset, int limit) { return publishServiceInternal.getPublishPackageItems(siteId, packageId, path, @@ -80,7 +82,10 @@ public Collection getPublishPackageItems(@SiteId String } @Override - public int getPublishPackageItemCount(String siteId, long packageId, String path, List systemType, String internalName) { + @RequirePackageExists + @HasPermission(type = DefaultPermission.class, action = PERMISSION_GET_PUBLISHING_QUEUE) + public int getPublishPackageItemCount(@SiteId String siteId, @PackageId long packageId, String path, List systemType, String internalName) + throws PublishPackageNotFoundException, SiteNotFoundException { return publishServiceInternal.getPublishPackageItemCount(siteId, packageId, path, systemType, internalName); } @@ -149,17 +154,17 @@ public long publishDelete(@SiteId String siteId, Collection userRequeste } @Override - @RequireSiteExists + @RequirePackageExists @HasPermission(type = DefaultPermission.class, action = PERMISSION_GET_PUBLISHING_QUEUE) - public PublishPackage getPackage(@SiteId String siteId, long packageId) + public PublishPackage getPackage(@SiteId String siteId, @PackageId long packageId) throws PublishPackageNotFoundException, SiteNotFoundException { return publishServiceInternal.getPackage(siteId, packageId); } @Override - @RequireSiteExists + @RequirePackageExists @HasPermission(type = DefaultPermission.class, action = PERMISSION_GET_PUBLISHING_QUEUE) - public Collection getPublishItems(@SiteId String siteId, final long packageId, + public Collection getPublishItems(@SiteId String siteId, @PackageId final long packageId, final int offset, final int limit) throws PublishPackageNotFoundException, SiteNotFoundException { return publishServiceInternal.getPublishItems(siteId, packageId, offset, limit); diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java index 2996ce278d..f9769333b8 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java @@ -230,26 +230,15 @@ public long publishDelete(String siteId, Collection userRequestedPaths, @Override public PublishPackage getPackage(final String siteId, final long packageId) - throws PublishPackageNotFoundException, SiteNotFoundException { + throws SiteNotFoundException { Site site = siteService.getSite(siteId); - PublishPackage publishPackage = publishDao.getById(site.getId(), packageId); - if (publishPackage == null) { - throw new PublishPackageNotFoundException(siteId, packageId); - } - return publishPackage; + return publishDao.getById(site.getId(), packageId); } @Override public Collection getPublishItems(final String siteId, final long packageId, final int offset, final int limit) throws PublishPackageNotFoundException, SiteNotFoundException { - Collection publishItems = publishDao.getPublishItems(siteId, packageId, offset, limit); - if (isEmpty(publishItems)) { - if (getPackage(siteId, packageId) == null) { - throw new PublishPackageNotFoundException(siteId, packageId); - } - return emptyList(); - } - return publishItems; + return publishDao.getPublishItems(siteId, packageId, offset, limit); } @Override diff --git a/src/main/resources/crafter/studio/security/common.xml b/src/main/resources/crafter/studio/security/common.xml index 7b3f2986f7..cb46e16c67 100644 --- a/src/main/resources/crafter/studio/security/common.xml +++ b/src/main/resources/crafter/studio/security/common.xml @@ -191,6 +191,10 @@ + + + + diff --git a/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml b/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml index 7384dfa183..1d22f7938d 100644 --- a/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml +++ b/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml @@ -148,6 +148,15 @@ and site_id = #{siteId} + + UPDATE publish_package SET From c32d2185ba262525bf9f6fcf2a73431591910be0 Mon Sep 17 00:00:00 2001 From: Jonathan Mendez Date: Thu, 26 Dec 2024 17:45:43 -0600 Subject: [PATCH 5/5] Recalculate publish package API --- src/main/api/studio-api.yaml | 76 +++++++++++++++++++ .../studio/api/v2/dal/publish/PublishDAO.java | 33 ++++++-- .../api/v2/dal/publish/PublishPath.java | 41 ++++++++++ .../v2/service/publish/PublishService.java | 15 ++++ .../controller/rest/v2/PublishController.java | 19 ++++- .../rest/v2/RequestMappingConstants.java | 1 + .../service/publish/PublishServiceImpl.java | 8 ++ .../internal/PublishServiceInternalImpl.java | 15 ++++ .../RecalculatePublishPackageRequest.java | 41 ++++++++++ .../studio/api/v2/dal/publish/PublishDAO.xml | 10 +++ 10 files changed, 250 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishPath.java create mode 100644 src/main/java/org/craftercms/studio/model/rest/publish/RecalculatePublishPackageRequest.java diff --git a/src/main/api/studio-api.yaml b/src/main/api/studio-api.yaml index 5d7c367899..e382644306 100644 --- a/src/main/api/studio-api.yaml +++ b/src/main/api/studio-api.yaml @@ -6662,6 +6662,82 @@ paths: '500': $ref: '#/components/responses/InternalServerError' + /api/2/publish/{siteId}/package/{packageId}/recalculate: + post: + tags: + - publishing + summary: Recalculate a complete publish package user-requested items + description: 'Required permission "content_read"' + operationId: recalculatePublishPackage + parameters: + - name: siteId + in: path + description: site ID + required: true + schema: + type: string + - name: packageId + in: path + description: package ID + required: true + schema: + type: integer + format: int64 + requestBody: + description: publish request body + required: true + content: + application/json: + schema: + type: object + properties: + publishingTarget: + type: string + description: the publishing target (staging or live) + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + response: + $ref: '#/components/schemas/ApiResponse' + package: + type: object + properties: + items: + type: array + items: + type: string + description: the item path + example: "/site/website/article1/index.xml" + deletedItems: + type: array + items: + type: string + description: the deleted item path + example: "/site/website/about/index.xml" + hardDependencies: + type: array + items: + type: string + example: "/templates/web/article.ftl" + softDependencies: + type: array + items: + type: string + example: "/static-assets/images/background.png" + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + '404': + $ref: '#/components/responses/NotFound' + '500': + $ref: '#/components/responses/InternalServerError' + /api/2/publish/{siteId}/trigger: post: tags: diff --git a/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java index 01599c988e..6c0ff18cc6 100644 --- a/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java +++ b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishDAO.java @@ -25,13 +25,11 @@ import org.craftercms.studio.api.v2.dal.publish.PublishPackage.PackageState; import org.springframework.transaction.annotation.Transactional; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.groupingBy; import static org.apache.commons.collections4.CollectionUtils.isEmpty; import static org.craftercms.studio.api.v2.dal.ItemState.*; import static org.craftercms.studio.api.v2.dal.QueryParameterNames.*; @@ -171,7 +169,7 @@ default Map> getNextPublishPackages() { return emptyMap(); } return packageIds.stream() - .collect(Collectors.groupingBy(PublishPackageId::siteId, + .collect(groupingBy(PublishPackageId::siteId, LinkedHashMap::new, Collectors.toList())); } @@ -351,6 +349,31 @@ default Collection getPublishItems(final String siteId, final long Collection getPublishItems(@Param(SITE_ID) String siteId, @Param(PACKAGE_ID) long packageId, @Param(OFFSET) Integer offset, @Param(LIMIT) Integer limit); + + /** + * Get the user requested paths for the given package, in a map. + * Map keys are true for delete actions, false for other actions. + * + * @param siteId the site id + * @param packageId the package id + * @return the user requested paths by action + */ + default Map> getUserRequestedPathMap(String siteId, long packageId) { + return getUserRequestedPaths(siteId, packageId).stream() + .collect(groupingBy(pp -> pp.getAction() == PublishItem.Action.DELETE, + HashMap::new, + Collectors.mapping(PublishPath::getPath, Collectors.toList()))); + } + + /** + * Get the {@link PublishPath} items for the given package user-requested items + * + * @param siteId the site id + * @param packageId the package id + * @return the user requested action-path pairs + */ + Collection getUserRequestedPaths(@Param(SITE_ID) String siteId, @Param(PACKAGE_ID) long packageId); + /** * Get the paginated list of publish items (with metadata) for the given package * diff --git a/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishPath.java b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishPath.java new file mode 100644 index 0000000000..c2ad48ef62 --- /dev/null +++ b/src/main/java/org/craftercms/studio/api/v2/dal/publish/PublishPath.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.api.v2.dal.publish; + +/** + * Simplified Publish item path-action pair. + */ +public class PublishPath { + private String path; + private PublishItem.Action action; + + public PublishItem.Action getAction() { + return action; + } + + public void setAction(PublishItem.Action action) { + this.action = action; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java index bbb7a1312a..058b308926 100644 --- a/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java +++ b/src/main/java/org/craftercms/studio/api/v2/service/publish/PublishService.java @@ -195,6 +195,21 @@ CalculatedPublishPackageResult calculatePublishPackage(String siteId, String pub Collection paths, Collection commitIds) throws ServiceLayerException, IOException; + /** + * Recalculate a publish package + * This will retrieve the user-requested items of a previously submitted package and + * recalculate the dependencies. + * + * @param site site id + * @param packageId package id + * @param target the publishing target + * @return the recalculated package + * @throws SiteNotFoundException if the site is not found + * @throws PublishPackageNotFoundException if the package is not found + */ + CalculatedPublishPackageResult recalculatePublishPackage(String site, long packageId, String target) + throws ServiceLayerException; + /** * Get the submitted package containing the given item * diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java index 13dffa3083..a6b4f8249f 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/PublishController.java @@ -40,10 +40,7 @@ import org.craftercms.studio.model.rest.PaginatedResultList; import org.craftercms.studio.model.rest.Result; import org.craftercms.studio.model.rest.ResultOne; -import org.craftercms.studio.model.rest.publish.AvailablePublishingTargets; -import org.craftercms.studio.model.rest.publish.CalculatePublishPackageRequest; -import org.craftercms.studio.model.rest.publish.EnablePublisherRequest; -import org.craftercms.studio.model.rest.publish.PublishPackageRequest; +import org.craftercms.studio.model.rest.publish.*; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -199,6 +196,20 @@ public ResultOne calculatePublishPackage(@PathVa return result; } + @PostMapping(PATH_PARAM_SITE + PACKAGE + PATH_PARAM_PACKAGE + RECALCULATE) + public ResultOne recalculate(@PathVariable @NotEmpty @ValidSiteId String site, + @PathVariable @Positive long packageId, + @RequestBody RecalculatePublishPackageRequest request) + throws ServiceLayerException, IOException { + CalculatedPublishPackageResult calculatedPackage = publishService.recalculatePublishPackage(site, + packageId, request.getPublishingTarget()); + + ResultOne result = new ResultOne<>(); + result.setResponse(OK); + result.setEntity(RESULT_KEY_PACKAGE, calculatedPackage); + return result; + } + @PostMapping(PATH_PARAM_SITE + ENABLE_PUBLISHER) public Result enablePublisher(@PathVariable @NotEmpty @ValidSiteId String site, @RequestBody EnablePublisherRequest request) { sitesService.enablePublishing(site, request.isEnable()); diff --git a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java index 3fd29c0f5f..455c745fda 100644 --- a/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java +++ b/src/main/java/org/craftercms/studio/controller/rest/v2/RequestMappingConstants.java @@ -111,6 +111,7 @@ public final class RequestMappingConstants { public static final String PATH_PARAM_PACKAGE = "/{packageId}"; public static final String ITEMS = "/items"; public static final String CALCULATE = "/calculate"; + public static final String RECALCULATE = "/recalculate"; /** Dependency Controller */ public static final String DEPENDENCY = "/dependency"; diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java index 5dd40a2cb0..c72ae0abeb 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/publish/PublishServiceImpl.java @@ -130,6 +130,14 @@ public CalculatedPublishPackageResult calculatePublishPackage(@SiteId String sit return publishServiceInternal.calculatePublishPackage(siteId, publishingTarget, paths, commitIds); } + @Override + @RequirePackageExists + @HasPermission(type = DefaultPermission.class, action = PERMISSION_CONTENT_READ) + public CalculatedPublishPackageResult recalculatePublishPackage(@SiteId String site, @PackageId long packageId, String target) + throws ServiceLayerException { + return publishServiceInternal.recalculatePublishPackage(site, packageId, target); + } + @Override @RequireSiteExists @HasPermission(type = DefaultPermission.class, action = PERMISSION_GET_PUBLISHING_QUEUE) diff --git a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java index f9769333b8..cadf8f3cf2 100644 --- a/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java +++ b/src/main/java/org/craftercms/studio/impl/v2/service/publish/internal/PublishServiceInternalImpl.java @@ -188,6 +188,20 @@ public CalculatedPublishPackageResult calculatePublishPackage(final String siteI return new CalculatedPublishPackageResult(corePackagePaths, deletedPaths, hardDependencies, softDependencies); } + @Override + public CalculatedPublishPackageResult recalculatePublishPackage(String siteId, long packageId, String target) + throws ServiceLayerException { + Map> publishPaths = publishDao.getUserRequestedPathMap(siteId, packageId); + + Set corePackagePaths = new HashSet<>(publishPaths.get(false)); + Collection deletedPaths = publishPaths.get(true); + + Collection softDependencies = dependencyServiceInternal.getPublishingSoftDependencies(siteId, corePackagePaths); + // Get hard deps of them all + Collection hardDependencies = dependencyServiceInternal.getHardDependencies(siteId, target, corePackagePaths); + return new CalculatedPublishPackageResult(corePackagePaths, deletedPaths, hardDependencies, softDependencies); + } + @Override public PublishPackage getReadyPackageForItem(final String siteId, final String path, final boolean includeChildren) { return publishDao.getReadyPackageForItem(siteId, path, includeChildren); @@ -676,6 +690,7 @@ protected long buildInitialPublishPackage(Site site, String publishingTarget, bo /** * Create a collection of {@link PublishItem} objects for a publish all request. + * * @param site the site * @return the collection of publish items */ diff --git a/src/main/java/org/craftercms/studio/model/rest/publish/RecalculatePublishPackageRequest.java b/src/main/java/org/craftercms/studio/model/rest/publish/RecalculatePublishPackageRequest.java new file mode 100644 index 0000000000..c25abb15f0 --- /dev/null +++ b/src/main/java/org/craftercms/studio/model/rest/publish/RecalculatePublishPackageRequest.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007-2024 Crafter Software Corporation. All Rights Reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.craftercms.studio.model.rest.publish; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import org.craftercms.commons.validation.annotations.param.EsapiValidatedParam; + +import static org.craftercms.commons.validation.annotations.param.EsapiValidationType.ALPHANUMERIC; + +/** + * Request for publish package recalculation + */ +public class RecalculatePublishPackageRequest { + @NotEmpty + @Size(max = 20) + @EsapiValidatedParam(type = ALPHANUMERIC) + private String publishingTarget; + + public String getPublishingTarget() { + return publishingTarget; + } + + public void setPublishingTarget(String publishingTarget) { + this.publishingTarget = publishingTarget; + } +} diff --git a/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml b/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml index 1d22f7938d..bfe2e0d6fd 100644 --- a/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml +++ b/src/main/resources/org/craftercms/studio/api/v2/dal/publish/PublishDAO.xml @@ -243,6 +243,16 @@ + +