Skip to content

Conversation

@kelliott72
Copy link

@kelliott72 kelliott72 commented Apr 15, 2025

New Feature:
Add support for notifications using Apprise-api, which supports over 100 notification types and has an Unraid app docker.

Summary by CodeRabbit

  • New Features
    • Introduced a new notification agent configuration for Apprise, allowing users to customize server URL, notification title, message, tags, and importance level for more flexible and targeted notifications.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 15, 2025

Walkthrough

A new XML agent configuration named "Apprise" has been added. This configuration introduces six variables for server URL, stateful key, tags, stateless URLs, title, and message. It includes an embedded Bash script that processes these variables, formats a JSON payload for notification delivery, and sends it to a specified server endpoint using a POST request. The script also handles normalization of input values and maps importance levels to priority strings.

Changes

File(s) Change Summary
emhttp/plugins/dynamix/agents/Apprise.xml Added a new XML agent definition for "Apprise" with configurable variables and an embedded Bash script for notifications.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AppriseAgent (Bash Script)
    participant AppriseServer

    User->>AppriseAgent: Provide notification variables (SERVER_URL, STATEFUL_KEY, etc.)
    AppriseAgent->>AppriseAgent: Normalize and process variables
    AppriseAgent->>AppriseAgent: Map IMPORTANCE to PRIORITY
    AppriseAgent->>AppriseAgent: Build JSON payload
    AppriseAgent->>AppriseServer: POST /notify[/{STATEFUL_KEY}] with JSON payload
    AppriseServer-->>AppriseAgent: Response
Loading

Poem

A new agent hops into view,
With variables six, not a few!
It crafts a JSON, neat and tight,
Sends your message through the night.
Apprise now joins the notification crew—
Bash and curl, working for you!
🐇✨

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
emhttp/plugins/dynamix/agents/Apprise.xml (1)

40-43: Add error handling for curl failures.

Currently, the script does not check if the curl command succeeds or fails. For better reliability and troubleshooting, capture the exit code and output an error message if the notification fails.

Example addition:

-curl -X POST \
-  -H "Content-Type: application/json" \
-  -d "$JSON" \
-  $SERVER_URL/notify${STATEFUL_KEY:+/$STATEFUL_KEY} 2>&1
+response=$(curl -s -w "%{http_code}" -o /tmp/apprise_response.txt -X POST \
+  -H "Content-Type: application/json" \
+  -d "$JSON" \
+  "$SERVER_URL/notify${STATEFUL_KEY:+/$STATEFUL_KEY}")
+if [ "$response" -ne 200 ]; then
+  echo "Apprise notification failed with HTTP status $response"
+  cat /tmp/apprise_response.txt
+fi

This helps with debugging and ensures failures are visible.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6486409 and 54789ab.

