diff --git a/samples/Drupal8/DevPortal/apicatalog-config.json b/samples/Drupal8/DevPortal/apicatalog-config.json index 6490a22..480a5d5 100755 --- a/samples/Drupal8/DevPortal/apicatalog-config.json +++ b/samples/Drupal8/DevPortal/apicatalog-config.json @@ -1,6 +1,7 @@ { "fields":{ - "field_business_unit":"Petstore", + "field_image": "pets.jpeg", + "field_business_unit":"Petstore", "field_drop_down":"one", "field_multi_value":[ "value1", diff --git a/samples/Drupal8/DevPortal/shared-pom.xml b/samples/Drupal8/DevPortal/shared-pom.xml index b8b8fdc..56eee5c 100755 --- a/samples/Drupal8/DevPortal/shared-pom.xml +++ b/samples/Drupal8/DevPortal/shared-pom.xml @@ -26,7 +26,7 @@ com.apigee.smartdocs.config apigee-smartdocs-maven-plugin - 2.1.1 + 2.1.2 smartdocs-deploy diff --git a/samples/Drupal8/DevPortal/specs/mock.yaml b/samples/Drupal8/DevPortal/specs/Petstore.yaml similarity index 100% rename from samples/Drupal8/DevPortal/specs/mock.yaml rename to samples/Drupal8/DevPortal/specs/Petstore.yaml diff --git a/samples/Drupal8/DevPortal/specs/pets.jpeg b/samples/Drupal8/DevPortal/specs/pets.jpeg new file mode 100644 index 0000000..1b664e1 Binary files /dev/null and b/samples/Drupal8/DevPortal/specs/pets.jpeg differ diff --git a/samples/Drupal8/README.md b/samples/Drupal8/README.md index 76c6b66..d29ae47 100755 --- a/samples/Drupal8/README.md +++ b/samples/Drupal8/README.md @@ -96,9 +96,12 @@ For example, the default Categories field on API Doc is associated with the "API Here is a sample metadata file (apicatalog-config.json) : +** NOTE: Support for API spec image is available from v2.1.2. Make sure the image is in the same folder as the spec and include the name of the file in the config file (see below) + ``` { "fields":{ + "field_image": "pets.jpeg", "field_business_unit": "ABC", "field_multi_value":[ "item1", diff --git a/samples/Drupal8/media/screenshot2.png b/samples/Drupal8/media/screenshot2.png index a92a35b..9782cca 100755 Binary files a/samples/Drupal8/media/screenshot2.png and b/samples/Drupal8/media/screenshot2.png differ diff --git a/src/main/java/com/apigee/smartdocs/config/mavenplugin/APIDocsMojo.java b/src/main/java/com/apigee/smartdocs/config/mavenplugin/APIDocsMojo.java index 38962ce..c30a098 100755 --- a/src/main/java/com/apigee/smartdocs/config/mavenplugin/APIDocsMojo.java +++ b/src/main/java/com/apigee/smartdocs/config/mavenplugin/APIDocsMojo.java @@ -17,6 +17,7 @@ package com.apigee.smartdocs.config.mavenplugin; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import org.apache.maven.plugin.MojoExecutionException; @@ -26,7 +27,6 @@ import com.apigee.smartdocs.config.rest.PortalRestUtil; import com.apigee.smartdocs.config.utils.ServerProfile; -import com.google.api.client.util.Key; /** ¡¡ * Goal to create API Docs in Apigee Developer Portal @@ -37,7 +37,7 @@ * @phase install */ -public class APIDocsMojo extends GatewayAbstractMojo { +public class APIDocsMojo extends PortalAbstractMojo { static Logger logger = LoggerFactory.getLogger(APIDocsMojo.class); private static File[] files = null; @@ -126,8 +126,6 @@ public void execute() throws MojoExecutionException, MojoFailureException { return; } - Logger logger = LoggerFactory.getLogger(APIDocsMojo.class); - try { init(); if (buildOption == OPTIONS.none) { @@ -205,7 +203,12 @@ public void getOpenAPISpecs() throws MojoExecutionException { // Scan the directory for files. String directory = serverProfile.getPortalDirectory(); logger.info("Get OpenAPI Specs from " + directory); - files = new File(directory).listFiles(); + files = new File(directory).listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".yaml") || name.endsWith(".yml") || name.endsWith(".json"); + } + }); } } diff --git a/src/main/java/com/apigee/smartdocs/config/mavenplugin/GatewayAbstractMojo.java b/src/main/java/com/apigee/smartdocs/config/mavenplugin/PortalAbstractMojo.java similarity index 98% rename from src/main/java/com/apigee/smartdocs/config/mavenplugin/GatewayAbstractMojo.java rename to src/main/java/com/apigee/smartdocs/config/mavenplugin/PortalAbstractMojo.java index 5bbc5b9..7d7f90c 100755 --- a/src/main/java/com/apigee/smartdocs/config/mavenplugin/GatewayAbstractMojo.java +++ b/src/main/java/com/apigee/smartdocs/config/mavenplugin/PortalAbstractMojo.java @@ -22,7 +22,7 @@ import com.apigee.smartdocs.config.utils.ServerProfile; import com.apigee.smartdocs.config.utils.PortalField; -public abstract class GatewayAbstractMojo extends AbstractMojo { +public abstract class PortalAbstractMojo extends AbstractMojo { /** * Directory containing the build files. @@ -173,7 +173,7 @@ public abstract class GatewayAbstractMojo extends AbstractMojo { public ServerProfile buildProfile; - public GatewayAbstractMojo() { + public PortalAbstractMojo() { super(); } diff --git a/src/main/java/com/apigee/smartdocs/config/rest/PortalRestUtil.java b/src/main/java/com/apigee/smartdocs/config/rest/PortalRestUtil.java index e79990f..26bc778 100755 --- a/src/main/java/com/apigee/smartdocs/config/rest/PortalRestUtil.java +++ b/src/main/java/com/apigee/smartdocs/config/rest/PortalRestUtil.java @@ -203,6 +203,12 @@ public static class APIDocObject { public Object links; } + public static class ImageDocObject { + public JSONAPI jsonapi; + public Data data; + public Object links; +} + public static class APIErrorObject { public JSONAPI jsonapi; public List errors; @@ -245,6 +251,7 @@ public static class Body{ public static class Relationships{ public Relationships_Spec field_apidoc_spec; + public Relationships_Spec field_image; } public static class Relationships_Data{ @@ -320,7 +327,6 @@ public static HttpResponse authenticate(ServerProfile profile) throws IOExceptio * Run Cron */ public static void runCron(ServerProfile profile) throws IOException { - HttpResponse response = null; try { // First authenticate. authenticate(profile); @@ -330,7 +336,7 @@ public static void runCron(ServerProfile profile) throws IOException { restRequest.setReadTimeout(0); logger.info("Running Cron"); - response = PortalRestUtil.executeRequest(restRequest); + PortalRestUtil.executeRequest(restRequest); } catch (HttpResponseException e) { throw e; } @@ -340,7 +346,9 @@ public static void runCron(ServerProfile profile) throws IOException { /** * Helper function to build the body for API Doc creations and updates. */ - private static ByteArrayContent getAPIDocContent(ServerProfile profile, SpecObject spec, String uuid, String docId, boolean isUpdate) throws IOException { + private static ByteArrayContent constructAPIDocRequestBody(ServerProfile profile, SpecObject spec, String uuid, String docId, String imageId, boolean isUpdate) throws IOException { + boolean hasImage = false; + File imageFile = null; Gson gson = new Gson(); JsonObject body = new JsonObject(); if (spec.getDescription() != null) { @@ -368,8 +376,14 @@ private static ByteArrayContent getAPIDocContent(ServerProfile profile, SpecObje for (String key : fieldsMap.keySet()) { if(fieldsMap.get(key) instanceof List){ attributes.add(key, gson.toJsonTree(fieldsMap.get(key))); - }else - attributes.addProperty(key, (String)fieldsMap.get(key)); + } + //no need to add to attributes for "field_image" + else if (key!=null && key.equals("field_image")){ + hasImage = true; + imageFile = new File(profile.getPortalDirectory()+"/"+(String)fieldsMap.get(key)); + } + else + attributes.addProperty(key, (String)fieldsMap.get(key)); } } @@ -407,8 +421,26 @@ private static ByteArrayContent getAPIDocContent(ServerProfile profile, SpecObje field_apidoc_spec_data.addProperty("id", docId); JsonObject field_apidoc_spec = new JsonObject(); field_apidoc_spec.add("data", field_apidoc_spec_data); - + relationships.add("field_apidoc_spec", field_apidoc_spec); + + //field_image + if(hasImage) { + JsonObject field_image_data = new JsonObject(); + field_image_data.addProperty("type", "media--image"); + if(!isUpdate) { + ImageDocObject imageDoc = importImage(profile, imageFile); + String mediaImageId = importMediaImage(profile, imageFile.getName(), imageDoc.data.id); + field_image_data.addProperty("id", mediaImageId); + } + else { + field_image_data.addProperty("id", imageId); + } + JsonObject field_image = new JsonObject(); + field_image.add("data", field_image_data); + + relationships.add("field_image", field_image); + } JsonObject data = new JsonObject(); data.addProperty("type", "node--apidoc"); @@ -564,6 +596,84 @@ public static APIDocObject importAPIDoc(ServerProfile profile, File file) throws } } + /** + * Import an image + */ + public static ImageDocObject importImage(ServerProfile profile, File imageFile) throws IOException { + HttpResponse response = null; + try { + logger.info("Importing image.."); + byte[] fileBytes = Files.readAllBytes(imageFile.toPath()); + ByteArrayContent fileContent = new ByteArrayContent("application/octet-stream", fileBytes); + HttpRequest restRequest = REQUEST_FACTORY + .buildPostRequest(new GenericUrl(profile.getPortalURL() + "/jsonapi/media/image/field_media_image"), fileContent); + HttpHeaders headers = restRequest.getHeaders(); + headers.setAccept("application/vnd.api+json"); + headers.set("Content-Disposition", "file; filename=\""+imageFile.getName()+"\""); + headers.setBasicAuthentication(profile.getPortalUserName(), profile.getPortalPassword()); + restRequest.setReadTimeout(0); + response = restRequest.execute(); + logger.info("Image import complete.."); + Gson gson = new Gson(); + Reader reader = new InputStreamReader(response.getContent()); + + ImageDocObject model = gson.fromJson(reader, ImageDocObject.class); + if(model != null && model.data!=null) { + logger.info("Image uuid:" + model.data.id); + return model; + } + return null; + + } catch (HttpResponseException e) { + throw new IOException(exceptionHandler(e)); + } + } + + /** + * Configure media-image + */ + + public static String importMediaImage(ServerProfile profile, String fileName, String imageId) throws IOException { + HttpResponse response = null; + try { + String payload = "{\n" + + " \"data\": {\n" + + " \"type\": \"media--image\",\n" + + " \"attributes\": {\n" + + " \"name\": \""+fileName+"\"\n" + + " },\n" + + " \"relationships\": {\n" + + " \"field_media_image\": {\n" + + " \"data\": {\n" + + " \"type\": \"file--file\",\n" + + " \"id\": \""+imageId+"\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + ByteArrayContent content = new ByteArrayContent("application/vnd.api+json", payload.getBytes()); + HttpRequest restRequest = REQUEST_FACTORY + .buildPostRequest(new GenericUrl(profile.getPortalURL() + "/jsonapi/media/image"), content); + HttpHeaders headers = restRequest.getHeaders(); + headers.setAccept("application/vnd.api+json"); + headers.setBasicAuthentication(profile.getPortalUserName(), profile.getPortalPassword()); + restRequest.setReadTimeout(0); + response = restRequest.execute(); + Gson gson = new Gson(); + Reader reader = new InputStreamReader(response.getContent()); + ImageDocObject model = gson.fromJson(reader, ImageDocObject.class); + if(model != null && model.data!=null) { + logger.info("media--image uuid:" + model.data.id); + return model.data.id; + } + } + catch (HttpResponseException e) { + throw new IOException(exceptionHandler(e)); + } + return null; + } + /** * Import an API Doc */ @@ -572,7 +682,7 @@ public static void updateAPIDoc(ServerProfile profile, File file, APIDocResponse SpecObject spec = parseSpec(profile, file); logger.info("Update API catalog"); - ByteArrayContent content = getAPIDocContent(profile, spec, doc.data.get(0).id, doc.data.get(0).relationships.field_apidoc_spec.data.id, true); + ByteArrayContent content = constructAPIDocRequestBody(profile, spec, doc.data.get(0).id, doc.data.get(0).relationships.field_apidoc_spec.data.id, doc.data.get(0).relationships.field_image.data.id, true); HttpRequest restPatchRequest = APACHE_REQUEST_FACTORY.buildRequest(HttpMethods.PATCH, new GenericUrl(profile.getPortalURL() + "/jsonapi/node/apidoc/"+doc.data.get(0).id), content); HttpHeaders patchHeaders = restPatchRequest.getHeaders(); @@ -607,7 +717,7 @@ public static String createAPIDoc(ServerProfile profile, File file, APIDocObject SpecObject spec = parseSpec(profile, file); logger.info("Creating spec.." + doc.data.id); - ByteArrayContent content = getAPIDocContent(profile, spec, doc.data.id, null, false); + ByteArrayContent content = constructAPIDocRequestBody(profile, spec, doc.data.id, null, null, false); HttpRequest restRequest = REQUEST_FACTORY .buildPostRequest(new GenericUrl(profile.getPortalURL() + "/jsonapi/node/apidoc"), content); HttpHeaders headers = restRequest.getHeaders();