Skip to content

Commit

Permalink
Add support for Expiring Messages
Browse files Browse the repository at this point in the history
Resolves openhab#15288

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
  • Loading branch information
jlaur committed Jul 22, 2023
1 parent 37c0e97 commit 67e9b2e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 18 deletions.
6 changes: 5 additions & 1 deletion bundles/org.openhab.binding.pushover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@ The parameter `message` is **mandatory**, the `title` parameter defaults to what
Parameters declared as `@Nullable` are not optional.
One has to pass a `null` value if it should be skipped or the default value for it should be used.

- `sendMessage(String message, @Nullable String title, @Nullable String sound, @Nullable String url, @Nullable String urlTitle, @Nullable String attachment, @Nullable String contentType, @Nullable Integer priority, @Nullable String device)` - This method is used to send a plain text message providing all available parameters.
- `sendMessage(String message, @Nullable String title, @Nullable String sound, @Nullable String url, @Nullable String urlTitle, @Nullable String attachment, @Nullable String contentType, @Nullable Integer priority, @Nullable String device, @Nullable Integer ttl)` - This method is used to send a plain text message providing all available parameters.

- `sendMessage(String message)` - This method is used to send a plain text message with default title.

- `sendMessage(String message, @Nullable String title)` - This method is used to send a plain text message.

- `sendMessage(String message, @Nullable String title, @Nullable Integer ttl)` - This method is used to send a plain text message with TTL (in seconds).

- `sendHtmlMessage(String message, @Nullable String title)` - This method is used to send a HTML message.

- `sendMonospaceMessage(String message, @Nullable String title)` - This method is used to send a monospace message.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
* Some automation actions to be used with a {@link PushoverAccountHandler}.
*
* @author Christoph Weitkamp - Initial contribution
* @author Jacob Laursen - Added support for Expiring Messages
*/
@ThingActionsScope(name = "pushover")
@NonNullByDefault
Expand All @@ -53,7 +54,8 @@ public class PushoverActions implements ThingActions {
@ActionInput(name = "attachment", label = "@text/sendMessageActionInputAttachmentLabel", description = "@text/sendMessageActionInputAttachmentDescription", type = "java.lang.String") @Nullable String attachment,
@ActionInput(name = "contentType", label = "@text/sendMessageActionInputContentTypeLabel", description = "@text/sendMessageActionInputContentTypeDescription", type = "java.lang.String", defaultValue = DEFAULT_CONTENT_TYPE) @Nullable String contentType,
@ActionInput(name = "priority", label = "@text/sendMessageActionInputPriorityLabel", description = "@text/sendMessageActionInputPriorityDescription", type = "java.lang.Integer", defaultValue = DEFAULT_EMERGENCY_PRIORITY) @Nullable Integer priority,
@ActionInput(name = "device", label = "@text/sendMessageActionInputDeviceLabel", description = "@text/sendMessageActionInputDeviceDescription", type = "java.lang.String") @Nullable String device) {
@ActionInput(name = "device", label = "@text/sendMessageActionInputDeviceLabel", description = "@text/sendMessageActionInputDeviceDescription", type = "java.lang.String") @Nullable String device,
@ActionInput(name = "ttl", label = "@text/sendMessageActionInputTTLLabel", description = "@text/sendMessageActionInputTTLDescription", type = "java.lang.Integer") @Nullable Integer ttl) {
logger.trace(
"ThingAction 'sendMessage' called with value(s): message='{}', title='{}', sound='{}', url='{}', urlTitle='{}', attachment='{}', contentType='{}', priority='{}', device='{}'",
message, title, sound, url, urlTitle, attachment, contentType, priority, device);
Expand Down Expand Up @@ -81,14 +83,28 @@ public class PushoverActions implements ThingActions {
if (device != null) {
builder.withDevice(device);
}
if (ttl != null) {
builder.withTTL(ttl.intValue());
}
return send(builder, title);
}

public static Boolean sendMessage(ThingActions actions, String message, @Nullable String title,
@Nullable String sound, @Nullable String url, @Nullable String urlTitle, @Nullable String attachment,
@Nullable String contentType, @Nullable Integer priority, @Nullable String device) {
@Nullable String contentType, @Nullable Integer priority, @Nullable String device, @Nullable Integer ttl) {
return ((PushoverActions) actions).sendMessage(message, title, sound, url, urlTitle, attachment, contentType,
priority, device);
priority, device, ttl);
}

