From 40b0204508488266163b6f2dbb3cd3639bec1016 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Fri, 4 Dec 2020 15:34:19 +0000 Subject: [PATCH] Initial import --- .github/GitHub-Actions.org | 41 +++++++ .github/NOTES | 45 ++++++++ .github/codesigning.asc.gpg | Bin 0 -> 6493 bytes .github/deploy.sh | 43 +++++++ .github/settings.xml | 28 +++++ .github/workflows/maven-build.yml | 22 ++++ .github/workflows/sonatype-deploy.yml | 24 ++++ .gitignore | 32 ++++++ README.md | 7 ++ pom.xml | 79 +++++++++++++ .../java/net/kemitix/trello/Attachment.java | 28 +++++ .../kemitix/trello/AttachmentDirectory.java | 7 ++ .../trello/AttachmentDirectoryImpl.java | 51 +++++++++ .../kemitix/trello/CardWithAttachments.java | 40 +++++++ .../kemitix/trello/KemitixTrelloClient.java | 18 +++ .../java/net/kemitix/trello/ListUtils.java | 15 +++ .../java/net/kemitix/trello/LoadCard.java | 26 +++++ .../net/kemitix/trello/LocalAttachment.java | 38 ++++++ .../net/kemitix/trello/TrelloAttachment.java | 87 ++++++++++++++ .../java/net/kemitix/trello/TrelloBoard.java | 108 ++++++++++++++++++ .../java/net/kemitix/trello/TrelloCard.java | 43 +++++++ .../java/net/kemitix/trello/TrelloClient.java | 7 ++ .../java/net/kemitix/trello/TrelloConfig.java | 48 ++++++++ .../net/kemitix/trello/TrelloProducers.java | 38 ++++++ src/main/resources/META-INF/beans.xml | 0 25 files changed, 875 insertions(+) create mode 100644 .github/GitHub-Actions.org create mode 100644 .github/NOTES create mode 100644 .github/codesigning.asc.gpg create mode 100644 .github/deploy.sh create mode 100644 .github/settings.xml create mode 100644 .github/workflows/maven-build.yml create mode 100644 .github/workflows/sonatype-deploy.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/net/kemitix/trello/Attachment.java create mode 100644 src/main/java/net/kemitix/trello/AttachmentDirectory.java create mode 100644 src/main/java/net/kemitix/trello/AttachmentDirectoryImpl.java create mode 100644 src/main/java/net/kemitix/trello/CardWithAttachments.java create mode 100644 src/main/java/net/kemitix/trello/KemitixTrelloClient.java create mode 100644 src/main/java/net/kemitix/trello/ListUtils.java create mode 100644 src/main/java/net/kemitix/trello/LoadCard.java create mode 100644 src/main/java/net/kemitix/trello/LocalAttachment.java create mode 100644 src/main/java/net/kemitix/trello/TrelloAttachment.java create mode 100644 src/main/java/net/kemitix/trello/TrelloBoard.java create mode 100644 src/main/java/net/kemitix/trello/TrelloCard.java create mode 100644 src/main/java/net/kemitix/trello/TrelloClient.java create mode 100644 src/main/java/net/kemitix/trello/TrelloConfig.java create mode 100644 src/main/java/net/kemitix/trello/TrelloProducers.java create mode 100644 src/main/resources/META-INF/beans.xml diff --git a/.github/GitHub-Actions.org b/.github/GitHub-Actions.org new file mode 100644 index 0000000..1c882b8 --- /dev/null +++ b/.github/GitHub-Actions.org @@ -0,0 +1,41 @@ +* Deploying using Github Actions + +** Actions definition: workflow/sonatype-deploy.yml + +When a GitHub Release is created, usually from a tag, this action will trigger. + +Using JDK8 the software will be packaged, including running any tests. + +Then the Deploy script will sign the created artifacts then deploy them according to the distributionManagement configuration in the `pom.xml`. + +** Deploy Script + +Uses a signing key provided from the GitHub Actions Secrets as an environment variable to sign the artifact(s) before they are then deployed. + +*** Inputs + +**** DEPLOY_PROJECTS (optional) + +An optional list of modules in a multi-module project to be deployed. If this value is not specified, then all projects will be deployed. + +** Maven Configuration + +Picks up the credentials from Environment variables for authenticating both with GPG and with the target deployment server (e.g. sonatype-nexus). + +*** Inputs + +**** NEXUS_USERNAME + +The username for your account on the deployment server. + +**** NEXUS_PASSWORD + +The password for your account on the deployement server. + +**** GPG_KEYNAME + +The key to use when signing. + +**** GPG_PASSPHRASE + +The passphrase to unlock the key to use when signing. diff --git a/.github/NOTES b/.github/NOTES new file mode 100644 index 0000000..7b0565b --- /dev/null +++ b/.github/NOTES @@ -0,0 +1,45 @@ +Add subkeys: + +???? + +Backup: + +gpg --export --armor pcampbell@kemitix.net > gpg-key-backup.asc +gpg --export-secret-keys --armor pcampbell@kemitix.net >> gpg-key-backup.asc + +Export sub-keys: + +gpg --export-secret-subkeys pcampbell@kemitix.net > subkeys + +Remove master keys: + +gpg --delete-secret-key pcampbell@kemitix.net + +Import sub-keys and clean up: + +gpg --import subkeys + +shred --remove subkeys + +Delete any encryption subkeys: + +gpg --edit-key pcampbell@kemitix.net + +2 +delkey +save + +Change passphrase: + +gpg --edit-key pcampbell@kemitix.net +passwd +save + +Export keys: + +gpg --export --armor pcampbell@kemitix.net > codesigning.asc +gpg --export-secret-keys --armor pcampbell@kemitix.net >> codesigning.asc + +Encrypt keys: + +gpg --symmetric --cipher-algo AES256 codesigning.asc diff --git a/.github/codesigning.asc.gpg b/.github/codesigning.asc.gpg new file mode 100644 index 0000000000000000000000000000000000000000..6327d4396aacf1c0c8faa4508cd6fde443e51d8f GIT binary patch literal 6493 zcmV-j8KUNl4Fm}T0?+T&q}KYbg8$O&0b%EdXR6H#Yur2FF^E=umOgDR$Av5g{_*aC|DTg z+Q?B4>j@X%7zucRkAUXl5wjKHH6H*P=|^Z~zVL>k;il(gW?BS+ZEg{oLB3ENJw-2v zrSbw5muVCy11lmTk{s#8Fu*=IhPofie&@C}oja~#8zFxoQu)f5K+IH8KiiE5rb?$T-u5ED$&li;G)yXXs$PfkEvN%neo&rNMPp{N#202vo&~g@HR*R3_vS1`U+%5T*{=5qJXIDC?vd^T|bmWK1E0ryNL!XaH`Nn zLg%&Zhebk^&L>&b_LuQECwM>uE+L&P+MFg#%C- z)M5c7cU+ooE1Hxa9!texLhc1vd}5NH`tND?D(BL6Fe^D#vvOP%AIQjl2_ZGrsb@hX zOx>jKo}JB7UUyrJ=xye1l)x1NuP4q!8=Eq2`oZ@W1w}AffxK4`*9mdd8)hK|<_zKA zpoQQufW?q;&iZ1lJxEb8**Y^|;WxuAyF<8wtF*;N*L<=Q1Y1Xlq3j93CuHr zZ|a{i6>4dXXCL;OT(*_R@B#Ddk;90EbNlL^I;<5(bfS)=8fdP4rir?rXg-XnKEOgQfBTasrgLMF{xrI0Vf6%Jd41GS4hawCtL zGb}%6%cL)eWO4uP4=+}YCA!nF?cE6zr&LblIPxAN9yZZTCj2VQ{b0FLNm^|7S!}ax z-DVW^4tQzLsVCEAg|J;d!YpM3U!D|!xtABvLI+6j%-(hEh=(*>CbC|37r>`Vd$y3X zAo>3?yWC6;vV*p0kl~4Y0DaowuxDv7yb!JR6+N(2rpZZRp|tPW)O<{y)6N7(btBDK zYXjFMG+Mno-tKLal19n>TE#^PKKQ-NjdXIj8$XM+>?!-$MpKv%OwNlNd@-e*Md zU4l01+wHi2eonvPx39c_~2b3izUs0>(@^uSlKVAwIlgfOBDd+|t- z)|2$e^R0>&E~aS# znJvzoz!4&#OshVFobj?r=ytdNQ~i|!HD zRmR2S>zK~k6Kseal>LAxJO}*YXl31de918(ROrY4t`&qj=OvH*+7Ed|_k^JFd}ukL zOfvM{+5|Yo&GYVVLL#yNELOdL#h#lFefTyQ_d@2|)=s>Aayz7}RD7yT5NRYg0MS{O0(PBive&n816>)WVU_)UdU%_>6LWZ zc=Khl>Plb=cJ$*F6NF?==2o)KT)wRtz`EXEh2MK44E6UvI{;+(j?It$QN_J{L z53+OVs3bBv`tJjH;E6uMoogiZEfSY&97iopjo2U<=OB_PdL+mwFd!&?jp-XBGeM8E z`_=lF4Oo-juMo-+LYol?hz~ja%pFef^{}NTfYy=U!KSzO7ZERUoG?fk2&tZF++V7J zOc|zzeG>`w0=@@6b3Kr8h+*G)C)?m)Bk1>rmLWi1QW0E2#1U?z^@dbCkTM+$xw!e4 zy|YlpYbYitQdA>We7v0fd0<}-nmES{!yHb4rxWh%UpeA^`))N=+@FMSAukrxwo`)J zU7OiHMVFTd0LuVNS0m@V9I~OO1$FtY!ws_k;(duYshW4>`mx!;xycB!UGrSE6w`Ke4WX zN7=MT6_E2<^X(gRR}YBx@UC#lS2CBFQg*=?_OFGJ8Um3?QK@&UZ6x1g(F4eHFxM3% z$K0Y}$Uy&_;wmF+r3*g(7WZ{9VLyq!c{KVJUH7C04>W+<*92sy#EIo$E&i}670MU1 zt$b?X?srD6w?7?(T?ugP*wI5I<^}?FF3I5|`o4m~* zlQ0Ef5>Rz~CY8(qDiQ}oZmVI=VS~S)ru67VYyyBguUj{ZAK24=?YYvh>swQ^$`b^pXHOB62Rm^~LY9Mi_d|PTS5mpyuh$YqFUFNdtLlxgvWXQt-cMpV^*vB~%SFg3o6?fQB=y3>Th@(~yPRwfGJk+G9 zo79B43&+n=l7DCq@Ib4RRy)aC8RBH|!nqGe?YpV=Sn@!sM_aRx-K(v=tU*wC~4ol+b=y!6&F@CRyOK4Bs^PX#_ zNH6R0arFezFMpD}XQ0es>dDtW5i?vZRqboC-cR_{ZF|4_KI^W2C7!e z@lBX7-O2=6_uS0XL83_UVt8zPl;R)wtAVQfTyWoWcsgt}#Ioa&0L}VJ4#?6R3`-}; zoYSDUYfqQt_3l)2^1Nj${iH>L`N715N4hVqqSB|re6GW38#iTg?wXLYZ$oqo!q=PqR<_vniYZg4+P zE#&DmxhnFt&6dVxzyFMlh)@E%IVdlHx%>9yNA`GdqAmZnqmr3K$QzahW!3ZxU0g+3 z>?II-Vclnc)E|YnT57*Ga%c@Brg?wjX}{eQvjF7DC5o^f=^vMRwz#l-c_6z zJGZZ&15J8N94JovxE+L6=sCHXqyh}x{x29eTk>&tIP|7y-yh}!<0%((5G<$((|7Ga*96QZy%6EL3}{M3Pv#@dL>5dDUS zBI4y(Q7-1S+5sE(K9uoW_(Y*DaYO78Y6OQN}8_XGRS0`Pl_gaXb zws#cl7v(85aVtf+18+4QwF5e)xLvhe$)@TrR60ij4F4zH%J_N^3Ijd1+j4>+56OGN z^;va8xfS{z%vzA8>-G+{vWUL2SN#S(V3LDXZyK?cQwik(IrU42iETM6t_TUu0YDcx$L51P6)U2w6iUpdP#7ZYXi@3>;cO{CzWHUpGoL2optXObnHGgr|;qwdi>4A*nDYTeE$3va0eT@ug0r-G9 z*8;3PRd^9~T1f{VPb~zozPi>rI49X{F+N3z$IXC>k&5E){ch=jwUeIFd9J&d>itVH z6Q&7VhUO7L4Z>4cXH98DjAF0#V9*}n(Gm~Hzqt8lde(FZ?b8LkpIG)#pp;k6(>Z)@ zpERRr{W3tQ^-53qs?Fbf6>693uJ6e{(xKBT-hIMfZE|a`W`BWMrd_;>8RovrA4~NX zWfHt=K%p2tRcw1Z$w3e|1$a&@TUG}E`QRk)mOSz8%=^w*mQSqnj71F|QT?#&EemSR zUrN)VEI!K2#(8bS&rl*3$|8U%%EB^8!+v%$Y^Lh94oT<-@4c@SRA&`tRbcYTt~E-T z);g_mk>T$leaq6EOnBw0-Y$QHjbR#vMCi-wQXhFJ)b-CABkLD$?KLrS^JNGz%Ua}k zyV?%yK+aZ$KX1&CsCxWFh9Q~qHrwft5$ z$AJe+PHs%s+VHULVf719EK52Yf6!B+lwIoAN_*$Y8xP3#5Wgi0BWDiQP*I8D9cwt- zzNqUiH(Sjp?%rs$L%m+J6Qe>9lfEf>UX5JrJ|Ie^;K_}sj{d#?y&?TIz<=He`dy-Mu($74r+l zDYE&VTu;Ilb@!r`6-bF$&Ij*nz%H#+OrO!B9I7mZxtkL*_lVh9N1DGLZN9$SQwER4 zt88N}aOfKwoDaKb3SpRi<Gc#W@LezoFvY?SyS`*RcRMP?Tc_R}D0VDsn zvcZx{WiBE^zVOciW*2p3Iwh(f#FU+~yCmkZ`};rM`Ehc9JroA9Kt04Wca<=xc!8q5 zT@#L1rJDXc{#tTwxeaWR6@OV8uQc#2icHtJ{UOm46*t-Kw4`)>*wP%uoDqn=i`;gHNJ`#&ukuRK~o7~l7WUpWCEQ~ zpz{GL6;k*?pUH&0F=(jtz2*K7c+tM5-lmhFI0A2%hpTJI*=P)ezjaGwZbx1u*ByM` zqX%B+MHMd{Zg{nN?oAv(G9IHIYvc_!+m278*F5jJcyX6(RaW-!Pmq?vGd>N9p29(N zEmE>O?(mz!ZD8WR5@)ZnX3el*)NY3W%1MSm+JvdlG#_*B=axmS#WdRJR zIM#6h4X@qyC};1=bM_B-N$4gDVk4Jgm;U#?{n?;1S{K@`)D<{uXFdvqJYe0rDmmf~ z0Q4}=$QB5NGzz77=_5ZR&%E>@%7(84hQ0eq#Ryj-Y*vz0!fA~ zk>*sbjF(o?xeF5ron#1xi*@w3xhYoOg*B9xCdP!~PlOnMZ7>-bOg6l2a*m@A)kqjD z2SZ^{M7N#Lk^GBu$Jwf+o)`nH{*f?2QzC+1!iMU!Go#r|KkDr2(#WBm7XE==0N zO%lB8hMUU()XM&wIGfGum9kqOTQ?#X=(H&}EQvBfj#zt{|B8XFND8 + + + + sonatype-nexus-snapshots + ${env.NEXUS_USERNAME} + ${env.NEXUS_PASSWORD} + + + sonatype-nexus-staging + ${env.NEXUS_USERNAME} + ${env.NEXUS_PASSWORD} + + + + + gpg-sign + + true + + + gpg + ${env.GPG_KEYNAME} + ${env.GPG_PASSPHRASE} + + + + diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml new file mode 100644 index 0000000..1b38e65 --- /dev/null +++ b/.github/workflows/maven-build.yml @@ -0,0 +1,22 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: '*' + pull_request: + branches: '*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/.github/workflows/sonatype-deploy.yml b/.github/workflows/sonatype-deploy.yml new file mode 100644 index 0000000..3068ff8 --- /dev/null +++ b/.github/workflows/sonatype-deploy.yml @@ -0,0 +1,24 @@ +name: Deploy to Sonatype Nexus + +on: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn -B package + - name: Nexus Repo Publish + run: sh .github/deploy.sh + env: + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + GPG_KEYNAME: ${{ secrets.GPG_KEYNAME }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67803cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +pom.xml.versionsBackup +nohup.out +.install +target/ + +# Jetbrains +*.iml +.idea/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffb877d --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Kemitix Trello + +Wrapper for Trello. + +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. diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..31a7c95 --- /dev/null +++ b/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + + net.kemitix + kemitix-parent + 5.3.0 + + + + kemitix-trello + 1.0.0 + + + 2.18 + 2.10.0 + + 0.14 + 1.18.16 + 3.6.0 + + + + + org.projectlombok + lombok + ${lombok.version} + true + + + com.taskadapter + trello-java-wrapper + ${trello-java-wrapper.version} + + + javax.inject + javax.inject + 1 + + + javax.annotation + javax.annotation-api + 1.3.2 + + + org.apache.camel + camel-api + ${camel-api.version} + + + jakarta.enterprise + jakarta.enterprise.cdi-api + 2.0.2 + compile + + + + + + + + io.repaint.maven + tiles-maven-plugin + ${tiles-maven-plugin.version} + true + + + net.kemitix.tiles:maven-plugins:${kemitix-tiles.version} + net.kemitix.tiles:compiler-jdk-lts:${kemitix-tiles.version} + + + + + + + \ No newline at end of file diff --git a/src/main/java/net/kemitix/trello/Attachment.java b/src/main/java/net/kemitix/trello/Attachment.java new file mode 100644 index 0000000..469c3f1 --- /dev/null +++ b/src/main/java/net/kemitix/trello/Attachment.java @@ -0,0 +1,28 @@ +package net.kemitix.trello; + +import java.io.File; + +public interface Attachment { + + /** + * The name of the attachment file. + * + * @return the name of the file + */ + File getFilename(); + + /** + * Downlaods the file to local file system. + * + * @return the name of the local file. + */ + LocalAttachment download(); + + /** + * The original filename. + * + * @return the name of the file originally + */ + File getOriginalFilename(); + +} diff --git a/src/main/java/net/kemitix/trello/AttachmentDirectory.java b/src/main/java/net/kemitix/trello/AttachmentDirectory.java new file mode 100644 index 0000000..84ca159 --- /dev/null +++ b/src/main/java/net/kemitix/trello/AttachmentDirectory.java @@ -0,0 +1,7 @@ +package net.kemitix.trello; + +import java.io.File; + +public interface AttachmentDirectory { + File createFile(File fileName); +} diff --git a/src/main/java/net/kemitix/trello/AttachmentDirectoryImpl.java b/src/main/java/net/kemitix/trello/AttachmentDirectoryImpl.java new file mode 100644 index 0000000..aefe73b --- /dev/null +++ b/src/main/java/net/kemitix/trello/AttachmentDirectoryImpl.java @@ -0,0 +1,51 @@ +package net.kemitix.trello; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +@ApplicationScoped +public class AttachmentDirectoryImpl implements AttachmentDirectory { + + private static final Logger LOG = + Logger.getLogger( + AttachmentDirectoryImpl.class.getName()); + + private Path dir; + private List toDelete = new ArrayList<>(); + + @PostConstruct + void init() throws IOException { + dir = Files.createTempDirectory("attachments"); + LOG.info("Attachments directory: " + dir); + } + + @Override + public File createFile(File fileName) { + File file = dir.resolve(fileName.getName()).toFile(); + LOG.info("Created attachment: " + file); + toDelete.add(file); + return file; + } + + @PreDestroy + public void deleteFiles() { + toDelete.stream() + .peek(file -> LOG.info("Deleting: " + file)) + .map(File::delete) + .filter(deleted -> !deleted) + .forEach(r -> LOG.warning("Could not delete file")); + if (dir.toFile().delete()) { + LOG.info("Deleted directory: " + dir); + } else { + LOG.warning("Could not delete directory: " + dir); + } + } +} diff --git a/src/main/java/net/kemitix/trello/CardWithAttachments.java b/src/main/java/net/kemitix/trello/CardWithAttachments.java new file mode 100644 index 0000000..891a8f6 --- /dev/null +++ b/src/main/java/net/kemitix/trello/CardWithAttachments.java @@ -0,0 +1,40 @@ +package net.kemitix.trello; + +import com.julienvey.trello.Trello; +import com.julienvey.trello.domain.Card; + +import java.util.stream.Stream; + +public class CardWithAttachments { + private final com.julienvey.trello.domain.Card tcard; + private final Trello trello; + private AttachmentDirectory attachmentDir; + + private CardWithAttachments( + Card tcard, + Trello trello, + AttachmentDirectory attachmentDir + ) { + this.tcard = tcard; + this.trello = trello; + this.attachmentDir = attachmentDir; + } + + public static CardWithAttachments create( + Card tcard, + Trello trello, + AttachmentDirectory attachmentDir + ) { + return new CardWithAttachments(tcard, trello, attachmentDir); + } + + public Stream findAttachments() { + return trello.getCardAttachments(tcard.getId()).stream() + .map(attachment -> TrelloAttachment + .create(attachment, tcard, attachmentDir)); + } + + public String getName() { + return tcard.getName(); + } +} diff --git a/src/main/java/net/kemitix/trello/KemitixTrelloClient.java b/src/main/java/net/kemitix/trello/KemitixTrelloClient.java new file mode 100644 index 0000000..7146ace --- /dev/null +++ b/src/main/java/net/kemitix/trello/KemitixTrelloClient.java @@ -0,0 +1,18 @@ +package net.kemitix.trello; + +import com.julienvey.trello.TrelloHttpClient; +import com.julienvey.trello.impl.TrelloImpl; + +public class KemitixTrelloClient + extends TrelloImpl + implements TrelloClient { + + public KemitixTrelloClient( + String applicationKey, + String accessToken, + TrelloHttpClient httpClient + ) { + super(applicationKey, accessToken, httpClient); + } + +} diff --git a/src/main/java/net/kemitix/trello/ListUtils.java b/src/main/java/net/kemitix/trello/ListUtils.java new file mode 100644 index 0000000..193f65c --- /dev/null +++ b/src/main/java/net/kemitix/trello/ListUtils.java @@ -0,0 +1,15 @@ +package net.kemitix.trello; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ListUtils { + + public static List map(List a, Function f) { + return a.stream() + .map(f) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/net/kemitix/trello/LoadCard.java b/src/main/java/net/kemitix/trello/LoadCard.java new file mode 100644 index 0000000..e1c9171 --- /dev/null +++ b/src/main/java/net/kemitix/trello/LoadCard.java @@ -0,0 +1,26 @@ +package net.kemitix.trello; + +import org.apache.camel.Header; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.util.Objects; + +@ApplicationScoped +public class LoadCard { + + private final TrelloBoard trelloBoard; + + @Inject + public LoadCard(TrelloBoard trelloBoard) { + this.trelloBoard = trelloBoard; + } + + public TrelloCard loadCard(@Header("SlushyCardId") String cardId) { + return Objects.requireNonNull( + trelloBoard.getCard(cardId), + "Card Not Found" + ); + } + +} diff --git a/src/main/java/net/kemitix/trello/LocalAttachment.java b/src/main/java/net/kemitix/trello/LocalAttachment.java new file mode 100644 index 0000000..73b9259 --- /dev/null +++ b/src/main/java/net/kemitix/trello/LocalAttachment.java @@ -0,0 +1,38 @@ +package net.kemitix.trello; + +import lombok.Getter; + +import java.io.File; + +/** + * An attachment that has already been downloaded. + * + * Calling download, is a noop that returns the local file. + */ +@Getter +public class LocalAttachment + implements Attachment { + + private final File filename; + private final File originalFilename; + private final long length; + + public LocalAttachment( + File filename, + File originalFilename, + long length + ) { + this.filename = filename; + this.originalFilename = originalFilename; + this.length = length; + } + + boolean isZero() { + return length == 0; + } + + @Override + public LocalAttachment download() { + return this; + } +} diff --git a/src/main/java/net/kemitix/trello/TrelloAttachment.java b/src/main/java/net/kemitix/trello/TrelloAttachment.java new file mode 100644 index 0000000..1a2bfcd --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloAttachment.java @@ -0,0 +1,87 @@ +package net.kemitix.trello; + +import com.julienvey.trello.domain.Card; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.channels.Channels; +import java.util.logging.Logger; + +public class TrelloAttachment implements Attachment { + + private static final Logger LOG = + Logger.getLogger( + TrelloAttachment.class.getName()); + + private static final String[] EXTENSIONS = new String[]{"doc", "docx", "odt"}; + private final com.julienvey.trello.domain.Attachment attachment; + private final Card card; + private final AttachmentDirectory attachmentDirectory; + private final String id; + + private TrelloAttachment( + com.julienvey.trello.domain.Attachment attachment, + Card card, + AttachmentDirectory attachmentDirectory + ) { + this.attachment = attachment; + this.card = card; + this.attachmentDirectory = attachmentDirectory; + this.id = card.getIdShort(); + } + + public static Attachment create( + com.julienvey.trello.domain.Attachment attachment, + Card card, + AttachmentDirectory dir + ) { + return new TrelloAttachment(attachment, card, dir); + } + + @Override + public File getFilename() { + return new File(String.format("%4s - %s.%s", + id, card.getName(), extension())); + } + + private String extension() { + URI uri = URI.create(attachment.getUrl()); + String path = uri.getPath(); + for (String ex : EXTENSIONS) { + if (path.endsWith("." + ex)) { + return ex; + } + } + return ""; + } + + @Override + public LocalAttachment download() { + try (var source = Channels.newChannel(getUrl().openStream());){ + File filename = new File(attachment.getName()); + LOG.info("Downloading from " + filename); + var file = attachmentDirectory.createFile(getFilename()); + LOG.info("Downloading to " + file.getCanonicalPath()); + try (var channel = new FileOutputStream(file).getChannel()) { + long length = channel.transferFrom(source, 0, Long.MAX_VALUE); + LOG.info("Downloaded length: " + length); + return new LocalAttachment(file, filename, length); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public File getOriginalFilename() { + return getFilename(); + } + + private URL getUrl() throws MalformedURLException { + return URI.create(attachment.getUrl()).toURL(); + } +} diff --git a/src/main/java/net/kemitix/trello/TrelloBoard.java b/src/main/java/net/kemitix/trello/TrelloBoard.java new file mode 100644 index 0000000..497115b --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloBoard.java @@ -0,0 +1,108 @@ +package net.kemitix.trello; + +import com.julienvey.trello.NotFoundException; +import com.julienvey.trello.Trello; +import com.julienvey.trello.domain.*; +import com.julienvey.trello.domain.Attachment; +import lombok.extern.java.Log; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.kemitix.trello.ListUtils.map; + +@Log +@ApplicationScoped +public class TrelloBoard { + + private final Trello trello; + private final TrelloConfig trelloConfig; + + private List lists; + + @Inject + public TrelloBoard( + Trello trello, + TrelloConfig trelloConfig + ) { + this.trello = trello; + this.trelloConfig = trelloConfig; + } + + @PostConstruct + void init () { + lists = board().fetchLists(); + } + + private Board board() { + String userName = trelloConfig.getUserName(); + log.info("User: " + userName); + String boardName = trelloConfig.getBoardName(); + log.info("Loading Board: " + boardName); + return trello + .getMemberBoards(userName) + .stream() + .filter(board -> board.getName().equals(boardName)) + .findFirst() + .orElseThrow(() -> new NotFoundException("Board: " + boardName)); + } + + private TList getList(String listName) { + return lists + .stream() + .filter(list -> list.getName().equals(listName)) + .findAny() + .orElseThrow(() -> new NotFoundException("List: " + listName)); + } + + + public void updateCard(TrelloCard card) { + trello.updateCard(card); + } + + public List getListCards(String listName) { + return trello.getListCards(getListId(listName)).stream() + .map(card -> TrelloCard.from(card, trello)) + .collect(Collectors.toList()); + } + + public List getAttachments(Card card) { + return trello.getCardAttachments(card.getId()); + } + + public TrelloCard addMemberToCard(TrelloCard card, Member member) { + var members = trello.addMemberToCard(card.getId(), member.getId()); + card.setIdMembers(map(members, Member::getId)); + trello.updateCard(card); + return card; + } + + public TrelloCard removeMemberFromCard(TrelloCard card, Member member) { + var members = trello.removeMemberFromCard(card.getId(), member.getId()); + card.setIdMembers(map(members, Member::getId)); + trello.updateCard(card); + return card; + } + + public String getListId(String listName) { + return getList(listName).getId(); + } + + public String getBoardId() { + return board().getId(); + } + + public Stream getListNames() { + return lists.stream() + .map(TList::getName); + } + + public TrelloCard getCard(String cardId) { + Card card = trello.getCard(cardId); + return TrelloCard.from(card, trello); + } +} diff --git a/src/main/java/net/kemitix/trello/TrelloCard.java b/src/main/java/net/kemitix/trello/TrelloCard.java new file mode 100644 index 0000000..3a0ccff --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloCard.java @@ -0,0 +1,43 @@ +package net.kemitix.trello; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.julienvey.trello.Trello; +import com.julienvey.trello.domain.Card; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@JsonIgnoreProperties(ignoreUnknown = true) +public class TrelloCard extends Card { + + private boolean dueComplete; + + public static TrelloCard from(Card card, Trello trello) { + TrelloCard s = new TrelloCard(); + s.setInternalTrello(trello); + s.setId(card.getId()); + s.setName(card.getName()); + s.setIdList(card.getIdList()); + s.setDesc(card.getDesc()); + s.setUrl(card.getUrl()); + s.setDue(card.getDue()); + s.setIdMembers(card.getIdMembers()); + s.setLabels(card.getLabels()); + s.setBadges(card.getBadges()); + s.setCheckItemStates(card.getCheckItemStates()); + s.setClosed(card.isClosed()); + s.setDateLastActivity(card.getDateLastActivity()); + s.setIdBoard(card.getIdBoard()); + s.setIdChecklists(card.getIdChecklists()); + s.setIdMembersVoted(card.getIdMembersVoted()); + s.setIdShort(card.getIdShort()); + s.setIdAttachmentCover(card.getIdAttachmentCover()); + s.setManualCoverAttachment(card.isManualCoverAttachment()); + s.setPos(card.getPos()); + s.setShortLink(card.getShortLink()); + s.setShortUrl(card.getShortUrl()); + s.setSubscribed(card.isSubscribed()); + return s; + } +} diff --git a/src/main/java/net/kemitix/trello/TrelloClient.java b/src/main/java/net/kemitix/trello/TrelloClient.java new file mode 100644 index 0000000..24d5d7a --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloClient.java @@ -0,0 +1,7 @@ +package net.kemitix.trello; + +import com.julienvey.trello.Trello; + +public interface TrelloClient + extends Trello { +} diff --git a/src/main/java/net/kemitix/trello/TrelloConfig.java b/src/main/java/net/kemitix/trello/TrelloConfig.java new file mode 100644 index 0000000..1699df6 --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloConfig.java @@ -0,0 +1,48 @@ +package net.kemitix.trello; + +public interface TrelloConfig { + + /** + * The Trello Developer API Key. + * + *

