Skip to content

Fix logo and address not showing in Sticker#3

Merged
dkayiwa merged 14 commits intoopenmrs:mainfrom
jnsereko:O3-5123
Nov 4, 2025
Merged

Fix logo and address not showing in Sticker#3
dkayiwa merged 14 commits intoopenmrs:mainfrom
jnsereko:O3-5123

Conversation

@jnsereko
Copy link
Contributor

@jnsereko jnsereko commented Oct 14, 2025

Description

This PR addresses two issues:

  1. Logo not displaying

    • The logo could not be pulled from other modules using relative paths with Docker (e.g., moduleResources/legacyui/images/openmrs_logo_white_large.png or moduleResources/legacyui/openmrs_logo_white_large.png

    • Solution: Added ability to supply a custom logo resolved under OPENMRS_APPLICATION_DATA_DIRECTORY (e.g., /openmrs/data/my_custom_logo.png) and as a fall back, an OpenMRS logo pulled from the servlet context ie /images/openmrs_logo_white_large.png

  2. Address not showing

    • The Address object from the patient object was being accessed with the wrong property name

    • Solution: Corrected the property name to properly retrieve patient address information

Screenshot

Screenshot 2025-10-15 at 13 56 23 Screenshot 2025-10-15 at 13 54 22

Related issue

https://openmrs.atlassian.net/browse/O3-5123

@jnsereko jnsereko marked this pull request as draft October 14, 2025 12:45
@jnsereko jnsereko requested review from dkayiwa and ibacher October 15, 2025 10:58
@jnsereko jnsereko marked this pull request as ready for review October 15, 2025 10:58
@jnsereko
Copy link
Contributor Author

Hey @dkayiwa and @ibacher could you kindly look at this as we add this module to the distro here

@dkayiwa
Copy link
Member

dkayiwa commented Oct 15, 2025

Don't we already have the openmrs logo in core?

@jnsereko jnsereko requested a review from ibacher October 28, 2025 10:22
@jnsereko
Copy link
Contributor Author

jnsereko commented Oct 28, 2025

hello @ibacher and @dkayiwa I have improved logic to;

  • get the OpenMRS logo from the servlet context and cache it in the OPENMRS_APPLICATION_DATA_DIRECTORY as a fallback in case custom logo has not been found.
  • get the custom log from OPENMRS_APPLICATION_DATA_DIRECTORY and its relative path eg /openmrs/data/my_custom_logo.png

@jnsereko
Copy link
Contributor Author

Hey @dkayiwa and @ibacher
Could you kindly re-review this?

}
}