@RuleAction(label = "@text/sendMessageActionLabel", description = "@text/sendMessageActionDescription")
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMessage(
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message) {
logger.trace("ThingAction 'sendMessage' called with value(s): message='{}'", message);
return send(getDefaultPushoverMessageBuilder(message), null);
}

public static Boolean sendMessage(ThingActions actions, String message) {
return ((PushoverActions) actions).sendMessage(message);
}

@RuleAction(label = "@text/sendMessageActionLabel", description = "@text/sendMessageActionDescription")
Expand All @@ -103,11 +119,30 @@ public static Boolean sendMessage(ThingActions actions, String message, @Nullabl
return ((PushoverActions) actions).sendMessage(message, title);
}

@RuleAction(label = "@text/sendMessageActionLabel", description = "@text/sendMessageActionDescription")
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMessage(
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
@ActionInput(name = "ttl", label = "@text/sendMessageActionInputTTLLabel", description = "@text/sendMessageActionInputTTLDescription", type = "java.lang.Integer") @Nullable Integer ttl) {
logger.trace("ThingAction 'sendMessage' called with value(s): message='{}', title='{}', ttl='{}'", message,
title, ttl);
PushoverMessageBuilder builder = getDefaultPushoverMessageBuilder(message);
if (ttl != null) {
builder.withTTL(ttl.intValue());
}
return send(builder, title);
}

public static Boolean sendMessage(ThingActions actions, String message, @Nullable String title,
@Nullable Integer ttl) {
return ((PushoverActions) actions).sendMessage(message, title, ttl);
}

