Skip to content

Fix logo and address not showing in Sticker#3

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

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

Conversation

@jnsereko

@jnsereko jnsereko commented Oct 14, 2025

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Contributor Author

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

@dkayiwa

dkayiwa commented Oct 15, 2025

Copy link
Copy Markdown
Member

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

Comment thread api/src/main/resources/msfStickerFopStylesheet.xsl
@jnsereko
jnsereko requested a review from ibacher October 28, 2025 10:22
@jnsereko

jnsereko commented Oct 28, 2025

Copy link
Copy Markdown
Contributor Author

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
Copy Markdown
Contributor Author

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

}
}

private void loadAndCacheDefaultLogo(ServletContext servletContext) {

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.

@dkayiwa dkayiwa Oct 30, 2025

Copy link
Copy Markdown
Member

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
Copy Markdown
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
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this correct?

@jnsereko jnsereko Oct 30, 2025

Copy link
Copy Markdown
Contributor Author

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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

jnsereko commented Nov 4, 2025

Copy link
Copy Markdown
Contributor Author

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
Copy Markdown
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
Copy Markdown
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

dkayiwa commented Nov 4, 2025

Copy link
Copy Markdown
Member

Is the pull request description still valid?

@jnsereko
jnsereko requested a review from dkayiwa November 4, 2025 15:56
@jnsereko

jnsereko commented Nov 4, 2025

Copy link
Copy Markdown
Contributor Author

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

dkayiwa commented Nov 4, 2025

Copy link
Copy Markdown
Member

@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

jnsereko commented Nov 5, 2025

Copy link
Copy Markdown
Contributor Author

@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