https://trello.com/app-key

+ */ + String getTrelloKey(); + + /** + * The Trello Developer API Key Token. + * + *

https://trello.com/app-key

+ */ + String getTrelloSecret(); + + /** + * The name of the user with access to the Trello Slush Pile Board. + */ + String getUserName(); + + /** + * The trello board containing the Slush Pile. + */ + String getBoardName(); + + /** + * The email address to send submission attachments to. + * + *

e.g. the kindle address

+ */ + String getSender(); + + /** + * The email address to send emails from. + * + *

If sending to Kindle, then ensure this address is listed as a valid sender.

+ */ + String getReader(); + + /** + * The URL of the Webhook to register with services. + */ + String getWebhook(); + +} diff --git a/src/main/java/net/kemitix/trello/TrelloProducers.java b/src/main/java/net/kemitix/trello/TrelloProducers.java new file mode 100644 index 0000000..a4435ec --- /dev/null +++ b/src/main/java/net/kemitix/trello/TrelloProducers.java @@ -0,0 +1,38 @@ +package net.kemitix.trello; + +import com.julienvey.trello.Trello; +import com.julienvey.trello.TrelloHttpClient; +import com.julienvey.trello.domain.Member; +import com.julienvey.trello.impl.http.JDKTrelloHttpClient; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; + +@ApplicationScoped +public class TrelloProducers { + + @Produces + @ApplicationScoped + TrelloHttpClient trelloHttpClient() { + return new JDKTrelloHttpClient(); + } + + @Produces + @ApplicationScoped + TrelloClient trello( + TrelloConfig config, + TrelloHttpClient httpClient + ) { + return new KemitixTrelloClient( + config.getTrelloKey(), + config.getTrelloSecret(), + httpClient); + } + + @Produces + @ApplicationScoped + Member member(Trello trello, TrelloConfig trelloConfig) { + return trello.getMemberInformation(trelloConfig.getUserName()); + } + +} diff --git a/src/main/resources/META-INF/beans.xml b/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..e69de29