Skip to content

fix(api): decode HTML entities in plain-text email bodies - #9805

Open
RealBhupesh wants to merge 1 commit into
makeplane:previewfrom
RealBhupesh:fix/plain-text-email-url-entities
Open

fix(api): decode HTML entities in plain-text email bodies#9805
RealBhupesh wants to merge 1 commit into
makeplane:previewfrom
RealBhupesh:fix/plain-text-email-url-entities

Conversation

@RealBhupesh

@RealBhupesh RealBhupesh commented Sep 9, 2026

Copy link
Copy Markdown

Description

Workspace invitation emails keep a fallback URL under “If the button doesn’t work, copy and paste this link”. HTML templates escape & as &, and generate_plain_text_from_html() only stripped tags, so the plain-text part still contained &slug / &token. Copied links never loaded invitation details.

This decodes entities after stripping tags in the shared helper used by invitation and other email tasks.

Related stale draft: #9522 (targets develop / old apiserver/ paths; current tasks already go through this helper).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

N/A — full SMTP stack was not run. Verified html.unescape(strip_tags(...)) turns invitation URLs back into ?invitation_id=…&slug=…&token=….

Test Scenarios

  • Unit: generate_plain_text_from_html decodes &amp; in invitation URLs and still strips <style> / tags
  • Send a workspace invitation with SMTP and copy the fallback URL — query params should be slug and token, not amp;slug / amp;token
  • HTML invitation emails still use escaped &amp; in href attributes

References

Fixes #9497

Made with Cursor

Summary by CodeRabbit

  • Bug Fixes

    • Invitation links in plain-text emails now preserve ampersands in query parameters instead of displaying encoded HTML entities.
    • Plain-text email conversion continues to remove styling blocks and HTML tags while preserving readable text.
  • Tests

    • Added coverage for HTML entity decoding and removal of styles and tags in plain-text email content.

Invitation fallback URLs were keeping `&amp;` after strip_tags, so
copied links parsed amp;slug and amp;token and never loaded.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coldtea-pr-lens

coldtea-pr-lens Bot commented Sep 9, 2026

Copy link
Copy Markdown

◈ PR Lens

🟢 +0 new · 🟠 ~1 changed · 🔴 -0 removed · 1 flow · 2 files · commit 4d68cfe


Architecture

Architecture diagram for makeplane/plane at 4d68cfe

1 component touched across 2 lanes.

Open the interactive canvas


Data flow

Data flow diagram for makeplane/plane at 4d68cfe

Converting HTML emails to plain text

Open the interactive canvas


Drill down
Background Workers — 1 component
🟡 CHANGED Email Utilities

Converts HTML email templates into plain text alternatives with decoded entities.


View

  • Architecture lens
  • Data flow lens
  • Expand every detail
  • Show unchanged neighbours

Tip

GitHub will not let you zoom an image in a comment. The link under each diagram opens it on an interactive canvas, where you can zoom, pan and step through the flow.

🪧 More tips
  • Run PR Lens on your own machine: npx skills add coldteadotai/pr-lens installs the agent skill. Then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."
  • Draw a diff before it is even a pull request: npx @coldtea/pr-lens-cli analyze --base origin/main reads the diff with your own model key, and npx @coldtea/pr-lens-cli render .pr-lens/graph.json draws the same lenses on your machine.
  • The boxes under View are live. Tick Architecture lens or Data flow lens to choose which diagrams appear, or Expand every detail to open every drill-down at once. The comment redraws in place a few seconds later.
  • Show unchanged neighbours lists the components this change did not touch alongside the ones it did, so the drill-down shows what the changed code sits next to.
  • The CLI's render picks up .github/pr-lens.yml automatically and applies your corrections (renames, exclusions, lane pins) at draw time.
  • Would you rather run it from CI on a key of your own? Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and a model key in your repository secrets, say GEMINI_API_KEY. The Action asks Gemini by default, or OpenAI and any endpoint speaking /chat/completions through its provider input.
  • PR Lens is free for open source. A star on the repository is what keeps it going.
  • Push a new commit and the whole comment re-renders for the new head. An older run never overwrites a newer one, so a slow render cannot put a stale diagram back.
  • The diagrams follow your GitHub theme, so dark mode gets the dark render and light mode the light one, and the moving dots show this pull request's data in motion.

◈ Rendered by PR Lens · crafted with ❤️ by the Coldtea team · Come say hi on Discord

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 81c99353-e2c6-40a7-8a87-cf6b181eaeb4

📥 Commits

Reviewing files that changed from the base of the PR and between 1fec307 and 4d68cfe.

📒 Files selected for processing (2)
  • apps/api/plane/tests/unit/utils/test_email.py
  • apps/api/plane/utils/email.py

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The email utility now decodes HTML entities after stripping HTML tags. Unit tests verify decoded invitation URLs and preserved text content without styles or tags.

Changes

Plain-text email entity decoding

Layer / File(s) Summary
Decode entities in plain-text email output
apps/api/plane/utils/email.py, apps/api/plane/tests/unit/utils/test_email.py
generate_plain_text_from_html now converts entities such as &amp; to & after removing tags. Unit tests cover invitation URLs, style removal, tag removal, and preserved text.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 4d68c

Plain-text email fallbacks now produce usable invitation URL query separators while HTML email escaping remains unchanged. The targeted behavior is covered and no current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: decoding HTML entities in plain-text email bodies.
Description check ✅ Passed The description is complete. It explains the bug, identifies the fix, records the change type, documents test coverage and limitations, and references issue #9497.
Linked Issues check ✅ Passed The implementation meets issue #9497. It decodes HTML entities after stripping tags, fixes plain-text invitation URLs, and preserves HTML rendering behavior. Unit tests cover entity decoding and tag r…
Out of Scope Changes check ✅ Passed All code changes are directly related to the linked issue. The helper change and its unit tests address plain-text invitation URL generation without unrelated modifications.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

Bug: Workspace invitation plain-text fallback link contains escaped query separators

1 participant