ACS-9734 Context aware documentation links (#3394)

This commit is contained in:
SatyamSah5
2025-06-25 13:40:51 +05:30
committed by GitHub
parent 6e815ebd34
commit 917dd35c27
44 changed files with 387 additions and 47 deletions

View File

@@ -27,7 +27,7 @@ to integrate with a number of external Authentication providers including
* https://github.com/Alfresco/alfresco-data-model/tree/master/src/main/java/org/alfresco/repo/security/authentication
* License: LGPL
* Issue Tracker Link: https://issues.alfresco.com/jira/issues/?jql=project%3DREPO
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Administer/Manage-Security/Authentication-and-sync
* Documentation Link: https://support.hyland.com/access?dita:id=byj1720776091160&vrm_version=25.2&component=Alfresco%20Content%20Services%20Community%20Edition
* Contribution Model: Alfresco Open Source
***

View File

@@ -16,7 +16,7 @@
* Source Code Link:m https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/
* License: LGPL
* Issue Tracker Link: https://issues.alfresco.com/jira/secure/RapidBoard.jspa?projectKey=REPO&useStoredSettings=true&rapidView=379
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Configure/Repository/About-Versioning
* Documentation Link: https://support.hyland.com/access?dita:id=ybx1720084724583&vrm_version=25.2
* Contribution Model: Alfresco publishes the source code and will review proposed patch requests
***

View File

@@ -0,0 +1,195 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2025 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.template;
import java.util.List;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateScalarModel;
import org.apache.commons.lang3.StringUtils;
public class DocumentationURLMethod extends BaseTemplateProcessorExtension implements TemplateMethodModelEx
{
private static final String COMPONENT_SEARCHENTERPRISE = "elasticsearch";
private static final String COMPONENT_SEARCH = "solr";
private String documentationBaseUrl;
private String acsVersion;
private String alfrescoSearchVersion;
private String alfrescoSearchEnterpriseVersion;
private String defaultDocumentationUrl;
public void setDefaultDocumentationUrl(String defaultDocumentationUrl)
{
this.defaultDocumentationUrl = defaultDocumentationUrl;
}
public void setAcsVersion(String acsVersion)
{
this.acsVersion = acsVersion;
}
public void setAlfrescoSearchVersion(String alfrescoSearchVersion)
{
this.alfrescoSearchVersion = alfrescoSearchVersion;
}
public void setAlfrescoSearchEnterpriseVersion(String alfrescoSearchEnterpriseVersion)
{
this.alfrescoSearchEnterpriseVersion = alfrescoSearchEnterpriseVersion;
}
public void setDocumentationBaseUrl(String documentationBaseUrl)
{
this.documentationBaseUrl = documentationBaseUrl;
}
/**
* Returns documentation URL. You can specify property key which should hold value of topic uid and url component(if required). * a) If no arguments are provided, the default documentation URL is returned.
*
* <pre>
* ${documentationUrl() -> https://support.hyland.com/p/alfresco
* </pre>
*
* b) First argument is interpreted as Topic UID of the URL. The value is retrieved and treated as Topic UID appended after baseURL and before version.
*
* <pre>
* ${documentationURL("eet567890373737")} -> https://support.hyland.com/access?dita:id=eet567890373737&vrm_version=25.1
* </pre>
*
* c) Second argument(if required) is interpreted as an additional URL component, which will be appended to the URL to denote a specific component of Alfresco.
*
* <pre>
* ${documentationUrl("eeu1720075126296", "&component=Alfresco%20Content%20Services%20Community%20Edition"} -> https://support.hyland.com/access?dita:id=eeu1720075126296&vrm_version=25.1&component=Alfresco%20Content%20Services%20Community%20Edition
* </pre>
*
* d) Third argument (if required) is interpreted as the Alfresco component (e.g., "solr", "elasticsearch", or empty) to determine which version to use in the URL.
*
* <pre>
* ${documentationUrl("eeu1720075126296", "", "solr")} -> https://support.hyland.com/access?dita:id=eeu1720075126296&vrm_version=2.0
* </pre>
*
* @param args
* arguments passed to Freemarker template method invocation first argument is interpreted as Topic UID of the URL, second argument is interpreted as an additional URL component, third argument is interpreted as the Alfresco component ("solr", "elasticsearch", or empty) to select the version.
* @return the documentation URL
* @throws TemplateModelException
* if an error occurs
*/
@Override
public Object exec(List args) throws TemplateModelException
{
String topicUid = getTopicUid(args);
String urlComponent = getUrlComponent(args);
String alfrescoComponent = getAlfrescoComponent(args);
return getDocumentationUrl(topicUid, urlComponent, alfrescoComponent);
}
/**
* Returns default landing documentation URL.
*
* @return default documentation URL
*/
public String getDocumentationUrl()
{
return defaultDocumentationUrl;
}
/**
* Constructs the documentation URL using the base URL, topic UID, version, and additional component.
*
* @param topicUid
* path segment
* @param urlComponent
* additional URL component (may be empty)
* @param alfrescoComponent
* additional Alfresco component (may be empty), to determine the version
* @return full documentation URL
*/
public String getDocumentationUrl(String topicUid, String urlComponent, String alfrescoComponent)
{
if (StringUtils.isEmpty(topicUid) && StringUtils.isEmpty(urlComponent))
{
return getDocumentationUrl();
}
String version = selectVersion(alfrescoComponent);
return documentationBaseUrl + topicUid + version + urlComponent;
}
private String selectVersion(String alfrescoComponent)
{
if (COMPONENT_SEARCHENTERPRISE.equalsIgnoreCase(alfrescoComponent))
{
return alfrescoSearchEnterpriseVersion;
}
if (COMPONENT_SEARCH.equalsIgnoreCase(alfrescoComponent))
{
return alfrescoSearchVersion;
}
return acsVersion;
}
/**
* Extracts a string argument from the list at the given index.
*
* @param args
* argument list
* @param index
* index to extract
* @return string value or empty string if not present
* @throws TemplateModelException
* if argument is not a scalar
*/
private String getStringArg(List<?> args, int index) throws TemplateModelException
{
if (args.size() > index)
{
Object arg = args.get(index);
if (arg instanceof TemplateScalarModel)
{
String value = ((TemplateScalarModel) arg).getAsString();
return value != null ? value : "";
}
}
return "";
}
private String getTopicUid(List<?> args) throws TemplateModelException
{
return getStringArg(args, 0);
}
private String getUrlComponent(List<?> args) throws TemplateModelException
{
return getStringArg(args, 1);
}
private String getAlfrescoComponent(List<?> args) throws TemplateModelException
{
return getStringArg(args, 2);
}
}

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Vlastnost ''{0}'' nebyla nastavena: {1} ({2})
system.err.duplicate_name=Duplicitn\u00ed n\u00e1zvy pod\u0159\u00edzen\u00fdch objekt\u016f nejsou povoleny ({0})
system.err.lucene_not_supported=Subsyst\u00e9m hled\u00e1n\u00ed Lucene nen\u00ed podporov\u00e1n. Viz https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Egenskaben ''{0}'' er ikke blevet indstillet: {1} ({2})
system.err.duplicate_name=Duplikeret navn p\u00e5 underordnet er ikke tilladt: {0}
system.err.lucene_not_supported=Lucene-s\u00f8geundersystemet underst\u00f8ttes ikke. Se https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Ominaisuutta {0} ei ole m\u00e4\u00e4ritetty: {1} ({2})
system.err.duplicate_name=P\u00e4\u00e4llekk\u00e4ist\u00e4 alatasonime\u00e4 ei sallita: {0}
system.err.lucene_not_supported=Lucene-hakualij\u00e4rjestelm\u00e4\u00e4 ei tueta. Saat lis\u00e4tietoja osoitteesta https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set : {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed : {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Nie ustawiono w\u0142a\u015bciwo\u015bci ''{0}'': {1} ({2})
system.err.duplicate_name=Zduplikowane nazwy element\u00f3w podrz\u0119dnych s\u0105 niedozwolone: {0}
system.err.lucene_not_supported=Podsystem wyszukiwania Lucene nie jest obs\u0142ugiwany. Zobacz https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Egenskap ''{0}'' har inte st\u00e4llts in: {1} ({2})
system.err.duplicate_name=Dubbelt underordnat namn inte till\u00e5tet: {0}
system.err.lucene_not_supported=Lucene-s\u00f6kundersystemet st\u00f6ds inte. Se https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -5,7 +5,6 @@
system.err.property_not_set=Property ''{0}'' has not been set: {1} ({2})
system.err.duplicate_name=Duplicate child name not allowed: {0}
system.err.lucene_not_supported=The lucene search subsystem is not supported. Please see https://support.hyland.com/p/alfresco
# Bootstrap configuration check messages

View File

@@ -1402,3 +1402,10 @@ default.async.folder.items=1000
default.nodeSize.corePoolSize=5
default.nodeSize.maximumPoolSize=10
default.nodeSize.workQueueSize=100
# Documentation URLs properties
alfresco.documentation.baseurl=https://support.hyland.com/access?dita:id=
alfresco.documentation.acsVersion=&vrm_version=25.2
alfresco.documentation.searchVersion=&vrm_version=2.0
alfresco.documentation.searchEnterpriseVersion=&vrm_version=5.1
alfresco.documentation.defaultDocumentationUrl=https://support.hyland.com/p/alfresco

View File

@@ -161,4 +161,25 @@
<ref bean="ServiceRegistry"/>
</property>
</bean>
<bean id="documentationUrlExtension" parent="mailBaseTemplateImplementation" class="org.alfresco.repo.template.DocumentationURLMethod">
<property name="extensionName">
<value>documentationUrl</value>
</property>
<property name="documentationBaseUrl">
<value>${alfresco.documentation.baseurl}</value>
</property>
<property name="acsVersion">
<value>${alfresco.documentation.acsVersion}</value>
</property>
<property name="alfrescoSearchVersion">
<value>${alfresco.documentation.searchVersion}</value>
</property>
<property name="alfrescoSearchEnterpriseVersion">
<value>${alfresco.documentation.searchEnterpriseVersion}</value>
</property>
<property name="defaultDocumentationUrl">
<value>${alfresco.documentation.defaultDocumentationUrl}</value>
</property>
</bean>
</beans>

View File

@@ -171,4 +171,25 @@
<value>urldecode</value>
</property>
</bean>
<bean id="documentationUrlExtension" parent="baseTemplateImplementation" class="org.alfresco.repo.template.DocumentationURLMethod">
<property name="extensionName">
<value>documentationUrl</value>
</property>
<property name="documentationBaseUrl">
<value>${alfresco.documentation.baseurl}</value>
</property>
<property name="acsVersion">
<value>${alfresco.documentation.acsVersion}</value>
</property>
<property name="alfrescoSearchVersion">
<value>${alfresco.documentation.searchVersion}</value>
</property>
<property name="alfrescoSearchEnterpriseVersion">
<value>${alfresco.documentation.searchEnterpriseVersion}</value>
</property>
<property name="defaultDocumentationUrl">
<value>${alfresco.documentation.defaultDocumentationUrl}</value>
</property>
</bean>
</beans>

View File

@@ -271,7 +271,8 @@ import org.alfresco.util.testing.category.NonBuildTests;
org.alfresco.util.schemacomp.SchemaDifferenceHelperUnitTest.class,
org.alfresco.repo.tagging.TaggingServiceImplUnitTest.class,
org.alfresco.repo.serviceaccount.ServiceAccountRegistryImplTest.class
org.alfresco.repo.serviceaccount.ServiceAccountRegistryImplTest.class,
org.alfresco.repo.template.DocumentationURLMethodTest.class
})
public class AllUnitTestsSuite
{}

View File

@@ -0,0 +1,111 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2025 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.template;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collections;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateModelException;
import org.junit.Before;
import org.junit.Test;
public class DocumentationURLMethodTest
{
public static final String BASE_URL = "baseUrl";
public static final String ACS_VERSION = "_acs_";
public static final String SEARCH_VERSION = "_solr_";
public static final String SEARCH_ENTERPRISE_VERSION = "_es_";
public static final String DEFAULT_DOCUMENTATION_URL = "defaultDocumentationUrl";
DocumentationURLMethod documentationURLMethod;
@Before
public void setUp() throws Exception
{
documentationURLMethod = new DocumentationURLMethod();
documentationURLMethod.setAcsVersion(ACS_VERSION);
documentationURLMethod.setAlfrescoSearchVersion(SEARCH_VERSION);
documentationURLMethod.setAlfrescoSearchEnterpriseVersion(SEARCH_ENTERPRISE_VERSION);
documentationURLMethod.setDocumentationBaseUrl(BASE_URL);
documentationURLMethod.setDefaultDocumentationUrl(DEFAULT_DOCUMENTATION_URL);
}
@Test
public void testGetDocumentationUrl_NoArgs() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Collections.emptyList());
assertEquals("defaultDocumentationUrl", result);
}
@Test
public void testGetDocumentationUrl_EmptyTopicUidAndUrlComponent() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Arrays.asList(
new SimpleScalar(""),
new SimpleScalar("")));
assertEquals("defaultDocumentationUrl", result);
}
@Test
public void testGetDocumentationUrl_WithTopicUid_AcsVersion() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Collections.singletonList(new SimpleScalar("/topic")));
assertEquals(BASE_URL + "/topic" + ACS_VERSION, result);
}
@Test
public void testGetDocumentationUrl_WithTopicUidAndUrlComponent_AcsVersion() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Arrays.asList(
new SimpleScalar("/topic"),
new SimpleScalar("urlComponent")));
assertEquals(BASE_URL + "/topic" + ACS_VERSION + "urlComponent", result);
}
@Test
public void testGetDocumentationUrl_WithSolrVersion() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Arrays.asList(
new SimpleScalar("/topic"),
new SimpleScalar("urlComponent"),
new SimpleScalar("solr")));
assertEquals(BASE_URL + "/topic" + SEARCH_VERSION + "urlComponent", result);
}
@Test
public void testGetDocumentationUrl_WithElasticSearchVersion() throws TemplateModelException
{
Object result = documentationURLMethod.exec(Arrays.asList(
new SimpleScalar("/topic"),
new SimpleScalar("urlComponent"),
new SimpleScalar("elasticsearch")));
assertEquals(BASE_URL + "/topic" + SEARCH_ENTERPRISE_VERSION + "urlComponent", result);
}
}