A Rocket.Chat Apps-Engine app that automatically converts ticket references like #1234 or GH-42 in chat messages into clickable ticket URLs, across any number of independently configured ticket systems.
When a user sends a message containing a ticket reference matching one of the configured rules, the app rewrites it into a full ticket URL before the message is posted:
Can someone look at #1234? Also see GH-42.
becomes
Can someone look at https://www.myticketurl.com/1234? Also see https://github.com/org/repo/issues/42.
The app implements the IPreMessageSentModify event handler, which runs on every message before it is sent:
- Check phase —
checkPreMessageSentModifyquickly tests whether the message matches any configured rule's pattern. If not, the app does nothing. - Modify phase —
executePreMessageSentModifyrewrites every match, from every rule, in a single pass.
- Code is left untouched. Fenced code blocks (
```) and inline code (`) are stashed as placeholders before rewriting and restored afterwards, so ticket-like patterns inside code are never modified. - Existing URLs are left untouched. A ticket reference that is part of a URL path or fragment (preceded by a word character or
/) is not rewritten.
Rules are configured from a single app setting, "Ticket Rules", editable from Admin → Apps → Ticket URL Generator → Settings with no code changes or repackaging required.
One rule per line:
<pattern> => <url template>
<pattern>— a regular expression matching a ticket reference. Must contain exactly one capturing group, which holds the ticket id.<url template>— the URL to build, with{{id}}marking where the ticket id goes — anywhere in the URL (path, query string, even the host).
Default, if left unconfigured:
#(\d+) => https://www.myticketurl.com/{{id}}
Example with several independent ticket systems active at once:
#(\d+) => https://www.myticketurl.com/{{id}}
GH-(\d+) => https://github.com/org/repo/issues/{{id}}
SUP-(\d+) => https://helpdesk.example.com/ticket?id={{id}}
Blank lines are ignored. A line is rejected if:
- the pattern doesn't compile as a regular expression,
- the pattern doesn't have exactly one capturing group (that group must hold the ticket id),
- the pattern is too complex and could hang the server on certain messages (catastrophic backtracking, e.g. nested repetition like
(a+)+) — avoid nested or ambiguous repetition, - the pattern matches an internal sample of ordinary chat text (dates, times, plain numbers, a URL, an email address — no ticket references) — this catches a pattern that's too loose, e.g. a bare
\d+with no fixed prefix, which would turn every stray number in every message into a bogus link. Give the pattern a specific, fixed prefix (#,GH-,TICKET-, ...) so it can't match incidentally, - the template lacks
{{id}}or isn't a validhttp(s)URL once{{id}}is substituted.
As further defense in depth regardless of how safe a saved pattern looks, the app never runs any pattern against a message longer than 5000 characters (Rocket.Chat's own default message size limit) — this bounds the worst case even for a pattern that turns out to be slow in some edge case the checks above didn't catch.
Validated on save (onPreSettingUpdate): if any line is invalid, the whole update is rejected and the previous value is kept — every invalid line's reason is logged in one go (not just the first) under Admin → Apps → Ticket URL Generator → Logs, so all of them can be fixed in one edit. The settings UI itself doesn't surface the reason.
If two rules' patterns could both match the same text, whichever match starts earliest in the message wins; among rules that could start at the same position, the first-listed rule wins.
Upgrading from a single pattern/URL pair (pre-0.1.0)? Rewrite it as one line in the new format, e.g. an old pattern #(\d+) and base URL https://www.myticketurl.com/ becomes #(\d+) => https://www.myticketurl.com/{{id}}. An old value with no => on any line has zero valid rules and silently falls back to the default above — check the app logs after upgrading if your rules aren't behaving as expected.
Requires the Rocket.Chat Apps CLI:
npm install -g @rocket.chat/apps-cli
npm installrc-apps packageThe packaged .zip is written to dist/.
rc-apps deploy --url <your-server-url> --username <admin-user> --password <admin-password>Or upload the zip from dist/ manually via Admin → Apps → Upload App (requires development mode enabled on the server).
| Permission | Why |
|---|---|
message.read |
Read outgoing messages to detect ticket references |
message.write |
Rewrite the message text with the generated URL |
See repository for license details.