private void loadAndCacheDefaultLogo(ServletContext servletContext) {
Copy link
Member

Choose a reason for hiding this comment

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

Why are you caching it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dkayiwa since we can only get the default logo using the servlet context, yet we need to use it from the API, I thought it’s better saving it for better performance.

Copy link
Member

Choose a reason for hiding this comment

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

What was the performance difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dkayiwa , the logo needs to be accessed for every patient document generated. In a busy hospital setting with potentially hundreds of patients per day, repeatedly reading from the servlet context for each document would mean hundreds of I/O operations daily for the same 8KB file. Caching it once to the application data directory eliminates this repeated overhead. The servlet context resource stream needs to be opened and closed on each access, whereas with caching, we read once and reuse. I've also added a check to ensure we only cache if the file doesn't already exist.

Copy link
Member

@dkayiwa dkayiwa Oct 30, 2025

Choose a reason for hiding this comment

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

Are you caching it in memory such that you do not do any further I/O on disk?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dkayiwa, good point. I've removed the caching mechanism entirely as it was adding unnecessary disk I/O and complexity without clear performance benefits.
The logo is now loaded directly from the servlet context and embedded as a base64 data URI in the XML output.

@jnsereko jnsereko requested a review from dkayiwa October 30, 2025 07:29

The optional header section can contain:
- An organizational logo on the left (loaded from HTTP URL)
- An organizational logo on the left (from a file path under `OPENMRS_APPLICATION_DATA_DIRECTORY`)
Copy link
Member

Choose a reason for hiding this comment

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

Is this correct?

Copy link
Contributor Author

@jnsereko jnsereko Oct 30, 2025

Choose a reason for hiding this comment

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

Yes it is. We get the custom logo like new File(OpenmrsUtil.getDirectoryInApplicationDataDirectory(""), logoUrlPath)

@jnsereko jnsereko requested a review from dkayiwa October 30, 2025 13:49
// 2. Fall back to default logo
if (isBlank(logoPath) && defaultLogoBytes != null && defaultLogoBytes.length > 0) {
String base64Image = Base64.getEncoder().encodeToString(defaultLogoBytes);
logoPath = "data:image/png;base64," + base64Image;
Copy link
Member

Choose a reason for hiding this comment

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

What happens when the logo is not a png?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you @dkayiwa. This is the default fallback logo, which we hardcoded to a PNG file at DEFAULT_LOGO_CLASSPATH = "/images/openmrs_logo_white_large.png"
Are we expecting the default logo format to change from PNG to something else? If so, I can make this more dynamic, but otherwise the hardcoded MIME type should match the hardcoded PNG file.

Copy link
Member

Choose a reason for hiding this comment

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

What happens when someone's config has a JPG?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The user-supplied logo will be retrieved using its absolute path (step 1 in configureLogo()) before falling back to the default logo. So if someone configures a JPG in their report.patientIdSticker.logourl setting, the absolute file path to that JPG will be used directly. The MIME type image/png only applies to our hardcoded default fallback logo (openmrs_logo_white_large.png), not to user-supplied images.

Map<String, String> addressData = (Map<String, String>) patientData.get("preferredAddress");
if (addressData != null) {
List<Map<String, String>> addressData = (List<Map<String, String>>) patientData.get("addresses");
if (addressData != null && !addressData.isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

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

Is this also related to the logo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No! This ensures that the address data is pulled from the right variable in the Patient Data object.
Since its a single line of change and related to intended field field not showing, i thought its better merging the work with the logo not showing.

@jnsereko jnsereko requested a review from dkayiwa November 3, 2025 14:34
@jnsereko
Copy link
Contributor Author

jnsereko commented Nov 4, 2025

Hey @dkayiwa and @ibacher,
Could you kindly take a look at my latest changes and share your feedback? Thanks!

// Create and append logo elements
Element branding = doc.createElement("branding");
Element image = doc.createElement("logo");
image.setTextContent(logoPath);
Copy link
Member

Choose a reason for hiding this comment

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

What is displayed for the image when logoPath is an empty string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have conditionally added logo creation.

@dkayiwa
Copy link
Member

dkayiwa commented Nov 4, 2025

Is the pull request description still valid?

@jnsereko jnsereko requested a review from dkayiwa November 4, 2025 15:56
@jnsereko
Copy link
Contributor Author

jnsereko commented Nov 4, 2025

Is the pull request description still valid?

I have revised the pull request description and believe it now provides a more comprehensive and accurate representation of the changes.

@dkayiwa dkayiwa merged commit ede0660 into openmrs:main Nov 4, 2025
1 check passed
@dkayiwa
Copy link
Member

dkayiwa commented Nov 4, 2025

@jnsereko though i have merged this, i would like us to limit this to only locations in the application data directory. Can you deal with the security safeguards against path traversal or unintended file reads?
After doing that in a followup pull request, we then should be able to include this in O3

@jnsereko
Copy link
Contributor Author

jnsereko commented Nov 5, 2025

@jnsereko though i have merged this, i would like us to limit this to only locations in the application data directory. Can you deal with the security safeguards against path traversal or unintended file reads? After doing that in a followup pull request, we then should be able to include this in O3

Thank you @dkayiwa!
I have created a followup Up PR solving this here.

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.

3 participants