fix(manager-api): fix updateApiVersion logic to support patch plan
feat(manager-api): allow email notifications to be explicitly toggled in `apiman.properties`
MODIFY
distro/tomcat/src/main/resources/overlay/conf/apiman.properties
distro/tomcat/src/main/resources/overlay/conf/apiman.properties
@@ -58,9 +58,10 @@ apiman-manager-ui.org-create-admin-only=false
apiman-manager.config.features.rest-response-should-contain-stacktraces=false
# Enable or disable the entire Apiman notifications subsystem.
-apiman-manager.config.notifications.enable=true
+apiman-manager.notifications.enable=true
# Email notifications settings.
+apiman-manager.notifications.email.enable=false
# apiman-manager.notifications.email.smtp.mock=false
# apiman-manager.notifications.email.smtp.ssl=false
# apiman-manager.notifications.email.smtp.startTLSMode=DISABLED

MODIFY
distro/wildfly/src/main/resources/overlay/standalone/configuration/apiman.properties
distro/wildfly/src/main/resources/overlay/standalone/configuration/apiman.properties
apiman.plugins.repositories=https://repo1.maven.org/maven2/,http://repository.jboss.org/nexus/content/groups/public/
apiman-manager.plugins.registries=https://cdn.jsdelivr.net/gh/apiman/apiman-plugin-registry@master/registry.json
-# Apiman Manager logging. standard, json or a FQDN implementing IApimanLogger
-apiman-manager.config.logger=standard
-
# Apiman Manager secret key for data encryption
#apiman.encrypter.type=io.apiman.common.util.crypt.AesDataEncrypter
#apiman.encrypter.secretKey=
@@ -61,9 +58,10 @@ apiman-manager-ui.org-create-admin-only=false
apiman-manager.config.features.rest-response-should-contain-stacktraces=false
# Enable or disable the entire Apiman notifications subsystem.
-apiman-manager.config.notifications.enable=true
+apiman-manager.notifications.enable=true
# Email notifications settings.
+apiman-manager.notifications.email.enable=false
# apiman-manager.notifications.email.smtp.mock=false
# apiman-manager.notifications.email.smtp.ssl=false
# apiman-manager.notifications.email.smtp.startTLSMode=DISABLED

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/ApiPlanBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/ApiPlanBean.java
@@ -22,6 +22,8 @@ import java.util.StringJoiner;
import javax.persistence.Column;
import javax.persistence.Embeddable;
+import org.hibernate.annotations.ColumnDefault;
+
/**
* Models a plan+version that is available for use with a particular API. This
* makes the Plan available when forming a Contract between an app and an API.
@@ -38,8 +40,10 @@ public class ApiPlanBean implements Serializable {
@Column(name = "version", nullable = false)
private String version;
@Column(name = "expose_in_portal", nullable = false)
+ @ColumnDefault("false")
private Boolean exposeInPortal = false;
@Column(name = "requires_approval", nullable = false)
+ @ColumnDefault("false")
private Boolean requiresApproval = false;
/**
@@ -114,12 +118,11 @@ public class ApiPlanBean implements Serializable {
return false;
}
ApiPlanBean that = (ApiPlanBean) o;
- return Objects.equals(planId, that.planId) && Objects.equals(version, that.version) && Objects.equals(exposeInPortal,
- that.exposeInPortal) && Objects.equals(requiresApproval, that.requiresApproval);
+ return Objects.equals(planId, that.planId) && Objects.equals(version, that.version);
}
@Override
public int hashCode() {
- return Objects.hash(planId, version, exposeInPortal, requiresApproval);
+ return Objects.hash(planId, version);
}
}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/UpdateApiVersionBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/UpdateApiVersionBean.java
*/
package io.apiman.manager.api.beans.apis;
+import io.apiman.manager.api.beans.apis.dto.ApiPlanBeanDto;
+
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.StringJoiner;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -42,7 +46,7 @@ public class UpdateApiVersionBean implements Serializable {
private Boolean parsePayload;
private Boolean publicAPI;
private Boolean disableKeysStrip;
- private Set<ApiPlanBean> plans;
+ private Set<ApiPlanBeanDto> plans;
private String extendedDescription;
private Boolean exposeInPortal;
@@ -111,14 +115,14 @@ public class UpdateApiVersionBean implements Serializable {
/**
* @return the plans
*/
- public Set<ApiPlanBean> getPlans() {
+ public Set<ApiPlanBeanDto> getPlans() {
return plans;
}
/**
* @param plans the plans to set
*/
- public void setPlans(Set<ApiPlanBean> plans) {
+ public void setPlans(Set<ApiPlanBeanDto> plans) {
this.plans = plans;
}
@@ -192,30 +196,43 @@ public class UpdateApiVersionBean implements Serializable {
return this;
}
- /* (non-Javadoc)
- * @see java.lang.Object#toString()
- */
@Override
- @SuppressWarnings("nls")
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UpdateApiVersionBean that = (UpdateApiVersionBean) o;
+ return Objects.equals(endpoint, that.endpoint) && endpointType == that.endpointType && endpointContentType == that.endpointContentType
+ && Objects.equals(endpointProperties, that.endpointProperties) && Objects.equals(gateways, that.gateways)
+ && Objects.equals(parsePayload, that.parsePayload) && Objects.equals(publicAPI, that.publicAPI) && Objects.equals(
+ disableKeysStrip, that.disableKeysStrip) && Objects.equals(plans, that.plans) && Objects.equals(extendedDescription,
+ that.extendedDescription) && Objects.equals(exposeInPortal, that.exposeInPortal);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(endpoint, endpointType, endpointContentType, endpointProperties, gateways, parsePayload, publicAPI, disableKeysStrip, plans,
+ extendedDescription,
+ exposeInPortal);
+ }
+
+ @Override
public String toString() {
- final int maxLen = 10;
- return "UpdateApiVersionBean [endpoint=" + endpoint + ", endpointType=" + endpointType
- + ", endpointProperties=" + toString(this.endpointProperties.entrySet(), maxLen)
- + ", gateways=" + (gateways != null ? toString(gateways, maxLen) : null) + ", publicAPI="
- + publicAPI + ", plans=" + (plans != null ? toString(plans, maxLen) : null) + "]";
- }
-
- @SuppressWarnings("nls")
- private String toString(Collection<?> collection, int maxLen) {
- StringBuilder builder = new StringBuilder();
- builder.append("[");
- int i = 0;
- for (Iterator<?> iterator = collection.iterator(); iterator.hasNext() && i < maxLen; i++) {
- if (i > 0)
- builder.append(", ");
- builder.append(iterator.next());
- }
- builder.append("]");
- return builder.toString();
+ return new StringJoiner(", ", UpdateApiVersionBean.class.getSimpleName() + "[", "]")
+ .add("endpoint='" + endpoint + "'")
+ .add("endpointType=" + endpointType)
+ .add("endpointContentType=" + endpointContentType)
+ .add("endpointProperties=" + endpointProperties)
+ .add("gateways=" + gateways)
+ .add("parsePayload=" + parsePayload)
+ .add("publicAPI=" + publicAPI)
+ .add("disableKeysStrip=" + disableKeysStrip)
+ .add("plans=" + plans)
+ .add("extendedDescription='" + extendedDescription + "'")
+ .add("exposeInPortal=" + exposeInPortal)
+ .toString();
}
}

ADD
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/dto/ApiPlanBeanDto.java
+package io.apiman.manager.api.beans.apis.dto;
+
+import java.util.Objects;
+import java.util.StringJoiner;
+
+/**
+ *
+ *
+ * @author Marc Savy {@literal <marc@blackparrotlabs.io>}
+ */
+public class ApiPlanBeanDto {
+ private String planId;
+ private String version;
+ private Boolean exposeInPortal;
+ private Boolean requiresApproval;
+
+ public ApiPlanBeanDto() {
+ }
+
+ public String getPlanId() {
+ return planId;
+ }
+
+ public ApiPlanBeanDto setPlanId(String planId) {
+ this.planId = planId;
+ return this;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public ApiPlanBeanDto setVersion(String version) {
+ this.version = version;
+ return this;
+ }
+
+ public Boolean getExposeInPortal() {
+ return exposeInPortal;
+ }
+
+ public ApiPlanBeanDto setExposeInPortal(Boolean exposeInPortal) {
+ this.exposeInPortal = exposeInPortal;
+ return this;
+ }
+
+ public Boolean getRequiresApproval() {
+ return requiresApproval;
+ }
+
+ public ApiPlanBeanDto setRequiresApproval(Boolean requiresApproval) {
+ this.requiresApproval = requiresApproval;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ApiPlanBeanDto that = (ApiPlanBeanDto) o;
+ return Objects.equals(planId, that.planId) && Objects.equals(version, that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(planId, version);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", ApiPlanBeanDto.class.getSimpleName() + "[", "]")
+ .add("planId='" + planId + "'")
+ .add("version='" + version + "'")
+ .add("exposeInPortal=" + exposeInPortal)
+ .add("requiresApproval=" + requiresApproval)
+ .toString();
+ }
+}

MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/dto/ApiVersionMapper.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/dto/ApiVersionMapper.java
package io.apiman.manager.api.beans.apis.dto;
+import io.apiman.manager.api.beans.apis.ApiPlanBean;
import io.apiman.manager.api.beans.apis.UpdateApiVersionBean;
+import java.util.Set;
+
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.NullValueMappingStrategy;
+import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.ReportingPolicy;
+import org.mapstruct.TargetType;
import org.mapstruct.factory.Mappers;
/**
* @author Marc Savy {@literal <marc@blackparrotlabs.io>}
*/
-@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
+@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE,
+ nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
+ nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
+ nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface ApiVersionMapper {
ApiVersionMapper INSTANCE = Mappers.getMapper(ApiVersionMapper.class);
@@ -25,4 +36,10 @@ public interface ApiVersionMapper {
@Mapping(source = "plans", target = "plans")
})
UpdateApiVersionBean toPublishedUpdateBean(UpdateApiVersionBean uvb);
+
+ Set<ApiPlanBeanDto> toDto(Set<ApiPlanBean> plans);
+
+ Set<ApiPlanBean> fromDto(Set<ApiPlanBeanDto> plans);
+
+ ApiPlanBeanDto merge(ApiPlanBeanDto source, @MappingTarget ApiPlanBeanDto target);
}

MODIFY
manager/api/core/src/main/java/io/apiman/manager/api/core/config/ApiManagerConfig.java
manager/api/core/src/main/java/io/apiman/manager/api/core/config/ApiManagerConfig.java
@@ -49,7 +49,7 @@ public abstract class ApiManagerConfig {
public static final String APIMAN_MANAGER_FEATURES_ORG_CREATE_ADMIN_ONLY = "apiman-manager.config.features.org-create-admin-only"; //$NON-NLS-1$
- public static final String APIMAN_MANAGER_CONFIG_NOTIFICATIONS = "apiman-manager.config.notifications";
+ public static final String APIMAN_MANAGER_CONFIG_NOTIFICATIONS = "apiman-manager.notifications";
/*
* Database/hibernate properties

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/notifications/email/SimpleMailNotificationService.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/notifications/email/SimpleMailNotificationService.java
@@ -54,7 +54,7 @@ public class SimpleMailNotificationService {
private static final IApimanLogger LOGGER = ApimanLoggerFactory.getLogger(SimpleMailNotificationService.class);
private static final Map<String, String> DEFAULT_HEADERS = Map.of("X-Notification-Producer", "Apiman");
- private IEmailSender emailSender;
+ private IEmailSender emailSender = new NullEmailSender();
private ApiManagerConfig config;
private QuteTemplateEngine templateEngine;
// String -> Map<Locale, EmailNotificationTemplate>
@@ -68,14 +68,13 @@ public class SimpleMailNotificationService {
public SimpleMailNotificationService(ApiManagerConfig config, QuteTemplateEngine templateEngine) {
this.templateEngine = templateEngine;
this.config = config;
- if (!config.getEmailNotificationProperties().isEmpty()) {
var smtpConfig = new SmtpEmailConfiguration(config.getEmailNotificationProperties());
- this.emailSender = new EmailSender(smtpConfig);
+ if (smtpConfig.isEnabled()) {
if (smtpConfig.isMock()) {
emailSender = new MockEmailSender();
- }
} else {
- emailSender = new MockEmailSender();
+ emailSender = new EmailSender(smtpConfig);
+ }
}
readEmailNotificationTemplatesFromFile();
}
@@ -234,4 +233,17 @@ public class SimpleMailNotificationService {
* Helpful for making Jackson deserialization a bit easier.
*/
private static final class ReasonMap extends HashMap<String, EmailTemplateFileEntry> { }
+
+ private static final class NullEmailSender implements IEmailSender {
+
+ @Override
+ public void sendPlaintext(String toEmail, String toName, String subject, String body, Map<String, String> headers) throws EmailException {
+
+ }
+
+ @Override
+ public void sendHtml(String toEmail, String toName, String subject, String htmlBody, String plainBody, Map<String, String> headers) throws EmailException {
+
+ }
+ }
}

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/notifications/email/SmtpEmailConfiguration.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/notifications/email/SmtpEmailConfiguration.java
@@ -6,6 +6,7 @@ import io.apiman.common.config.options.Predicates;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Map;
+import java.util.Objects;
import java.util.StringJoiner;
import static io.apiman.common.config.options.Predicates.anyOk;
@@ -17,6 +18,7 @@ import static io.apiman.common.config.options.Predicates.greaterThanZeroMsg;
*/
public class SmtpEmailConfiguration extends GenericOptionsParser {
public static final String PREFIX = "smtp.";
+ private boolean enabled;
private boolean mock;
private boolean ssl;
private StartTLSEnum startTLSMode = StartTLSEnum.OPTIONAL;
@@ -36,6 +38,8 @@ public class SmtpEmailConfiguration extends GenericOptionsParser {
@Override
protected void parse(Map<String, String> options) {
super.parse(options);
+ this.enabled = getBool(keys("enable"), false);
+ if (enabled) {
this.mock = getBool(keys(PREFIX + "mock"), false);
this.ssl = getBool(keys(PREFIX + "ssl"), true);
this.startTLSMode = getEnum(keys(PREFIX + "startTLSMode"), StartTLSEnum.OPTIONAL, StartTLSEnum::toValue);
@@ -46,6 +50,16 @@ public class SmtpEmailConfiguration extends GenericOptionsParser {
this.username = getString(keys(PREFIX + "username"), null, Predicates.anyOk(), "");
this.password = getString(keys(PREFIX + "password"), null, Predicates.anyOk(), "");
}
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public SmtpEmailConfiguration setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
public boolean isMock() {
return mock;
@@ -104,6 +118,7 @@ public class SmtpEmailConfiguration extends GenericOptionsParser {
@Override
public String toString() {
return new StringJoiner(", ", SmtpEmailConfiguration.class.getSimpleName() + "[", "]")
+ .add("enabled=" + enabled)
.add("mock=" + mock)
.add("ssl=" + ssl)
.add("startTLSMode=" + startTLSMode)
@@ -112,8 +127,29 @@ public class SmtpEmailConfiguration extends GenericOptionsParser {
.add("host='" + host + "'")
.add("port=" + port)
.add("authMethods=" + Arrays.toString(authMethods))
- .add("username='" + username + "'")
- .add("password='***'")
+ .add("username='xxxx'")
+ .add("password='xxxx'")
.toString();
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SmtpEmailConfiguration that = (SmtpEmailConfiguration) o;
+ return enabled == that.enabled && mock == that.mock && ssl == that.ssl && port == that.port && startTLSMode == that.startTLSMode && Objects.equals(fromName,
+ that.fromName) && Objects.equals(fromEmail, that.fromEmail) && Objects.equals(host, that.host) && Arrays.equals(authMethods,
+ that.authMethods) && Objects.equals(username, that.username) && Objects.equals(password, that.password);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(enabled, mock, ssl, startTLSMode, fromName, fromEmail, host, port, username, password);
+ result = 31 * result + Arrays.hashCode(authMethods);
+ return result;
+ }
}

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
@@ -21,6 +21,7 @@ import io.apiman.manager.api.beans.apis.NewApiVersionBean;
import io.apiman.manager.api.beans.apis.UpdateApiBean;
import io.apiman.manager.api.beans.apis.UpdateApiVersionBean;
import io.apiman.manager.api.beans.apis.dto.ApiBeanDto;
+import io.apiman.manager.api.beans.apis.dto.ApiPlanBeanDto;
import io.apiman.manager.api.beans.apis.dto.ApiVersionMapper;
import io.apiman.manager.api.beans.apis.dto.KeyValueTagDto;
import io.apiman.manager.api.beans.apis.dto.KeyValueTagMapper;
@@ -124,6 +125,7 @@ public class ApiService implements DataAccessUtilMixin {
private IGatewayLinkFactory gatewayLinkFactory;
private PolicyService policyService;
private IBlobStore blobStore;
+ private final ApiVersionMapper apiVersionMapper = ApiVersionMapper.INSTANCE;
private final ApiMapper apiMapper = ApiMapper.INSTANCE;
private final KeyValueTagMapper tagMapper = KeyValueTagMapper.INSTANCE;
@@ -345,7 +347,8 @@ public class ApiService implements DataAccessUtilMixin {
updatedApi.setEndpointProperties(cloneSource.getEndpointProperties());
updatedApi.setGateways(cloneSource.getGateways());
if (bean.getPlans() == null) {
- updatedApi.setPlans(cloneSource.getPlans());
+ Set<ApiPlanBeanDto> plans = ApiVersionMapper.INSTANCE.toDto(cloneSource.getPlans());
+ updatedApi.setPlans(plans);
}
if (bean.getPublicAPI() == null) {
updatedApi.setPublicAPI(cloneSource.isPublicAPI());
@@ -633,74 +636,87 @@ public class ApiService implements DataAccessUtilMixin {
}
}
- private ApiVersionBean updateApiVersionInternal(ApiVersionBean avb, UpdateApiVersionBean bean) throws ApiVersionNotFoundException {
+ private ApiVersionBean updateApiVersionInternal(ApiVersionBean avb, UpdateApiVersionBean update) throws ApiVersionNotFoundException {
if (avb.getStatus() == ApiStatus.Retired) {
throw ExceptionFactory.invalidApiStatusException();
}
avb.setModifiedBy(securityContext.getCurrentUser());
avb.setModifiedOn(new Date());
+ Set<ApiPlanBean> updatedPlans = apiVersionMapper.fromDto(update.getPlans());
EntityUpdatedData data = new EntityUpdatedData();
- if (AuditUtils.valueChanged(avb.getPlans(), bean.getPlans())) {
- data.addChange("plans", AuditUtils.asString_ApiPlanBeans(avb.getPlans()), AuditUtils.asString_ApiPlanBeans(bean.getPlans())); //$NON-NLS-1$
+ if (AuditUtils.valueChanged(avb.getPlans(), update.getPlans())) {
+ data.addChange("plans", AuditUtils.asString_ApiPlanBeans(avb.getPlans()), AuditUtils.asString_ApiPlanBeans(updatedPlans)); //$NON-NLS-1$
if (avb.getPlans() == null) {
avb.setPlans(new HashSet<>());
}
- avb.getPlans().clear();
- if (bean.getPlans() != null) {
- avb.getPlans().addAll(bean.getPlans());
+
+ if (update.getPlans() != null) {
+ Set<ApiPlanBeanDto> merged = new HashSet<>();
+ Set<ApiPlanBeanDto> existingPlans = apiVersionMapper.toDto(avb.getPlans());
+ // existingPlans.retainAll(bean.getPlans());
+ for (ApiPlanBeanDto updatedPlan : update.getPlans()) {
+ existingPlans.stream()
+ .filter(ep -> ep.equals(updatedPlan))
+ .findAny()
+ .ifPresentOrElse(
+ ep -> merged.add(apiVersionMapper.merge(updatedPlan, ep)),
+ () -> merged.add(updatedPlan)
+ );
}
+ avb.setPlans(apiVersionMapper.fromDto(merged));
}
- if (AuditUtils.valueChanged(avb.getGateways(), bean.getGateways())) {
- data.addChange("gateways", AuditUtils.asString_ApiGatewayBeans(avb.getGateways()), AuditUtils.asString_ApiGatewayBeans(bean.getGateways())); //$NON-NLS-1$
+ }
+ if (AuditUtils.valueChanged(avb.getGateways(), update.getGateways())) {
+ data.addChange("gateways", AuditUtils.asString_ApiGatewayBeans(avb.getGateways()), AuditUtils.asString_ApiGatewayBeans(update.getGateways())); //$NON-NLS-1$
if (avb.getGateways() == null) {
avb.setGateways(new HashSet<>());
}
avb.getGateways().clear();
- avb.getGateways().addAll(bean.getGateways());
+ avb.getGateways().addAll(update.getGateways());
}
- if (AuditUtils.valueChanged(avb.getEndpoint(), bean.getEndpoint())) {
+ if (AuditUtils.valueChanged(avb.getEndpoint(), update.getEndpoint())) {
// validate the endpoint is a URL
- validateEndpoint(bean.getEndpoint());
- data.addChange("endpoint", avb.getEndpoint(), bean.getEndpoint()); //$NON-NLS-1$
- avb.setEndpoint(bean.getEndpoint());
+ validateEndpoint(update.getEndpoint());
+ data.addChange("endpoint", avb.getEndpoint(), update.getEndpoint()); //$NON-NLS-1$
+ avb.setEndpoint(update.getEndpoint());
}
- if (AuditUtils.valueChanged(avb.getEndpointType(), bean.getEndpointType())) {
- data.addChange("endpointType", avb.getEndpointType(), bean.getEndpointType()); //$NON-NLS-1$
- avb.setEndpointType(bean.getEndpointType());
+ if (AuditUtils.valueChanged(avb.getEndpointType(), update.getEndpointType())) {
+ data.addChange("endpointType", avb.getEndpointType(), update.getEndpointType()); //$NON-NLS-1$
+ avb.setEndpointType(update.getEndpointType());
}
- if (AuditUtils.valueChanged(avb.getEndpointContentType(), bean.getEndpointContentType())) {
- data.addChange("endpointContentType", avb.getEndpointContentType(), bean.getEndpointContentType()); //$NON-NLS-1$
- avb.setEndpointContentType(bean.getEndpointContentType());
+ if (AuditUtils.valueChanged(avb.getEndpointContentType(), update.getEndpointContentType())) {
+ data.addChange("endpointContentType", avb.getEndpointContentType(), update.getEndpointContentType()); //$NON-NLS-1$
+ avb.setEndpointContentType(update.getEndpointContentType());
}
- if (AuditUtils.valueChanged(avb.getEndpointProperties(), bean.getEndpointProperties())) {
+ if (AuditUtils.valueChanged(avb.getEndpointProperties(), update.getEndpointProperties())) {
if (avb.getEndpointProperties() == null) {
avb.setEndpointProperties(new HashMap<>());
} else {
avb.getEndpointProperties().clear();
}
- if (bean.getEndpointProperties() != null) {
- avb.getEndpointProperties().putAll(bean.getEndpointProperties());
+ if (update.getEndpointProperties() != null) {
+ avb.getEndpointProperties().putAll(update.getEndpointProperties());
}
}
- if (AuditUtils.valueChanged(avb.isPublicAPI(), bean.getPublicAPI())) {
- data.addChange("publicAPI", String.valueOf(avb.isPublicAPI()), String.valueOf(bean.getPublicAPI())); //$NON-NLS-1$
- avb.setPublicAPI(bean.getPublicAPI());
+ if (AuditUtils.valueChanged(avb.isPublicAPI(), update.getPublicAPI())) {
+ data.addChange("publicAPI", String.valueOf(avb.isPublicAPI()), String.valueOf(update.getPublicAPI())); //$NON-NLS-1$
+ avb.setPublicAPI(update.getPublicAPI());
}
- if (AuditUtils.valueChanged(avb.isParsePayload(), bean.getParsePayload())) {
- data.addChange("parsePayload", String.valueOf(avb.isParsePayload()), String.valueOf(bean.getParsePayload())); //$NON-NLS-1$
- avb.setParsePayload(bean.getParsePayload());
+ if (AuditUtils.valueChanged(avb.isParsePayload(), update.getParsePayload())) {
+ data.addChange("parsePayload", String.valueOf(avb.isParsePayload()), String.valueOf(update.getParsePayload())); //$NON-NLS-1$
+ avb.setParsePayload(update.getParsePayload());
}
- if (AuditUtils.valueChanged(avb.getDisableKeysStrip(), bean.getDisableKeysStrip())) {
- data.addChange("disableKeysStrip", String.valueOf(avb.getDisableKeysStrip()), String.valueOf(bean.getDisableKeysStrip())); //$NON-NLS-1$
- avb.setDisableKeysStrip(bean.getDisableKeysStrip());
+ if (AuditUtils.valueChanged(avb.getDisableKeysStrip(), update.getDisableKeysStrip())) {
+ data.addChange("disableKeysStrip", String.valueOf(avb.getDisableKeysStrip()), String.valueOf(update.getDisableKeysStrip())); //$NON-NLS-1$
+ avb.setDisableKeysStrip(update.getDisableKeysStrip());
}
- if (AuditUtils.valueChanged(avb.getExtendedDescription(), bean.getExtendedDescription())) {
- data.addChange("extendedDescription", String.valueOf(avb.getExtendedDescription()), String.valueOf(bean.getExtendedDescription())); //$NON-NLS-1$
- avb.setExtendedDescription(bean.getExtendedDescription());
+ if (AuditUtils.valueChanged(avb.getExtendedDescription(), update.getExtendedDescription())) {
+ data.addChange("extendedDescription", String.valueOf(avb.getExtendedDescription()), String.valueOf(update.getExtendedDescription())); //$NON-NLS-1$
+ avb.setExtendedDescription(update.getExtendedDescription());
}
- if (AuditUtils.valueChanged(avb.isExposeInPortal(), bean.isExposeInPortal())) {
- data.addChange("exposeInPortal", String.valueOf(avb.isExposeInPortal()), String.valueOf(bean.isExposeInPortal())); //$NON-NLS-1$
- avb.setExposeInPortal(bean.isExposeInPortal());
+ if (AuditUtils.valueChanged(avb.isExposeInPortal(), update.isExposeInPortal())) {
+ data.addChange("exposeInPortal", String.valueOf(avb.isExposeInPortal()), String.valueOf(update.isExposeInPortal())); //$NON-NLS-1$
+ avb.setExposeInPortal(update.isExposeInPortal());
}
return tryAction(() -> {
@@ -1124,6 +1140,11 @@ public class ApiService implements DataAccessUtilMixin {
this.version = pvb.getVersion();
}
+ public PlanIdVersion(ApiPlanBeanDto pvb) {
+ this.id = pvb.getPlanId();
+ this.version = pvb.getVersion();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {

MODIFY
manager/test/api/src/test/java/io/apiman/manager/api/notifications/email/SimpleMailNotificationServiceTest.java
manager/test/api/src/test/java/io/apiman/manager/api/notifications/email/SimpleMailNotificationServiceTest.java
@@ -47,6 +47,7 @@ public class SimpleMailNotificationServiceTest {
};
Map<String, String> TEST_CONFIG = Map.of(
+ "enable", "true",
"smtp.mock", "false",
"smtp.ssl", "false",
"smtp.startTLSMode", "DISABLED",

fix(manager-api): fix updateApiVersion logic to support patch plan

feat(manager-api): allow email notifications to be explicitly toggled in `apiman.properties`