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

Publisher API fixes #3680

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
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
123 changes: 96 additions & 27 deletions src/main/api/studio-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6353,7 +6353,7 @@ paths:
'500':
$ref: '#/components/responses/InternalServerError'

/api/2/publish/{siteId}:
/api/2/publish/{siteId}/package:
post:
tags:
- publishing
Expand Down Expand Up @@ -6396,8 +6396,8 @@ paths:
type: string
description: package comment
responses:
'200':
description: OK
'201':
description: Created
content:
application/json:
schema:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -6590,21 +6634,25 @@ paths:
description: Limit for pagination
required: false
schema:
type: integer
format: int32
type: integer
format: int32
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
allOf:
- $ref: '#/components/schemas/PaginatedResponse'
properties:
response:
$ref: '#/components/schemas/ApiResponse'
allOf:
- $ref: '#/components/schemas/PaginatedResponse'
- $ref: '#/components/schemas/PublishPackageDetails'
items:
type: array
description: list of items to be published
items:
$ref: '#/components/schemas/PublishItem'
'400':
$ref: '#/components/responses/BadRequest'
'401':
Expand All @@ -6614,13 +6662,13 @@ paths:
'500':
$ref: '#/components/responses/InternalServerError'

/api/2/publish/{siteId}/package/{packageId}/status:
get:
/api/2/publish/{siteId}/package/{packageId}/recalculate:
post:
tags:
- publishing
summary: Get package status without the actual items list
description: 'Required permission "get_publishing_queue"'
operationId: getPublishPackageStatus
summary: Recalculate a complete publish package user-requested items
description: 'Required permission "content_read"'
operationId: recalculatePublishPackage
parameters:
- name: siteId
in: path
Expand All @@ -6635,6 +6683,17 @@ paths:
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
Expand All @@ -6646,9 +6705,30 @@ paths:
response:
$ref: '#/components/schemas/ApiResponse'
package:
$ref: '#/components/schemas/PublishPackage'
progress:
$ref: '#/components/schemas/PublishTaskProgress'
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':
Expand Down Expand Up @@ -9487,17 +9567,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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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 {
}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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 {
}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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();
}

}
Loading