Skip to content

Commit

Permalink
Merge branch 'issue-28896-Create-Factory-Method-to-filter-all-levels-…
Browse files Browse the repository at this point in the history
…Category' of https://github.com/dotCMS/core into issue-28896-Create-Factory-Method-to-filter-all-levels-Category
  • Loading branch information
freddyDOTCMS committed Jun 26, 2024
2 parents ecd3c87 + 733ac47 commit 90a3627
Show file tree
Hide file tree
Showing 177 changed files with 594 additions and 472 deletions.
88 changes: 88 additions & 0 deletions core-web/libs/sdk/client/src/lib/client/sdk-js-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,94 @@ describe('DotCmsClient', () => {
dotcmsClient.init(config);
}).toThrow("Invalid configuration - 'authToken' is required");
});

it('should use a clean dotcmsUrl when passing an slash at the end', async () => {
const config = {
dotcmsUrl: 'https://example.com/',
siteId: '123456',
authToken: 'ABC'
};

const mockResponse = { content: 'Page data' };
mockFetchResponse(mockResponse);

const client = dotcmsClient.init(config);

await client.page.get({ path: '/home' });

expect(fetch).toHaveBeenCalledWith(
'https://example.com/api/v1/page/json/home?host_id=123456',
{
headers: { Authorization: 'Bearer ABC' }
}
);
});

it('should use a clean dotcmsUrl when passing a route at the end', async () => {
const config = {
dotcmsUrl: 'https://example.com/some/cool/route',
siteId: '123456',
authToken: 'ABC'
};

const mockResponse = { content: 'Page data' };
mockFetchResponse(mockResponse);

const client = dotcmsClient.init(config);

await client.page.get({ path: '/home' });

expect(fetch).toHaveBeenCalledWith(
'https://example.com/api/v1/page/json/home?host_id=123456',
{
headers: { Authorization: 'Bearer ABC' }
}
);
});

it('should use a clean dotcmsUrl when passing a port and an slash at the end', async () => {
const config = {
dotcmsUrl: 'https://example.com:3434/cool/route',
siteId: '123456',
authToken: 'ABC'
};

const mockResponse = { content: 'Page data' };
mockFetchResponse(mockResponse);

const client = dotcmsClient.init(config);

await client.page.get({ path: '/home' });

expect(fetch).toHaveBeenCalledWith(
'https://example.com:3434/api/v1/page/json/home?host_id=123456',
{
headers: { Authorization: 'Bearer ABC' }
}
);
});

it('should use a clean dotcmsUrl when passing a port and an slash at the end', async () => {
const config = {
dotcmsUrl: 'https://example.com:3434/',
siteId: '123456',
authToken: 'ABC'
};

const mockResponse = { content: 'Page data' };
mockFetchResponse(mockResponse);

const client = dotcmsClient.init(config);

await client.page.get({ path: '/home' });

expect(fetch).toHaveBeenCalledWith(
'https://example.com:3434/api/v1/page/json/home?host_id=123456',
{
headers: { Authorization: 'Bearer ABC' }
}
);
});
});

describe('page.get', () => {
Expand Down
17 changes: 10 additions & 7 deletions core-web/libs/sdk/client/src/lib/client/sdk-js-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,11 @@ type NavApiOptions = {
languageId?: number;
};

function isValidUrl(url: string): boolean {
function getHostURL(url: string): URL | undefined {
try {
new URL(url);

return true;
return new URL(url);
} catch (error) {
return false;
return undefined;
}
}

Expand Down Expand Up @@ -161,15 +159,20 @@ export class DotCmsClient {
throw new Error("Invalid configuration - 'dotcmsUrl' is required");
}

if (!isValidUrl(config.dotcmsUrl)) {
const dotcmsHost = getHostURL(config.dotcmsUrl);

if (!dotcmsHost) {
throw new Error("Invalid configuration - 'dotcmsUrl' must be a valid URL");
}

if (!config.authToken) {
throw new Error("Invalid configuration - 'authToken' is required");
}

this.config = config;
this.config = {
...config,
dotcmsUrl: dotcmsHost.origin
};

this.requestOptions = {
...this.config.requestOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet)
.forEach(field -> {

final Object storyBlockValue = contentlet.get(field.variable());
if (null != storyBlockValue && JsonUtil.isValidJSON(storyBlockValue.toString())) {
if (null != storyBlockValue) {
final StoryBlockReferenceResult result =
this.refreshStoryBlockValueReferences(storyBlockValue, contentlet.getIdentifier());
if (result.isRefreshed()) {
Expand All @@ -85,40 +85,50 @@ public StoryBlockReferenceResult refreshReferences(final Contentlet contentlet)
@SuppressWarnings("unchecked")
public StoryBlockReferenceResult refreshStoryBlockValueReferences(final Object storyBlockValue, final String parentContentletIdentifier) {
boolean refreshed = false;
if (ThreadUtils.isMethodCallCountEqualThan(this.getClass().getName(),
"refreshStoryBlockValueReferences", MAX_RECURSION_LEVEL)) {
Logger.debug(this, () -> "This method has been called more than " + MAX_RECURSION_LEVEL +
" times in the same thread. This could be a sign of circular reference in the Story Block field. Data will NOT be refreshed.");
return new StoryBlockReferenceResult(false, storyBlockValue);
}
try {
final LinkedHashMap<String, Object> blockEditorMap = this.toMap(storyBlockValue);
final Object contentsMap = blockEditorMap.get(CONTENT_KEY);
if(!UtilMethods.isSet(contentsMap) || !(contentsMap instanceof List)) {
return new StoryBlockReferenceResult(true, storyBlockValue);
if (null != storyBlockValue && JsonUtil.isValidJSON(storyBlockValue.toString())) {
if (ThreadUtils.isMethodCallCountEqualThan(this.getClass().getName(),
"refreshStoryBlockValueReferences", MAX_RECURSION_LEVEL)) {
Logger.debug(this, () -> "This method has been called more than " + MAX_RECURSION_LEVEL +
" times in the same thread. This could be a sign of circular reference in the Story Block field. Data will NOT be refreshed.");
return new StoryBlockReferenceResult(false, storyBlockValue);
}
for (final Map<String, Object> contentMap : (List<Map<String, Object>>) contentsMap) {
if (UtilMethods.isSet(contentMap)) {
final String type = contentMap.get(TYPE_KEY).toString();
if (allowedTypes.contains(type)) { // if somebody adds a story block to itself, we don't want to refresh it

refreshed |= this.refreshStoryBlockMap(contentMap, parentContentletIdentifier);
}
try {
final LinkedHashMap<String, Object> blockEditorMap = this.toMap(storyBlockValue);
final Object contentsMap = blockEditorMap.get(CONTENT_KEY);
if (!UtilMethods.isSet(contentsMap) || !(contentsMap instanceof List)) {
return new StoryBlockReferenceResult(true, storyBlockValue);
}
refreshed = isRefreshed(parentContentletIdentifier, (List<Map<String, Object>>) contentsMap);
if (refreshed) {
return new StoryBlockReferenceResult(true, this.toJson(blockEditorMap));
}
} catch (final Exception e) {
final String errorMsg = String.format("An error occurred when refreshing Story Block Contentlet references in parent Content " +
"'%s': %s", parentContentletIdentifier, ExceptionUtil.getErrorMessage(e));
Logger.warnAndDebug(StoryBlockAPIImpl.class, errorMsg, e);
throw new DotRuntimeException(errorMsg, e);
}
if (refreshed) {
return new StoryBlockReferenceResult(true, this.toJson(blockEditorMap));
}
} catch (final Exception e) {
final String errorMsg = String.format("An error occurred when refreshing Story Block Contentlet references in parent Content " +
"'%s': %s", parentContentletIdentifier, ExceptionUtil.getErrorMessage(e));
Logger.warnAndDebug(StoryBlockAPIImpl.class, errorMsg, e);
throw new DotRuntimeException(errorMsg, e);
}
// Return the original value in case no data was refreshed
return new StoryBlockReferenceResult(false, storyBlockValue);
}

private boolean isRefreshed(final String parentContentletIdentifier,
final List<Map<String, Object>> contentsMap) {

boolean refreshed = false;
for (final Map<String, Object> contentMap : contentsMap) {
if (UtilMethods.isSet(contentMap)) {
final String type = contentMap.get(TYPE_KEY).toString();
if (allowedTypes.contains(type)) { // if somebody adds a story block to itself, we don't want to refresh it

refreshed |= this.refreshStoryBlockMap(contentMap, parentContentletIdentifier);
}
}
}
return refreshed;
}

/**
* Takes the current data map of the referenced Contentlet in the Story Block field and checks whether it matches
* its latest live version or not. If it doesn't, then it means it must be refreshed with the data map from the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Optional;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -407,6 +408,21 @@ public void test_get_refreshStoryBlockValueReferences_with_bad_content_value()


}


/**
* Method to test: {@link StoryBlockAPI#refreshStoryBlockValueReferences(Object, String)}
* Given Scenario: Test a story block value that is not a json
* ExpectedResult: Do not throw exception and must return zero dependencies
*/
@Test
public void test_refreshStoryBlockValueReferences_with_json_value() {

final Object newStoryBlockJson1 = "bu bu bu}";

StoryBlockReferenceResult result = APILocator.getStoryBlockAPI().refreshStoryBlockValueReferences(newStoryBlockJson1, "xxx");
assertNotNull(result);
assertFalse(result.isRefreshed());

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.io.InputStream;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import com.dotcms.model.ResponseEntityView;
import com.dotcms.model.authentication.APITokenRequest;
import com.dotcms.model.authentication.TokenEntity;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import java.io.InputStream;
import java.util.Optional;
import java.util.Properties;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
import com.dotcms.model.views.CommonViews.ContentTypeInternalView;
import com.fasterxml.jackson.annotation.JsonView;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import com.dotcms.model.folder.SearchByPathRequest;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
import com.dotcms.model.views.CommonViews.LanguageFileView;
import com.fasterxml.jackson.annotation.JsonView;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
Expand Down
Loading

0 comments on commit 90a3627

Please sign in to comment.