Attachment: add support for authenticated downloads of attachments (#12)

This commit is contained in:
Paul Campbell 2021-08-12 23:04:46 +01:00 committed by GitHub
parent c9f904f83f
commit 8dab6e2c08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 6 deletions

View file

@ -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. 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+ 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.

View file

@ -12,7 +12,7 @@
</parent> </parent>
<artifactId>kemitix-trello</artifactId> <artifactId>kemitix-trello</artifactId>
<version>1.0.3</version> <version>1.1.0</version>
<properties> <properties>
<tiles-maven-plugin.version>2.18</tiles-maven-plugin.version> <tiles-maven-plugin.version>2.18</tiles-maven-plugin.version>

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -25,4 +25,13 @@ public interface Attachment {
*/ */
File getOriginalFilename(); 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);
} }

View file

@ -35,4 +35,9 @@ public class LocalAttachment
public LocalAttachment download() { public LocalAttachment download() {
return this; return this;
} }
@Override
public Attachment withApiKeyPair(ApiKeyPair apiKeyPair) {
return this;
}
} }

View file

@ -5,12 +5,13 @@ import com.julienvey.trello.domain.Card;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.net.URLEncoder; import java.net.URLConnection;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.charset.StandardCharsets;
import java.text.Normalizer; import java.text.Normalizer;
import java.util.Optional; import java.util.Optional;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -25,16 +26,19 @@ public class TrelloAttachment implements Attachment {
private final Card card; private final Card card;
private final AttachmentDirectory attachmentDirectory; private final AttachmentDirectory attachmentDirectory;
private final String id; private final String id;
private final ApiKeyPair apiKeyPair;
private TrelloAttachment( private TrelloAttachment(
com.julienvey.trello.domain.Attachment attachment, com.julienvey.trello.domain.Attachment attachment,
Card card, Card card,
AttachmentDirectory attachmentDirectory AttachmentDirectory attachmentDirectory,
ApiKeyPair apiKeyPair
) { ) {
this.attachment = attachment; this.attachment = attachment;
this.card = card; this.card = card;
this.attachmentDirectory = attachmentDirectory; this.attachmentDirectory = attachmentDirectory;
this.id = card.getIdShort(); this.id = card.getIdShort();
this.apiKeyPair = apiKeyPair;
} }
public static Attachment create( public static Attachment create(
@ -42,7 +46,16 @@ public class TrelloAttachment implements Attachment {
Card card, Card card,
AttachmentDirectory dir 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 @Override
@ -67,7 +80,11 @@ public class TrelloAttachment implements Attachment {
@Override @Override
public LocalAttachment download() { 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()); File filename = new File(attachment.getName());
LOG.info("Downloading from " + filename); LOG.info("Downloading from " + filename);
var file = attachmentDirectory.createFile(getFilename()); 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 @Override
public File getOriginalFilename() { public File getOriginalFilename() {
return getFilename(); return getFilename();
} }
@Override
public Attachment withApiKeyPair(ApiKeyPair apiKeyPair) {
return create(attachment, card, attachmentDirectory, apiKeyPair);
}
private URL getUrl() throws MalformedURLException { private URL getUrl() throws MalformedURLException {
return URI.create(attachment.getUrl()).toURL(); return URI.create(attachment.getUrl()).toURL();
} }