diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/EmailMessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/EmailMessageDecorator.java index e39e110e055..2a55344a0be 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/EmailMessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/EmailMessageDecorator.java @@ -14,6 +14,7 @@ package org.openmetadata.service.formatter.decorators; import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; +import static org.openmetadata.service.util.EntityUtil.encodeEntityFqn; import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings; import java.util.ArrayList; @@ -61,11 +62,12 @@ public class EmailMessageDecorator implements MessageDecorator { @Override public String getEntityUrl(String prefix, String fqn, String additionalParams) { + String encodedFqn = encodeEntityFqn(fqn); return String.format( - "%s", + "%s", getSmtpSettings().getOpenMetadataUrl(), prefix, - fqn.trim(), + encodedFqn, nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams), fqn.trim()); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/FeedMessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/FeedMessageDecorator.java index cedd3f6fae0..c92e61c3b86 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/FeedMessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/FeedMessageDecorator.java @@ -14,6 +14,7 @@ package org.openmetadata.service.formatter.decorators; import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; +import static org.openmetadata.service.util.EntityUtil.encodeEntityFqn; import org.openmetadata.schema.type.ChangeEvent; import org.openmetadata.service.formatter.util.FeedMessage; @@ -57,11 +58,12 @@ public class FeedMessageDecorator implements MessageDecorator { @Override public String getEntityUrl(String prefix, String fqn, String additionalParams) { + String encodedFqn = encodeEntityFqn(fqn); return String.format( "[%s](/%s/%s%s)", - fqn, - prefix, fqn.trim(), + prefix, + encodedFqn, nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams)); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/GChatMessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/GChatMessageDecorator.java index 6f55de114d2..d6b7091aff6 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/GChatMessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/GChatMessageDecorator.java @@ -14,6 +14,7 @@ package org.openmetadata.service.formatter.decorators; import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; +import static org.openmetadata.service.util.EntityUtil.encodeEntityFqn; import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings; import java.util.ArrayList; @@ -76,11 +77,12 @@ public class GChatMessageDecorator implements MessageDecorator { @Override public String getEntityUrl(String prefix, String fqn, String additionalParams) { + String encodedFqn = encodeEntityFqn(fqn); return String.format( "<%s/%s/%s%s|%s>", getSmtpSettings().getOpenMetadataUrl(), prefix, - fqn.trim().replace(" ", "%20"), + encodedFqn, nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams), fqn.trim()); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MSTeamsMessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MSTeamsMessageDecorator.java index f16b031f3d4..8dbc38445c1 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MSTeamsMessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MSTeamsMessageDecorator.java @@ -14,6 +14,7 @@ package org.openmetadata.service.formatter.decorators; import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; +import static org.openmetadata.service.util.EntityUtil.encodeEntityFqn; import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings; import java.util.ArrayList; @@ -81,11 +82,13 @@ public class MSTeamsMessageDecorator implements MessageDecorator { @Override public String getEntityUrl(String prefix, String fqn, String additionalParams) { + String encodedFqn = encodeEntityFqn(fqn); return String.format( - "[%s](/%s/%s%s)", + "[%s](%s/%s/%s%s)", fqn.trim(), getSmtpSettings().getOpenMetadataUrl(), prefix, + encodedFqn, nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams)); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MessageDecorator.java index f56a3dc4712..80b1479b251 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/MessageDecorator.java @@ -33,6 +33,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; +import lombok.SneakyThrows; import org.apache.commons.lang3.StringUtils; import org.bitbucket.cowwoc.diffmatchpatch.DiffMatchPatch; import org.openmetadata.common.utils.CommonUtil; @@ -48,8 +49,11 @@ import org.openmetadata.service.jdbi3.TestCaseRepository; import org.openmetadata.service.resources.feeds.MessageParser; import org.openmetadata.service.util.EntityUtil; import org.openmetadata.service.util.FeedUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public interface MessageDecorator { + Logger LOG = LoggerFactory.getLogger(MessageDecorator.class); String CONNECTION_TEST_DESCRIPTION = "This is a test message, receiving this message confirms that you have successfully configured OpenMetadata to receive alerts."; @@ -85,34 +89,40 @@ public interface MessageDecorator { T buildTestMessage(); + @SneakyThrows default String buildEntityUrl(String entityType, EntityInterface entityInterface) { String fqn = resolveFullyQualifiedName(entityType, entityInterface); - + String entityUrl = ""; switch (entityType) { case Entity.TEST_CASE: if (entityInterface instanceof TestCase testCase) { - return getEntityUrl( - "incident-manager", testCase.getFullyQualifiedName(), "test-case-results"); + entityUrl = + getEntityUrl( + "incident-manager", testCase.getFullyQualifiedName(), "test-case-results"); } break; case Entity.GLOSSARY_TERM: - return getEntityUrl(Entity.GLOSSARY, fqn, ""); + entityUrl = getEntityUrl(Entity.GLOSSARY, fqn, ""); + break; case Entity.TAG: - return getEntityUrl("tags", fqn.split("\\.")[0], ""); + entityUrl = getEntityUrl("tags", fqn.split("\\.")[0], ""); + break; case Entity.INGESTION_PIPELINE: - return getIngestionPipelineUrl(this, entityType, entityInterface); + entityUrl = getIngestionPipelineUrl(this, entityType, entityInterface); + break; default: - return getEntityUrl(entityType, fqn, ""); + entityUrl = getEntityUrl(entityType, fqn, ""); } - // Fallback in case of no match - return getEntityUrl(entityType, fqn, ""); + LOG.debug("buildEntityUrl for Alert: {}", entityUrl); + return entityUrl; } + @SneakyThrows default String buildThreadUrl( ThreadType threadType, String entityType, EntityInterface entityInterface) { @@ -120,30 +130,34 @@ public interface MessageDecorator { threadType.equals(ThreadType.Task) ? "activity_feed/tasks" : "activity_feed/all"; String fqn = resolveFullyQualifiedName(entityType, entityInterface); - + String entityUrl = ""; switch (entityType) { case Entity.TEST_CASE: if (entityInterface instanceof TestCase) { TestCase testCase = (TestCase) entityInterface; - return getEntityUrl("incident-manager", testCase.getFullyQualifiedName(), "issues"); + entityUrl = getEntityUrl("incident-manager", testCase.getFullyQualifiedName(), "issues"); } break; case Entity.GLOSSARY_TERM: - return getEntityUrl(Entity.GLOSSARY, fqn, activeTab); + entityUrl = getEntityUrl(Entity.GLOSSARY, fqn, activeTab); + break; case Entity.TAG: - return getEntityUrl("tags", fqn.split("\\.")[0], ""); + entityUrl = getEntityUrl("tags", fqn.split("\\.")[0], ""); + break; case Entity.INGESTION_PIPELINE: - return getIngestionPipelineUrl(this, entityType, entityInterface); + entityUrl = getIngestionPipelineUrl(this, entityType, entityInterface); + break; default: - return getEntityUrl(entityType, fqn, activeTab); + entityUrl = getEntityUrl(entityType, fqn, activeTab); } // Fallback in case of no match - return getEntityUrl(entityType, fqn, activeTab); + LOG.debug("buildThreadUrl for Alert: {}", entityUrl); + return entityUrl; } // Helper function to resolve FQN if null or empty diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/SlackMessageDecorator.java b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/SlackMessageDecorator.java index 8b4b3f854d9..3d54858e17a 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/SlackMessageDecorator.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/formatter/decorators/SlackMessageDecorator.java @@ -14,6 +14,7 @@ package org.openmetadata.service.formatter.decorators; import static org.openmetadata.common.utils.CommonUtil.nullOrEmpty; +import static org.openmetadata.service.util.EntityUtil.encodeEntityFqn; import static org.openmetadata.service.util.email.EmailUtil.getSmtpSettings; import com.slack.api.model.block.Blocks; @@ -77,14 +78,17 @@ public class SlackMessageDecorator implements MessageDecorator { return "~"; } + @Override public String getEntityUrl(String prefix, String fqn, String additionalParams) { + String encodedFqn = encodeEntityFqn(fqn); return String.format( "<%s/%s/%s%s|%s>", getSmtpSettings().getOpenMetadataUrl(), prefix, - fqn.trim().replaceAll(" ", "%20"), + encodedFqn, // Use encoded FQN in the URL nullOrEmpty(additionalParams) ? "" : String.format("/%s", additionalParams), - fqn.trim()); + fqn.trim() // Display text remains unencoded + ); } @Override diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/util/EntityUtil.java b/openmetadata-service/src/main/java/org/openmetadata/service/util/EntityUtil.java index e08ff1e910f..da72f15bf0e 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/util/EntityUtil.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/util/EntityUtil.java @@ -21,6 +21,8 @@ import static org.openmetadata.service.jdbi3.RoleRepository.DOMAIN_ONLY_ACCESS_R import static org.openmetadata.service.security.DefaultAuthorizer.getSubjectContext; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.LocalDate; import java.util.ArrayList; @@ -702,4 +704,8 @@ public final class EntityUtil { } } } + + public static String encodeEntityFqn(String fqn) { + return URLEncoder.encode(fqn.trim(), StandardCharsets.UTF_8).replace("+", "%20"); + } }