diff --git a/README.md b/README.md
index ff945c0..592d619 100644
--- a/README.md
+++ b/README.md
@@ -19,3 +19,11 @@ This wraps the `com.taskadapter:trello-java-wrapper` library.
It is intended for use on my `slushy` and `fuller` projects. It was originally developed as part of `slushy` and was extracted when preparing to start on `fuller` which would need some of the same functionality.
Requires JDK 11+
+
+## Downloading Attachments
+
+From 1.1.0 of `kemitix-trello` support is included for downloading attachments
+using the now required authorised methods. In order to do so the API key and
+token are needed to download the attachment. These are provided either when
+creating the new `TrelloAttachment` constructor, or by calling the method
+`withApiKeyPair(...)`, which will return a new instance.
diff --git a/pom.xml b/pom.xml
index e358980..03c762b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
kemitix-trello
- 1.0.3
+ 1.1.0
2.18
diff --git a/src/main/java/net/kemitix/trello/ApiKeyPair.java b/src/main/java/net/kemitix/trello/ApiKeyPair.java
new file mode 100644
index 0000000..27597fe
--- /dev/null
+++ b/src/main/java/net/kemitix/trello/ApiKeyPair.java
@@ -0,0 +1,16 @@
+package net.kemitix.trello;
+
+public interface ApiKeyPair {
+
+ String getKey();
+ String getToken();
+
+ static ApiKeyPair create(String key, String token) {
+ return new ApiKeyPairImpl(key, token);
+ }
+
+ static ApiKeyPair none() {
+ return ApiKeyPairImpl.NONE;
+ }
+
+}
diff --git a/src/main/java/net/kemitix/trello/ApiKeyPairImpl.java b/src/main/java/net/kemitix/trello/ApiKeyPairImpl.java
new file mode 100644
index 0000000..af1e2ed
--- /dev/null
+++ b/src/main/java/net/kemitix/trello/ApiKeyPairImpl.java
@@ -0,0 +1,16 @@
+package net.kemitix.trello;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor(access = AccessLevel.PROTECTED)
+public class ApiKeyPairImpl implements ApiKeyPair {
+
+ public static final ApiKeyPair NONE = new ApiKeyPairImpl("", "");
+
+ private final String key;
+ private final String token;
+
+}
diff --git a/src/main/java/net/kemitix/trello/Attachment.java b/src/main/java/net/kemitix/trello/Attachment.java
index 469c3f1..787055d 100644
--- a/src/main/java/net/kemitix/trello/Attachment.java
+++ b/src/main/java/net/kemitix/trello/Attachment.java
@@ -25,4 +25,13 @@ public interface Attachment {
*/
File getOriginalFilename();
+ /**
+ * Adds the API Key Pair to a {@link TrelloAttachment}, creating a new
+ * instance, but ignored otherwise.
+ *
+ * @param apiKeyPair the key pair to add
+ * @return a new TrelloAttachment instance or itself
+ */
+ Attachment withApiKeyPair(final ApiKeyPair apiKeyPair);
+
}
diff --git a/src/main/java/net/kemitix/trello/LocalAttachment.java b/src/main/java/net/kemitix/trello/LocalAttachment.java
index 73b9259..5a3677c 100644
--- a/src/main/java/net/kemitix/trello/LocalAttachment.java
+++ b/src/main/java/net/kemitix/trello/LocalAttachment.java
@@ -35,4 +35,9 @@ public class LocalAttachment
public LocalAttachment download() {
return this;
}
+
+ @Override
+ public Attachment withApiKeyPair(ApiKeyPair apiKeyPair) {
+ return this;
+ }
}
diff --git a/src/main/java/net/kemitix/trello/TrelloAttachment.java b/src/main/java/net/kemitix/trello/TrelloAttachment.java
index 96dab20..ee95d16 100644
--- a/src/main/java/net/kemitix/trello/TrelloAttachment.java
+++ b/src/main/java/net/kemitix/trello/TrelloAttachment.java
@@ -5,12 +5,13 @@ import com.julienvey.trello.domain.Card;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.net.Authenticator;
+import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
-import java.net.URLEncoder;
+import java.net.URLConnection;
import java.nio.channels.Channels;
-import java.nio.charset.StandardCharsets;
import java.text.Normalizer;
import java.util.Optional;
import java.util.logging.Logger;
@@ -25,16 +26,19 @@ public class TrelloAttachment implements Attachment {
private final Card card;
private final AttachmentDirectory attachmentDirectory;
private final String id;
+ private final ApiKeyPair apiKeyPair;
private TrelloAttachment(
com.julienvey.trello.domain.Attachment attachment,
Card card,
- AttachmentDirectory attachmentDirectory
+ AttachmentDirectory attachmentDirectory,
+ ApiKeyPair apiKeyPair
) {
this.attachment = attachment;
this.card = card;
this.attachmentDirectory = attachmentDirectory;
this.id = card.getIdShort();
+ this.apiKeyPair = apiKeyPair;
}
public static Attachment create(
@@ -42,7 +46,16 @@ public class TrelloAttachment implements Attachment {
Card card,
AttachmentDirectory dir
) {
- return new TrelloAttachment(attachment, card, dir);
+ return new TrelloAttachment(attachment, card, dir, ApiKeyPair.none());
+ }
+
+ public static Attachment create(
+ com.julienvey.trello.domain.Attachment attachment,
+ Card card,
+ AttachmentDirectory dir,
+ ApiKeyPair apiKeyPair
+ ) {
+ return new TrelloAttachment(attachment, card, dir, apiKeyPair);
}
@Override
@@ -67,7 +80,11 @@ public class TrelloAttachment implements Attachment {
@Override
public LocalAttachment download() {
- try (var source = Channels.newChannel(getUrl().openStream());){
+ if (apiKeyPair == ApiKeyPair.none()) {
+ throw new UnsupportedOperationException(
+ "Download not permitted without a valid API KeyPair");
+ }
+ try (var source = Channels.newChannel(getConnection().getInputStream());) {
File filename = new File(attachment.getName());
LOG.info("Downloading from " + filename);
var file = attachmentDirectory.createFile(getFilename());
@@ -82,11 +99,24 @@ public class TrelloAttachment implements Attachment {
}
}
+ private URLConnection getConnection() throws IOException {
+ var connection = (HttpURLConnection) getUrl().openConnection();
+ connection.setRequestProperty("Authorization", String.format(
+ "OAuth oauth_consumer_key=\"%s\", oauth_token=\"%s\"",
+ apiKeyPair.getKey(), apiKeyPair.getToken()));
+ return connection;
+ }
+
@Override
public File getOriginalFilename() {
return getFilename();
}
+ @Override
+ public Attachment withApiKeyPair(ApiKeyPair apiKeyPair) {
+ return create(attachment, card, attachmentDirectory, apiKeyPair);
+ }
+
private URL getUrl() throws MalformedURLException {
return URI.create(attachment.getUrl()).toURL();
}