⛔ Files ignored due to path filters (1)
  • emhttp/plugins/dynamix/icons/apprise.png is excluded by !**/*.png
📒 Files selected for processing (1)
  • emhttp/plugins/dynamix/agents/Apprise.xml (1 hunks)
🔇 Additional comments (1)
emhttp/plugins/dynamix/agents/Apprise.xml (1)

2-11: XML structure and variable definitions are clear and comprehensive.

The agent definition and variable descriptions are well-written and provide clear guidance to users configuring Apprise notifications. Default values and help texts are appropriate.

Comment on lines +38 to +43
JSON="{\"urls\":\"$STATELESS_URLS\",\"tag\":\"$TAGS\",\"type\":\"$PRIORITY\",\"title\":\"$TITLE\",\"body\":\"$MESSAGE\"}"

curl -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
$SERVER_URL/notify${STATEFUL_KEY:+/$STATEFUL_KEY} 2>&1
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Potential JSON injection and quoting issues in payload construction.

  • The JSON payload is constructed via string interpolation, which is unsafe if any variable contains quotes, backslashes, or newlines. This can break the JSON structure and potentially cause notification failures or security issues.
  • Consider using a tool like jq -n or printf '%s' with proper escaping to build the JSON payload safely.

Example fix using jq (if available in the environment):

-JSON="{\"urls\":\"$STATELESS_URLS\",\"tag\":\"$TAGS\",\"type\":\"$PRIORITY\",\"title\":\"$TITLE\",\"body\":\"$MESSAGE\"}"
+JSON=$(jq -n \
+  --arg urls "$STATELESS_URLS" \
+  --arg tag "$TAGS" \
+  --arg type "$PRIORITY" \
+  --arg title "$TITLE" \
+  --arg body "$MESSAGE" \
+  '{urls: $urls, tag: $tag, type: $type, title: $title, body: $body}')

If jq is not available, at minimum, escape double quotes and backslashes in variables before constructing the JSON string.

  • Additionally, consider capturing the exit code of curl and logging or handling errors for better robustness.

Would you like a ready-to-use Bash snippet for safe JSON construction without jq?

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
JSON="{\"urls\":\"$STATELESS_URLS\",\"tag\":\"$TAGS\",\"type\":\"$PRIORITY\",\"title\":\"$TITLE\",\"body\":\"$MESSAGE\"}"
curl -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
$SERVER_URL/notify${STATEFUL_KEY:+/$STATEFUL_KEY} 2>&1
JSON=$(jq -n \
--arg urls "$STATELESS_URLS" \
--arg tag "$TAGS" \
--arg type "$PRIORITY" \
--arg title "$TITLE" \
--arg body "$MESSAGE" \
'{urls: $urls, tag: $tag, type: $type, title: $title, body: $body}')
curl -X POST \
-H "Content-Type: application/json" \
-d "$JSON" \
$SERVER_URL/notify${STATEFUL_KEY:+/$STATEFUL_KEY} 2>&1

Comment on lines +14 to +29
#!/bin/bash
############
{0}
############
MESSAGE=$(echo -e "$MESSAGE")
case "$IMPORTANCE" in
'normal' )
PRIORITY="info"
;;
'warning' )
PRIORITY="warning"
;;
'alert' )
PRIORITY="failure"
;;
esac
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Bash script logic is clear, but input handling and quoting could be improved.

  • The mapping of IMPORTANCE to PRIORITY is correct and clear.
  • However, the script does not quote variable expansions (e.g., $STATEFUL_KEY, $STATELESS_URLS, $TAGS) in the if statements, which can cause errors if variables contain spaces or are empty.
  • Consider quoting all variable expansions to prevent word splitting and unexpected behavior.

Example fix:

-if [ $STATEFUL_KEY == 'none' ]; then STATEFUL_KEY=; fi
-if [ $STATELESS_URLS == 'none' ]; then STATELESS_URLS=; fi
-if [ $TAGS == 'none' ]; then TAGS=; fi
+if [ "$STATEFUL_KEY" == 'none' ]; then STATEFUL_KEY=; fi
+if [ "$STATELESS_URLS" == 'none' ]; then STATELESS_URLS=; fi
+if [ "$TAGS" == 'none' ]; then TAGS=; fi

Committable suggestion skipped: line range outside the PR's diff.

@Squidly271
Copy link
Contributor

has an Unraid app docker

So this agent has a dependency of the apprise container being installed? (or another server running a apprise?)

Problem with the dependency, especially if its on the same server as a container would be that if something happens to the docker image / container, or if the array is stopped or docker system (or container) is stopped then notifications would be not be sent through which could prove to be troublesome.

Not my decision, but why not instead have it installed outside of the OS via a plugin (see https://raw.githubusercontent.com/Squidly271/Wxwork-sample/main/wxwork-sample.plg for how to do this) along with an appropriate xml for CA to be able to include it.

(FWIW, I love Apprise! Just wish that I could have managed to get it to do text messages without paying for it)

@kelliott72
Copy link
Author

Hi @Squidly271 - appreciate the comment, I'll go take a look at the plugin url you provided. Just trying to understand... As far as I can tell, this works the same as any of the other notification services, it just makes a curl request to a server with the message payload, doesn't necessarily have to be running on unraid. There's no real unraid os dependency, maybe I should have said apprise-api, since that's the rest api to apprise - [https://github.com/caronc/apprise-api].

For example, I'm running the gotify server on my unraid and using the gotify notification service which is already one of the options. I simply copied it's xml and tweaked it a bit. This just keeps the notification in the same place as all of the others and uses the same framework.

I've seen a request for support for apprise in several threads on the forum and since I wanted it too just took a stab at it.

Thanks!

@Squidly271
Copy link
Contributor

OK. Just as soon as I saw you mention the apprise container then I had concerns. But as you correctly noted (and reminded me of) is that other agents (not all of them) also have requirements for a container / executable to be operating in a container or on a separate server. I'm good either way.

That being said, the plugin route to get the xml into the system has as an advantage that it works on OS v 7.0.0 / 7.0.1 (this PR will only take effect if merged for 7.1.0) and if for some reason the API being leveraged has a breaking change / additional options etc then via the plg route modifications can be easily made instead of the changes required in the xml only taking effect going forward.

But, you should also consider the code modifications that coderabbit suggested here https://github.com/unraid/webgui/pull/2151/files#r2044656448

@ljm42
Copy link
Member

ljm42 commented Apr 23, 2025

Hi @kelliott72 Code Rabbit made a few suggestions that I think would be worth implementing here

@ljm42 ljm42 added the TBD label Apr 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants