Tag: notifications

  • Sending Prowl Alerts via Bash

    Sending Prowl Alerts via Bash

    I’m working on some server scripting and I wanted to find a way to make sure I get proper alerts. I tried hard getting Twilio working cheaply, but that failed. So I remembered that I use Prowl for other things on my phone–so why not just send more alerts that way?

    So, again with the help of ChatGPT I have made a terrible monstrosity:

    #!/bin/bash
    
    # Exit if any command fails, if an unset variable is used, or if a command in a pipeline fails
    set -euo pipefail
    
    # Default values
    application="Shell Notification"
    priority=0
    event="Event"
    message=""
    logfile="/var/log/send-prowl-alert.log"
    url=""
    
    # Usage information
    usage() {
        echo "Usage: $0 --message=<message> [--application=<application>] [--event=<event>] [--description=<description>] [--priority=<priority>] [--url=<url>]"
        echo "Required:"
        echo "  --message=<message>       A description of the event, generally terse"
        echo "                            Maximum of 10000 bytes"
        echo "Optional:"
        echo "  --application=<application>  The name of the application (default: 'Shell Notification')"
        echo "                               Maximum of 256 bytes"
        echo "  --event=<event>              The name of the event or subject of the notification (default: 'Event')"
        echo "                               Maximum of 1024 bytes"
        echo "  --priority=<priority>        The priority of the alert (default: 0)"
        echo "                               An integer value ranging [-2, 2] representing:"
        echo "                                   -2 Very Low"
        echo "                                   -1 Moderate"
        echo "                                    0 Normal"
        echo "                                    1 High"
        echo "                                    2 Emergency"
        echo "                               Emergency priority messages may bypass quiet hours according to the user's settings."
        echo "  --url=<url>                  The URL which should be attached to the notification"
        echo "                               Maximum of 512 bytes"
        echo "  --help                       Displays this help message"
    }
    
    # URL Encodes a string
    urlencode() {
      local string="$1"
      local length="${#string}"
      local i
    
      for ((i = 0; i < length; i++)); do
        local c="${string:i:1}"
        case $c in
          [a-zA-Z0-9.~_-])
            printf '%s' "$c"
            ;;
          *)
            printf '%%%02X' "'$c"
            ;;
        esac
      done
    }
    
    # Check if the script is being run manually or via cron
    if [[ -t 1 ]]; then
        # Output to console if being run manually
        log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
    else
        # Output to log file if being run via cron
        log_message() {
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "${logfile}"
            # Truncate the log file to 1 megabyte
            if [[ $(wc -c <"${logfile}") -gt 1000000 ]]; then
                tail -c 1000000 "${logfile}" > "${logfile}.tmp" && mv "${logfile}.tmp" "${logfile}"
            fi
        }
    fi
    
    # Parse arguments
    for arg in "$@"; do
        case "${arg}" in
            --message=*)
                message=${arg#*=}
                ;;
            --application=*)
                application=${arg#*=}
                ;;
            --event=*)
                event=${arg#*=}
                ;;
            --priority=*)
                priority=${arg#*=}
                ;;
            --url=*)
                url=${arg#*=}
                ;;
            --help)
                usage
                exit 0
                ;;
            *)
                echo "Error: Unsupported argument ${arg}"
                usage
                exit 1
                ;;
        esac
    done
    
    
    # Create a variable to store error messages
    errors=""
    
    # Check if curl is installed
    if ! command -v curl &> /dev/null; then
        errors+="Error: curl is not installed. Please install curl and try again.\n"
    fi
    
    # Check that a message was provided
    if [[ -z "${message}" ]]; then
        errors+="Error: No message provided."
    fi
    
    # Check if the URL is valid
    if [[ -n $url && ! $url =~ ^(https?://)[^\s/$.?#].[^\s]*$ ]]; then
        errors+="Error: Invalid URL.\n"
    fi
    
    # Check byte size of the parameters and append error if they exceed the max limit
    if [[ "${#url}" -gt 512 ]]; then
        errors+="Error: URL exceeds maximum byte limit (512 bytes).\n"
    fi
    
    if [[ "${#application}" -gt 256 ]]; then
        errors+="Error: Application name exceeds maximum byte limit (256 bytes).\n"
    fi
    
    if [[ "${#event}" -gt 1024 ]]; then
        errors+="Error: Event name exceeds maximum byte limit (1024 bytes).\n"
    fi
    
    if [[ "${#message}" -gt 10000 ]]; then
        errors+="Error: Message exceeds maximum length (10000 bytes).\n"
    fi
    
    if [[ ! "${priority}" =~ ^-?[0-2]$ ]]; then
        errors+="Error: Invalid priority. Must be an integer between -2 and 2.\n"
    fi
    
    # Check if the API key file exists and is not empty
    if [[ ! -s ~/.prowl_api_key ]]; then
        errors+="Error: The Prowl API key file does not exist or is empty. Please create a file at ~/.prowl_api_key and add your API key to it.\nExample:\n  echo 'your_api_key' > ~/.prowl_api_key\n  chmod 600 ~/.prowl_api_key\n"
    fi
    
    # Check the permissions on the API key file, if it exists
    # We have to do it in a convoluted cross platform way because macos does not support `stat -c`
    if [[ -f ~/.prowl_api_key ]]; then
        # Retrieve the file permissions and remove any trailing '@' symbol (indicating extended attributes)
        permissions=$(ls -l -d ~/.prowl_api_key | awk '{print $1}' | tr -d '@')
    
        # Check if the permissions are not set to '-rw-------'
        if [[ "$permissions" != "-rw-------" ]]; then
            # Add an error message to the 'errors' variable
            errors+="Error: The permissions on the API key file are not set correctly. Please run 'chmod 600 ~/.prowl_api_key' and try again.\n"
        fi
    fi
    
    # If any errors were detected, print the error messages and exit
    if [[ -n $errors ]]; then
        echo -e "${errors}"  # -e enables interpretation of backslash escapes like \n
        exit 1
    fi
    
    # Get the Prowl API key
    prowl_api_key=$(cat ~/.prowl_api_key)
    
    # Save the alert data for logging before we encode it
    alert_log_string="$application : $event : $priority : $url : $message"
    
    # URL-encode the variables
    prowl_api_key=$(urlencode "$prowl_api_key")
    application=$(urlencode "$application")
    event=$(urlencode "$event")
    message=$(urlencode "$message")
    priority=$(urlencode "$priority")
    url=$(urlencode "$url")
    
    # Send the alert
    response=$(curl -s "https://api.prowlapp.com/publicapi/add?apikey=${prowl_api_key}&application=${application}&event=${event}&description=${message}&priority=${priority}&url=${url}")
    
    # Check if the alert was sent successfully
    if [[ "${response}" != *"success code=\"200\""* ]]; then
        log_message "Error sending alert: ${alert_log_string}"
        log_message "Response: ${response}"
        exit 1
    fi
    
    log_message "Alert sent successfully: $alert_log_string"
    exit 0
    Code language: PHP (php)

    Good luck!

  • Limiting Featured Image Dimensions in WordPress

    Limiting Featured Image Dimensions in WordPress

    As a follow up to my last post about limiting file sizes during uploads, I had to come back to the problem with limiting image sizes for featured images. Not bytes this time, but pixel dimensions.

    Still being a bit of a block editor newb, this was an interesting challenge for me, and I was really surprised at how easy it was to implement. I basically googled around and found a few different things to put together that worked for me. The primary source was a post by Igor Benic on how to disable the publish button:

    After that, I discovered how to add notifications to the block editor, to tell when the image was too large, thanks to a post by David F. Carr:

    So what’s it look like? Well, it’s pretty simple. If you choose a featured image that’s too large for the settings, it will add a non-dismissible error notification to the editor:

    Then it will block you from hitting the publish button:

    So, finally the code. This is just enqueued in as a simple add_action() during the enqueue_block_editor_assets hook. I’m absolutely not a good JS developer, so please don’t judge me too harshly. Also, that means this could be riddled with bugs. Use at your own risk 😀

    var postLocked = false;
    wp.domReady( () => {
    	wp.data.subscribe( function() {
    		var imageId = wp.data.select( 'core/editor' ).getEditedPostAttribute( 'featured_media' ); // Featured Image ID.
    
    		// If we have no image ID, and we already locked the post, we won't do anything.
    		if ( imageId ) {
    			blockEditorSettings = wp.data.select('core/block-editor').getSettings();
    
    			// Default to 1200px wide.
    			maxImageSize = 1200;
    			imageAttrs = wp.data.select('core').getMedia( imageId );
    
    			// Get the size for the "large image" and if it's available, use that instead.
    			if ( typeof blockEditorSettings !== 'undefined' && blockEditorSettings.hasOwnProperty( 'imageDimensions' ) ) {
    				maxImageSize = blockEditorSettings.imageDimensions.large.width;
    			}
    
    			if ( typeof imageAttrs !== 'undefined' && imageAttrs.hasOwnProperty( 'media_details') ) {
    				// Publish is not locked and width is too large.
    				if ( ! postLocked && imageAttrs.media_details.width > maxImageSize ) {
    					postLocked = true;
    					wp.data.dispatch( 'core/editor' ).lockPostSaving( 'featuredImageTooLarge' );
    
    					wp.data.dispatch('core/notices').createNotice(
    						'error', // Can be one of: success, info, warning, error.
    						wp.i18n.__( wp.i18n.sprintf( 'Featured image width must be less than %spx, currently %spx. Publishing is disabled.', maxImageSize, imageAttrs.media_details.width ) ),
    						{
    							id: 'featuredImageTooLarge', // Assigning an ID prevents the notice from being added repeatedly.
    							isDismissible: false, // Whether the user can dismiss the notice.
    						}
    					);
    				}
    
    			}
    		} else if ( postLocked ) {
    			postLocked = false;
    			wp.data.dispatch( 'core/editor' ).unlockPostSaving( 'featuredImageTooLarge' );
    			wp.data.dispatch('core/notices').removeNotice( 'featuredImageTooLarge' );
    		}
    	} );
    } );Code language: JavaScript (javascript)
  • iPhone – Day 4

    iPhone – Day 4

    The big issue I’m having with iOS right now is the notification system.  I feel like I’ve stepped back in time years.  For a while now Android has had the ability to group similar notifications for an app.  This makes organizing and clearing notifications very easy.

    Compare this to iOS where the notifications are all separate:

    Along with this difference, clearing notifications takes more interactions.  You either have to swipe left and tap, or swipe left twice.  With Android, it’s one simple swipe and all of those unwanted notifications for a single app are gone.

    I know this sounds like a silly detail to complain about, but there’s just so much more about the Android notification experience.  Many of the notifications are “rich” and provide more details when swiped down, such as image previews, more details, or the ability to reply to messages inline without opening an app.

    It may be that iOS has these features as well, and I just don’t know how to use them since these features came to me organically on Android as they were added over the years.  Because of that, I won’t hold it against iOS too much, but it’s still points taken away.