Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduces a limited length render filter and HTML tag close filter #1128

Merged
merged 16 commits into from
Nov 27, 2023

Conversation

asegal-hs
Copy link
Collaborator

Currently, Jinjava provides filters for truncating HTML. The purpose of these is to shorten or summarize rich text. They correctly handle HTML so that tags are not left hanging open. However, they do not accommodate text that contains raw HubL as well as HTML. The purpose of this PR is to allow summaries of objects that contain raw HubL text.

This also includes a filter that closes HTML tags that may have been left hanging open.

Example usage in pseudocode:

user.name = Alice
text = "<p> Hello, {% user.name %} </p>"
rendered = text | render(13) // <p> Hello, Ali
closed = renderer | closehtml //<p> Hello, Ali</p>

This serves as an alternate option to the truncatehtml filter that will do the same thing to raw rich text but also correctly render HubL included in it.

Copy link
Contributor

@jasmith-hs jasmith-hs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These seem like good features to include


@Override
public String getName() {
return "render";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return "render";
return "closehtml";

if (args.length > 0) {
/*
This means a render limit length has been provided.
Here we begin a left to right render where we add to an HTML string until the length reaches a certain limit.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, not necessarily an HTML string, but the functionality makes sense

Copy link
Contributor

@jasmith-hs jasmith-hs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a few points that we should address before merging

@@ -24,6 +25,10 @@ public String getName() {

@Override
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
if (args.length > 0) {
String firstArg = args[0];
return interpreter.render(Objects.toString(var), NumberUtils.toLong(firstArg, 0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cap the limit to config.getMaxOutputSize()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we should add some nicer error handling here if we can't coerce the String to a Long

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I thought, except default max output size is 0 (unlimited I assume?) so clamping it always goes lower than the provided value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed the default value to explicitly take on whatever is in the config. We could instead just switch to the other case or throw an error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only clamp if the max output size is > 0

public String render(Node root, boolean processExtendRoots) {
OutputList output = new OutputList(config.getMaxOutputSize());

public String render(Node root, boolean processExtendRoots, long renderLimit) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be public

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's easier to increase visibility later than to decrease it

Comment on lines 300 to 301
public String render(Node root, long renderLimit) {
return render(root, true, renderLimit);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to add this method

}

/**
* Render the given root node, processing extend parents. Equivalent to render(root, true)
* Render the given root node, processing extend parents. Equivalent to render(root, true, -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to change this, also it's not the same as that since it passes the max output size from the config

Comment on lines 304 to 307
long safeRenderSize = (config.getMaxOutputSize() == 0)
? renderLimit
: Math.min(renderLimit, config.getMaxOutputSize());
OutputList output = new OutputList(safeRenderSize);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone could pass a negative or 0-value render limit and bypass the max output size.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it would be good to test these different cases for ensuring render limit doesn't allow rendering more than configured

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So by default, this using 0 (unlimited) as the render size makes me wonder what the problem is here. Do we have cases where we modify this config value for limited length rendering? As per my logic here in the filter, if no value/an invalid value is provided, we just pass in 0 anyway, so that to me seems like an easy workaround.

Right now, config.getMaxOutputSize() returns 0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If config.getMaxOutputSize() is 100 and renderLimit is 0, then it will bypass the configured limit and render unlimited characters.
For HubL, we are always setting a non-zero value for config.getMaxOutputSize()

Comment on lines 927 to 939
private long clampOutputSizeSafely(long providedLimit) {
long configMaxOutput = config.getMaxOutputSize();

if (configMaxOutput == 0) {
return providedLimit;
}

if (providedLimit <= 0) {
return configMaxOutput;
}

return Math.min(providedLimit, configMaxOutput);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, can we just get some tests for this logic?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks a lot Jack. To avoid repeating tests or changing signatures I moved this into a small static utils class which I tested on it's own. Let me know if you'd rather I just make it public in the interpreter or add more tests to the render method as a whole and take it back to being private.

I did like this a bit for simplicity though.

@asegal-hs asegal-hs merged commit bf66df2 into master Nov 27, 2023
4 checks passed
@asegal-hs asegal-hs deleted the capped-rendering branch November 27, 2023 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants