diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8fc9830 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: CI + +on: + push: + branches: [ master, release ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Java + uses: actions/setup-java@v1 + with: + java-version: '11' + - name: Build with Maven + run: mvn -B package --file pom.xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a995d08 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: Release + +on: + create: + tags: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout Source ðŸ›Žï¸ + uses: actions/checkout@v2 + + - name: Set up Java + uses: actions/setup-java@v1 + with: + java-version: '11' + + - name: Build with Maven 🔧 + run: mvn -B package --file pom.xml + + - name: Copy artifacts + run: | + mkdir artifacts + cp target/*.jar artifacts/ + cp target/*.obr artifacts/ + rm artifacts/*-tests.jar + ls artifacts + + - name: Archive artifacts + uses: actions/upload-artifact@v2 + with: + path: artifacts + + - name: Get tag name + run: echo "TAG_NAME=$(echo ${GITHUB_REF#refs/*/} | tr / -)" >> $GITHUB_ENV + + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@3.7.1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: artifacts + CLEAN: false + TARGET_FOLDER: ${{ env.TAG_NAME }} + COMMIT_MESSAGE: Releasing tag/branch ${{ env.TAG_NAME }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d5a4371..0000000 --- a/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: java -jdk: - - openjdk11 -script: mvn package diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index d4d1d57..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,46 +0,0 @@ -library identifier: 'WorkflowLibsShared@master', retriever: modernSCM( - [$class: 'GitSCMSource', remote: 'https://git.balgroupit.com/CICD-DevOps/WorkflowLibsShared.git'] -) - -pipeline { - agent { - label 'common' - } - - options { - skipStagesAfterUnstable() - disableConcurrentBuilds() - buildDiscarder(logRotator(numToKeepStr: '28')) - timeout(time: 1, unit: 'HOURS') - } - - triggers { - // at least once a day - cron('H H(0-7) * * *') - // every sixty minutes - pollSCM('H/5 * * * *') - } - - stages { - stage("SCM Checkout") { - steps { - deleteDir() - checkout scm - } - } - - stage("Maven") { - steps { - mvn "clean verify" - } - } - - stage("Nexus Lifecycle") { - steps { - nexusPolicyEvaluation iqApplication: 'com.baloise.confluence.digital-signature', - iqScanPatterns: [[scanPattern: 'target/*.jar']], - iqStage: 'build' - } - } - } -} diff --git a/README.MD b/README.MD index adb6fa3..7d9107b 100644 --- a/README.MD +++ b/README.MD @@ -4,10 +4,39 @@ A macro for Atlassian Confluence -Install via [marketplace.atlassian.com](https://marketplace.atlassian.com/plugins/com.baloise.confluence.digital-signature) +## Description +Allows you to enter a contract into a confluence macro and to sign it as logged in user. +- content and signatures can not be modified once signed +- white list users who can sign +- report when and by whom the contract was signed +- easily send email to signers of the contract +- receive notifications, when your contract was signed -## Builds +## Installation & Usage +Install via [Atlassian Marketplace](https://marketplace.atlassian.com/plugins/com.baloise.confluence.digital-signature). + +A detailed description of the available configuration fields and usage is described in the [Wiki...](https://github.com/baloise/digital-signature/wiki/Signature-Macro-Usage) + +## Feature overview +### Insert / edit macro +![](./docs/img/contract_text.png) +![](./docs/img/edit.png) + +### Sign +![](./docs/img/sign.png) -### [release](https://github.com/baloise/digital-signature/tree/gh-pages/release) [![Build Status](https://travis-ci.org/baloise/digital-signature.svg?branch=release)](https://travis-ci.org/baloise/digital-signature/branches) +- Set signers, title notified users and layout of the contract +- One click approval. User management is done by Confluence. +- The signature remains valid only as long the title and body are the same as at the time of signature. + +### Markdown +![](./docs/img/markdown.png) + +### Mail notification +![](./docs/img/report_email_export.png) +![](./docs/img/send_mail.png.png) + +## Builds +[![CI Build State](https://github.com/baloise/digital-signature/workflows/CI/badge.svg)](https://github.com/baloise/digital-signature/actions?query=workflow%3A%22CI%22) -### [master](https://github.com/baloise/digital-signature/tree/gh-pages/master) [![Build Status](https://travis-ci.org/baloise/digital-signature.svg?branch=master)](https://travis-ci.org/baloise/digital-signature/branches) +[Build Artifacts](https://github.com/baloise/digital-signature/tree/gh-pages/release) diff --git a/README.RELEASE.MD b/README.RELEASE.MD index deb768c..30499a7 100644 --- a/README.RELEASE.MD +++ b/README.RELEASE.MD @@ -3,5 +3,5 @@ - `mvn clean package` - merge onto release branch - set tag -- push and wait for https://travis-ci.org/baloise/digital-signature/branches to succeed -- create a version in marketplace https://marketplace.atlassian.com/manage/plugins/com.baloise.confluence.digital-signature/versions and upload obr (from https://github.com/baloise/digital-signature/tree/gh-pages/release) +- push and wait for the [![ReleaseAction](https://github.com/baloise/digital-signature/workflows/Release/badge.svg)](https://github.com/baloise/digital-signature/actions?query=workflow%3A%22Release%22) to succeed +- create a version in the [atlssian marketplace](https://marketplace.atlassian.com/manage/plugins/com.baloise.confluence.digital-signature/versions) and upload obr from [GitHub Pages](https://github.com/baloise/digital-signature/tree/gh-pages/release). diff --git a/docs/img/contract_text.png b/docs/img/contract_text.png new file mode 100644 index 0000000..1462c1a Binary files /dev/null and b/docs/img/contract_text.png differ diff --git a/docs/img/edit.png b/docs/img/edit.png new file mode 100644 index 0000000..1462c1a Binary files /dev/null and b/docs/img/edit.png differ diff --git a/docs/img/markdown.png b/docs/img/markdown.png new file mode 100644 index 0000000..9236264 Binary files /dev/null and b/docs/img/markdown.png differ diff --git a/docs/img/report_email_export.png b/docs/img/report_email_export.png new file mode 100644 index 0000000..6cf1f1c Binary files /dev/null and b/docs/img/report_email_export.png differ diff --git a/docs/img/send_mail.png b/docs/img/send_mail.png new file mode 100644 index 0000000..6cf1f1c Binary files /dev/null and b/docs/img/send_mail.png differ diff --git a/docs/img/sign.png b/docs/img/sign.png new file mode 100644 index 0000000..325a173 Binary files /dev/null and b/docs/img/sign.png differ diff --git a/pom.xml b/pom.xml index f50f4ca..4b04048 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 com.baloise.confluence digital-signature - 7.0.2 + 7.0.3 Baloise http://www.baloise.ch/ @@ -102,10 +102,10 @@ 2.2.2-atlassian-1 - org.mockito - mockito-all - 1.9.0 - test + org.mockito + mockito-all + 1.9.0 + test @@ -220,47 +220,4 @@ https://packages.atlassian.com/mvn/maven-external/ - - - - travis - - - env.TRAVIS - true - - - - - - com.github.github - site-maven-plugin - 0.12 - - true - baloise - ${project.artifactId} - Releasing ${project.version} - ${env.TRAVIS_BRANCH} - - ${project.build.finalName}.jar - ${project.build.finalName}.obr - - target - ${env.github_oauth2Token} - - - - - site - - package - - - - - - - - diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index 953ee4a..f203076 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -1,5 +1,31 @@ package com.baloise.confluence.digitalsignature; +import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; +import static com.atlassian.confluence.security.ContentPermission.EDIT_PERMISSION; +import static com.atlassian.confluence.security.ContentPermission.VIEW_PERMISSION; +import static com.atlassian.confluence.security.ContentPermission.createUserPermission; +import static com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext.GLOBAL_CONTEXT; +import static com.atlassian.confluence.util.velocity.VelocityUtils.getRenderedTemplate; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.InvalidParameterException; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; + +import org.apache.velocity.tools.generic.DateTool; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; + import com.atlassian.bandana.BandanaManager; import com.atlassian.confluence.content.render.xhtml.ConversionContext; import com.atlassian.confluence.core.ContentEntityObject; @@ -23,25 +49,6 @@ import com.atlassian.user.Group; import com.atlassian.user.GroupManager; import com.atlassian.user.search.page.Pager; -import org.apache.velocity.tools.generic.DateTool; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Autowired; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.InvalidParameterException; -import java.util.*; - -import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; -import static com.atlassian.confluence.security.ContentPermission.EDIT_PERMISSION; -import static com.atlassian.confluence.security.ContentPermission.VIEW_PERMISSION; -import static com.atlassian.confluence.security.ContentPermission.createUserPermission; -import static com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext.GLOBAL_CONTEXT; -import static com.atlassian.confluence.util.velocity.VelocityUtils.getRenderedTemplate; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; -import static java.util.stream.Collectors.toList; @Scanned public class DigitalSignatureMacro implements Macro { @@ -178,10 +185,15 @@ private void ensureProtectedPage(ConversionContext conversionContext, Page page, } private boolean hideSignatures(Map params, Signature signature, String currentUserName) { + try { + signature = signature.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } boolean pendingVisible = isVisible(signature, currentUserName, params.get("pendingVisible")); boolean signaturesVisible = isVisible(signature, currentUserName, params.get("signaturesVisible")); - if (!pendingVisible) signature.setMissingSignatures(emptySet()); - if (!signaturesVisible) signature.setSignatures(emptyMap()); + if (!pendingVisible) signature.setMissingSignatures(new TreeSet<>()); + if (!signaturesVisible) signature.setSignatures(new HashMap()); return pendingVisible && signaturesVisible; } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java index 64f588e..57e23ae 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java @@ -1,11 +1,15 @@ package com.baloise.confluence.digitalsignature; -import java.io.Serializable; -import java.util.*; - import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; -public class Signature implements Serializable { +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public class Signature implements Serializable, Cloneable { private static final long serialVersionUID = 1L; @@ -83,7 +87,7 @@ public void setSignatures(Map signatures) { } public Set getMissingSignatures() { - return missingSignatures; + return missingSignatures; } public void setMissingSignatures(Set missingSignatures) { @@ -191,4 +195,9 @@ public boolean isSignatory(String userName) { public boolean hasMissingSignatures() { return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); } + + @Override + public Signature clone() throws CloneNotSupportedException{ + return (Signature) super.clone(); + } } diff --git a/src/main/resources/digital-signature.properties b/src/main/resources/digital-signature.properties index 26f012b..8dca015 100644 --- a/src/main/resources/digital-signature.properties +++ b/src/main/resources/digital-signature.properties @@ -39,7 +39,7 @@ com.baloise.confluence.digital-signature.signature.macro.panel.export.label=Expo com.baloise.confluence.digital-signature.signature.macro.panel.email.label=Send e-mail to signatories com.baloise.confluence.digital-signature.signature.macro.panel.email.menu.already-signed=Completed signatories com.baloise.confluence.digital-signature.signature.macro.panel.email.menu.not-yet-signed=Pending signatories -com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort=You need to enter at least 10 characters of text to be signed. +com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort=Please enter at least 10 characters of text to be signed. You can type into the macro's body, once added to a page. com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent=You need to {0}restrict{1} page access and have at least one edit permission in order to allow protected content. com.baloise.confluence.digital-signature.signature.service.error.badUser={0} is not expected to sign document {1} com.baloise.confluence.digital-signature.signature.service.message.label.withNames=With names diff --git a/src/main/resources/digital-signature_de.properties b/src/main/resources/digital-signature_de.properties index 1d6637d..2438986 100644 --- a/src/main/resources/digital-signature_de.properties +++ b/src/main/resources/digital-signature_de.properties @@ -39,7 +39,7 @@ com.baloise.confluence.digital-signature.signature.macro.panel.export.label=Gesc com.baloise.confluence.digital-signature.signature.macro.panel.email.label=Email an Unterzeichnende com.baloise.confluence.digital-signature.signature.macro.panel.email.menu.already-signed=Bereits unterzeichnet com.baloise.confluence.digital-signature.signature.macro.panel.email.menu.not-yet-signed=Noch nicht unterzeichnet -com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort=Geben Sie mindesten 10 Zeichen Text ein. +com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort=Bitte geben Sie mindesten 10 Zeichen zu signierenden Text ein. Sie können diesen direkt im Macro eingeben, sobald dieses auf einer Seite platziert ist. com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent=Die müssen das Bearbeiten der Seite {0}beschränken{1} um eine geschütze Unterseite zu erstellen. com.baloise.confluence.digital-signature.signature.service.error.badUser=Es wird nicht erwartet, dass {0} {1} unterzeichnet. com.baloise.confluence.digital-signature.signature.service.message.label.withNames=Mit Namen diff --git a/src/test/java/com/baloise/confluence/digitalsignature/SignatureTest.java b/src/test/java/com/baloise/confluence/digitalsignature/SignatureTest.java new file mode 100644 index 0000000..6056305 --- /dev/null +++ b/src/test/java/com/baloise/confluence/digitalsignature/SignatureTest.java @@ -0,0 +1,20 @@ +package com.baloise.confluence.digitalsignature; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.junit.Test; + +public class SignatureTest { + + @Test + public void testClone() throws Exception { + Signature signature = new Signature(999, "title", "body"); + signature.getMissingSignatures().add("Hans"); + Signature cloned = signature.clone(); + assertFalse(signature == cloned); + assertEquals(signature, cloned); + assertEquals("Hans", cloned.getMissingSignatures().iterator().next()); + } + +} \ No newline at end of file