fix(manager-api): allow deletion of an API image
MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/OrganizationResourceImpl.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/rest/impl/OrganizationResourceImpl.java
@@ -552,6 +552,12 @@ public class OrganizationResourceImpl implements IOrganizationResource, DataAcce
apiService.deleteApi(organizationId, apiId);
}
+ @Override
+ public void deleteApiImage(String organizationId, String apiId) throws ApiNotFoundException, NotAuthorizedException {
+ securityContext.checkPermissions(PermissionType.apiEdit, organizationId);
+ apiService.deleteApiImage(organizationId, apiId);
+ }
+
@Override
public SearchResultsBean<AuditEntryBean> getApiActivity(String organizationId, String apiId, int page, int pageSize)
throws ApiNotFoundException, NotAuthorizedException {

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
@@ -948,6 +948,22 @@ public class ApiService implements DataAccessUtilMixin {
});
}
+ public void deleteApiImage(String organizationId, String apiId)
+ throws OrganizationNotFoundException, ApiVersionNotFoundException, NotAuthorizedException {
+
+ tryAction(() -> {
+ ApiBean apiForUpdate = getApiFromStorage(organizationId, apiId);
+ EntityUpdatedData auditData = new EntityUpdatedData();
+ if (apiForUpdate.getImage() != null){
+ blobStore.remove(apiForUpdate.getImage());
+ apiForUpdate.setImage(null);
+ auditData.addChange("image", apiForUpdate.getImage(), null);
+ }
+ storage.updateApi(apiForUpdate);
+ storage.createAuditEntry(AuditUtils.apiUpdated(apiForUpdate, auditData, securityContext));
+ });
+ }
+
public List<PolicySummaryBean> listApiPolicies(String organizationId, String apiId, String version)
throws OrganizationNotFoundException, ApiVersionNotFoundException, NotAuthorizedException {

MODIFY
manager/api/rest/src/main/java/io/apiman/manager/api/rest/IOrganizationResource.java
manager/api/rest/src/main/java/io/apiman/manager/api/rest/IOrganizationResource.java
@@ -945,6 +945,24 @@ public interface IOrganizationResource {
@PathParam("apiId") String apiId, UpdateApiBean bean)
throws ApiNotFoundException, NotAuthorizedException;
+ /**
+ * Use this endpoint to delete an API Image
+ * @summary Delete API Image
+ * @param organizationId The Organization ID.
+ * @param apiId The API ID.
+ * @statuscode 204 If the API is updated successfully.
+ * @statuscode 404 If the API does not exist.
+ * @throws ApiNotFoundException when trying to get, update, or delete an API that does not exist
+ * @throws NotAuthorizedException when the user attempts to do or see something that they are not authorized (do not have permission) to
+ */
+ @RolesAllowed("apiuser")
+ @DELETE
+ @Path("{organizationId}/apis/{apiId}/image")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void deleteApiImage(@PathParam("organizationId") String organizationId,
+ @PathParam("apiId") String apiId)
+ throws ApiNotFoundException, NotAuthorizedException;
+
@RolesAllowed("apiuser")
@PUT
@Consumes(MediaType.APPLICATION_JSON)

ADD
manager/test/api/src/test/resources/test-plan-data/blob/delete-reference/001_delete-api-image.resttest
+DELETE /organizations/Organization1/apis/API1/image admin/admin
+Content-Type: application/json
+
+----
+204
+

ADD
manager/test/api/src/test/resources/test-plan-data/blob/delete-reference/002_get-api-assert-image-deleted.resttest
+GET /organizations/Organization1/apis/API1 admin/admin
+----
+200
+Content-Type: application/json
+
+{
+ "organization" : {
+ "id" : "Organization1"
+ },
+ "id" : "API1",
+ "name" : "API 1",
+ "description" : "This is the description of API 1.",
+ "createdBy" : "admin",
+ "image": null
+}

MODIFY
manager/test/api/src/test/resources/test-plans/blob-testPlan.xml
manager/test/api/src/test/resources/test-plans/blob-testPlan.xml
<testGroup name="Blob export/import subsystem">
<test name="Full export">test-plan-data/blob/export/000_export.resttest</test>
</testGroup>
+
+ <testGroup name="Delete Blob Reference on API">
+ <test name="Delete blob from API">test-plan-data/blob/delete-reference/001_delete-api-image.resttest</test>
+ <test name="Verify blob reference is deleted">test-plan-data/blob/delete-reference/002_get-api-assert-image-deleted.resttest</test>
+ </testGroup>
</testPlan>

MODIFY
manager/ui/war/plugins/api-manager/html/api/api-devportal.html
manager/ui/war/plugins/api-manager/html/api/api-devportal.html
<button class="btn btn-primary" ng-click="openImageCropper()" type="button" data-field="uploadButton">
<span class="fa fa-upload"></span> Upload image
</button>
+ <button
+ class="btn btn-primary"
+ ng-click="deleteImage()"
+ type="button"
+ ng-show="data.latestImage"
+ >
+ <span class="fa fa-trash"></span> Delete image
+ </button>
</div>
</div>
</div>

MODIFY
manager/ui/war/plugins/api-manager/ts/api/api-devportal.ts
manager/ui/war/plugins/api-manager/ts/api/api-devportal.ts
@@ -173,6 +173,7 @@ function devPortalBusinessLogic(
$scope.updateFeaturedApi = invertFeaturedApi;
$scope.openImageCropper = openImageCropperModal;
$scope.getImageEndpoint = getImageEndpoint;
+ $scope.deleteImage = deleteApiImage;
$scope.onDiscoverabilityChange = onDiscoverabilityChange;
$scope.getDiscoverabilityDescription = getDiscoverabilityDescription;
@@ -396,6 +397,16 @@ function devPortalBusinessLogic(
// We may get a null when a plan hasn't yet been attached, so show the default.
return descriptions[discoverability|| 'ORG_MEMBERS'];
}
+
+ function deleteApiImage(): void {
+ const api: ApiBean = $scope.data.apiVersion.api;
+ DevPortalService.deleteApiImage(api.organization.id, api.id).then(() => {
+ Logger.info('Deleted Blob reference: {0}', api.image);
+ $scope.data.latestImage = null;
+ $scope.data.apiVersion.api.image = null;
+ $scope.doSave();
+ });
+ }
}
_module.controller("Apiman.DevPortalImageCropper",

MODIFY
manager/ui/war/plugins/api-manager/ts/rpc.ts
manager/ui/war/plugins/api-manager/ts/rpc.ts
@@ -90,6 +90,12 @@ _module.factory('DevPortalService', ['$http', 'Configuration', '$q',
data: bean
});
},
+ deleteApiImage: (orgId: string, apiId: string): Promise<void> => {
+ return $http({
+ method: 'DELETE',
+ url: `${Configuration.api.endpoint}/organizations/${orgId}/apis/${apiId}/image`
+ });
+ },
tagApi: (orgId: string, apiId: string, bean: KeyValueTagDto): Promise<any> => {
return $http({
method: 'PUT',

fix(manager-api): allow deletion of an API image