@RuleAction(label = "@text/sendURLMessageActionLabel", description = "@text/sendURLMessageActionDescription")
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendURLMessage(
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
@ActionInput(name = "url", label = "@text/sendMessageActionInputURLLabel", description = "@text/sendMessageActionInputURLDescription", type = "java.lang.String", required = true) String url,
@ActionInput(name = "url", label = "@text/sendMessageActionInputURLLabel", description = "@text/sendMessageActionInputURLDescription", type = "java.lang.String", required = true) @Nullable String url,
@ActionInput(name = "urlTitle", label = "@text/sendMessageActionInputURLTitleLabel", description = "@text/sendMessageActionInputURLTitleDescription", type = "java.lang.String") @Nullable String urlTitle) {
logger.trace(
"ThingAction 'sendURLMessage' called with value(s): message='{}', url='{}', title='{}', urlTitle='{}'",
Expand Down Expand Up @@ -157,7 +192,7 @@ public static Boolean sendMonospaceMessage(ThingActions actions, String message,
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendAttachmentMessage(
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
@ActionInput(name = "attachment", label = "@text/sendMessageActionInputAttachmentLabel", description = "@text/sendMessageActionInputAttachmentDescription", type = "java.lang.String", required = true) String attachment,
@ActionInput(name = "attachment", label = "@text/sendMessageActionInputAttachmentLabel", description = "@text/sendMessageActionInputAttachmentDescription", type = "java.lang.String", required = true) @Nullable String attachment,
@ActionInput(name = "contentType", label = "@text/sendMessageActionInputContentTypeLabel", description = "@text/sendMessageActionInputContentTypeDescription", type = "java.lang.String", defaultValue = DEFAULT_CONTENT_TYPE) @Nullable String contentType) {
logger.trace(
"ThingAction 'sendAttachmentMessage' called with value(s): message='{}', title='{}', attachment='{}', contentType='{}'",
Expand Down Expand Up @@ -201,10 +236,10 @@ public static String sendPriorityMessage(ThingActions actions, String message, @

@RuleAction(label = "@text/cancelPriorityMessageActionLabel", description = "@text/cancelPriorityMessageActionDescription")
public @ActionOutput(name = "canceled", label = "@text/cancelPriorityMessageActionOutputLabel", description = "@text/cancelPriorityMessageActionOutputDescription", type = "java.lang.Boolean") Boolean cancelPriorityMessage(
@ActionInput(name = "receipt", label = "@text/cancelPriorityMessageActionInputReceiptLabel", description = "@text/cancelPriorityMessageActionInputReceiptDescription", type = "java.lang.String", required = true) String receipt) {
@ActionInput(name = "receipt", label = "@text/cancelPriorityMessageActionInputReceiptLabel", description = "@text/cancelPriorityMessageActionInputReceiptDescription", type = "java.lang.String", required = true) @Nullable String receipt) {
logger.trace("ThingAction 'cancelPriorityMessage' called with value(s): '{}'", receipt);
if (accountHandler == null) {
throw new RuntimeException("PushoverAccountHandler is null!");
throw new IllegalStateException("PushoverAccountHandler is null!");
}

if (receipt == null) {
Expand All @@ -220,7 +255,7 @@ public static Boolean cancelPriorityMessage(ThingActions actions, String receipt

@RuleAction(label = "@text/sendMessageToDeviceActionLabel", description = "@text/sendMessageToDeviceActionDescription")
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMessageToDevice(
@ActionInput(name = "device", label = "@text/sendMessageActionInputDeviceLabel", description = "@text/sendMessageActionInputDeviceDescription", type = "java.lang.String", required = true) String device,
@ActionInput(name = "device", label = "@text/sendMessageActionInputDeviceLabel", description = "@text/sendMessageActionInputDeviceDescription", type = "java.lang.String", required = true) @Nullable String device,
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
logger.trace("ThingAction 'sendMessageToDevice' called with value(s): device='{}', message='{}', title='{}'",
Expand All @@ -237,9 +272,9 @@ public static Boolean sendMessageToDevice(ThingActions actions, String device, S
return ((PushoverActions) actions).sendMessageToDevice(device, message, title);
}

private PushoverMessageBuilder getDefaultPushoverMessageBuilder(String message) {
private PushoverMessageBuilder getDefaultPushoverMessageBuilder(@Nullable String message) {
if (accountHandler == null) {
throw new RuntimeException("PushoverAccountHandler is null!");
throw new IllegalStateException("PushoverAccountHandler is null!");
}

if (message == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class PushoverMessageBuilder {
private static final String MESSAGE_KEY_PRIORITY = "priority";
private static final String MESSAGE_KEY_RETRY = "retry";
private static final String MESSAGE_KEY_EXPIRE = "expire";
private static final String MESSAGE_KEY_TTL = "ttl";
private static final String MESSAGE_KEY_URL = "url";
private static final String MESSAGE_KEY_URL_TITLE = "url_title";
private static final String MESSAGE_KEY_SOUND = "sound";
Expand All @@ -67,6 +68,7 @@ public class PushoverMessageBuilder {
public static final int EMERGENCY_PRIORITY = 2;
private static final int MIN_RETRY_SECONDS = 30;
private static final int MAX_EXPIRE_SECONDS = 10800;
private static final int DEFAULT_TTL = 0;
private static final int MAX_URL_LENGTH = 512;
private static final int MAX_URL_TITLE_LENGTH = 100;
public static final String DEFAULT_CONTENT_TYPE = "image/jpeg";
Expand All @@ -79,6 +81,7 @@ public class PushoverMessageBuilder {
private int priority = DEFAULT_PRIORITY;
private int retry = 300;
private int expire = 3600;
private int ttl = DEFAULT_TTL;
private @Nullable String url;
private @Nullable String urlTitle;
private @Nullable String sound;
Expand Down Expand Up @@ -135,6 +138,11 @@ public PushoverMessageBuilder withExpire(int expire) {
return this;
}

public PushoverMessageBuilder withTTL(int ttl) {
this.ttl = ttl;
return this;
}

public PushoverMessageBuilder withUrl(String url) {
this.url = url;
return this;
Expand Down Expand Up @@ -171,6 +179,7 @@ public PushoverMessageBuilder withMonospaceFormatting() {
}

public ContentProvider build() throws CommunicationException {
String message = this.message;
if (message != null) {
if (message.length() > MAX_MESSAGE_LENGTH) {
throw new IllegalArgumentException(String.format(
Expand All @@ -179,6 +188,7 @@ public ContentProvider build() throws CommunicationException {
body.addFieldPart(MESSAGE_KEY_MESSAGE, new StringContentProvider(message), null);
}

String title = this.title;
if (title != null) {
if (title.length() > MAX_TITLE_LENGTH) {
throw new IllegalArgumentException(String
Expand All @@ -187,6 +197,7 @@ public ContentProvider build() throws CommunicationException {
body.addFieldPart(MESSAGE_KEY_TITLE, new StringContentProvider(title), null);
}

String device = this.device;
if (device != null) {
if (device.length() > MAX_DEVICE_LENGTH) {
logger.warn("Skip 'device' as it is longer than {} characters. Got: {}.", MAX_DEVICE_LENGTH, device);
Expand Down Expand Up @@ -224,13 +235,22 @@ public ContentProvider build() throws CommunicationException {
}
}

if (ttl != DEFAULT_TTL) {
if (priority == EMERGENCY_PRIORITY) {
logger.warn("TTL value of {} ignored for emergency priority.", ttl);
}
body.addFieldPart(MESSAGE_KEY_TTL, new StringContentProvider(String.valueOf(ttl)), null);
}

String url = this.url;
if (url != null) {
if (url.length() > MAX_URL_LENGTH) {
throw new IllegalArgumentException(String
.format("Skip sending the message as 'url' is longer than %d characters.", MAX_URL_LENGTH));
}
body.addFieldPart(MESSAGE_KEY_URL, new StringContentProvider(url), null);

String urlTitle = this.urlTitle;
if (urlTitle != null) {
if (urlTitle.length() > MAX_URL_TITLE_LENGTH) {
throw new IllegalArgumentException(
Expand All @@ -245,19 +265,19 @@ public ContentProvider build() throws CommunicationException {
body.addFieldPart(MESSAGE_KEY_SOUND, new StringContentProvider(sound), null);
}

String attachment = this.attachment;
if (attachment != null) {
String localAttachment = attachment;
if (localAttachment.startsWith("http")) { // support data HTTP(S) scheme
if (attachment.startsWith("http")) { // support data HTTP(S) scheme
RawType rawImage = HttpUtil.downloadImage(attachment, 10000);
if (rawImage == null) {
throw new IllegalArgumentException(
String.format("Skip sending the message as content '%s' does not exist.", attachment));
}
addFilePart(createTempFile(rawImage.getBytes()),
contentType == null ? rawImage.getMimeType() : contentType);
} else if (localAttachment.startsWith("data:")) { // support data URI scheme
} else if (attachment.startsWith("data:")) { // support data URI scheme
try {
RawType rawImage = RawType.valueOf(localAttachment);
RawType rawImage = RawType.valueOf(attachment);
addFilePart(createTempFile(rawImage.getBytes()),
contentType == null ? rawImage.getMimeType() : contentType);
} catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public Collection<Class<? extends ThingHandlerService>> getServices() {
*/
public List<Sound> getSounds() {
try {
PushoverAPIConnection connection = this.connection;
if (connection != null) {
List<Sound> sounds = connection.getSounds();
if (sounds != null) {
Expand Down Expand Up @@ -145,6 +146,7 @@ public PushoverMessageBuilder getDefaultPushoverMessageBuilder(String message) {
}

public boolean sendMessage(PushoverMessageBuilder messageBuilder) {
PushoverAPIConnection connection = this.connection;
if (connection != null) {
try {
return connection.sendMessage(messageBuilder);
Expand All @@ -160,6 +162,7 @@ public boolean sendMessage(PushoverMessageBuilder messageBuilder) {
}

public String sendPriorityMessage(PushoverMessageBuilder messageBuilder) {
PushoverAPIConnection connection = this.connection;
if (connection != null) {
try {
return connection.sendPriorityMessage(messageBuilder);
Expand All @@ -175,6 +178,7 @@ public String sendPriorityMessage(PushoverMessageBuilder messageBuilder) {
}

public boolean cancelPriorityMessage(String receipt) {
PushoverAPIConnection connection = this.connection;
if (connection != null) {
try {
return connection.cancelPriorityMessage(receipt);
Expand Down
Loading

0 comments on commit 67e9b2e

Please sign in to comment.