From 44aeff195ed234d435884eca67aa6d0e1bb35b0e Mon Sep 17 00:00:00 2001 From: tiliavir Date: Mon, 11 May 2020 22:01:52 +0200 Subject: [PATCH 01/15] auto format and minor cleanup (typos, md, etc.) --- .gitignore | 2 +- README.RELEASE.MD | 6 +- development.txt => development.md | 23 +- docs/privacy-policy.md | 8 +- icon/CREDITS | 2 +- .../digitalsignature/ContextHelper.java | 133 ++-- .../DigitalSignatureMacro.java | 689 +++++++++--------- .../digitalsignature/InheritSigners.java | 19 +- .../digitalsignature/Signature.java | 333 +++++---- .../digitalsignature/SignaturesVisible.java | 19 +- .../digitalsignature/UserProfileByName.java | 34 +- .../api/DigitalSignatureComponent.java | 8 +- .../impl/DigitalSignatureComponentImpl.java | 23 +- .../rest/DigitalSigatureService.java | 380 +++++----- .../digitalsignature/sal/DummyProfile.java | 84 +-- .../META-INF/spring/plugin-context.xml | 2 +- .../resources/digital-signature.properties | 2 +- .../resources/digital-signature_de.properties | 6 +- src/main/resources/templates/email.vm | 8 +- src/main/resources/templates/export.vm | 45 +- src/main/resources/templates/macro.vm | 98 ++- .../DigitalSignatureMacroTest.java | 105 ++- .../digitalsignature/InheritSignersTest.java | 30 +- .../digitalsignature/MarkdownTest.java | 54 +- .../digitalsignature/MessageFormatTest.java | 22 +- .../SignatureSerialisationTest.java | 57 +- .../digitalsignature/TemplatesTest.java | 72 +- .../UserProfileByNameTest.java | 43 +- .../digitalsignature/MyComponentUnitTest.java | 2 +- src/test/resources/signature.ser | Bin 534 -> 637 bytes 30 files changed, 1167 insertions(+), 1142 deletions(-) rename development.txt => development.md (74%) diff --git a/.gitignore b/.gitignore index 0d85da0..1858b8b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ /target .idea -*.iml \ No newline at end of file +*.iml diff --git a/README.RELEASE.MD b/README.RELEASE.MD index 5fed2b6..deb768c 100644 --- a/README.RELEASE.MD +++ b/README.RELEASE.MD @@ -1,7 +1,7 @@ -- check fixed issues are assigned to milestone : https://github.com/baloise/digital-signature/milestones +- check fixed issues are assigned to milestone: https://github.com/baloise/digital-signature/milestones - increase version in POM -- mvn clean package +- `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 ) +- 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) diff --git a/development.txt b/development.md similarity index 74% rename from development.txt rename to development.md index c475c1f..ec082b5 100644 --- a/development.txt +++ b/development.md @@ -1,32 +1,39 @@ -Install +# Install https://www.atlassian.com/software/confluence/download-archives -Apache Commons FileUpload Bundle +- Apache Commons FileUpload Bundle http://central.maven.org/maven2/commons-fileupload/commons-fileupload/1.3/commons-fileupload-1.3.jar -Atlassian PDK Install Plugin +- Atlassian PDK Install Plugin http://maven-us.nuxeo.org/nexus/content/repositories/public/com/atlassian/pdkinstall/pdkinstall-plugin/0.6/pdkinstall-plugin-0.6.jar -License +## License https://my.atlassian.com/products/index -Run +# Run +```shell script set CATALINA_HOME=C:\Users\Public\dev\atlas\Confluence set JPDA_ADDRESS=4444 set JPDA_TRANSPORT=dt_socket %CATALINA_HOME%\bin\catalina.bat jpda start +``` http://127.0.0.1:8090/ +```shell script atlas-install-plugin -p 8090 --context-path / --plugin-key com.baloise.confluence.digital-signature +``` ------------------- -Pure Maven setup ( not for the faint of heart, starup is slow on my box) +Pure Maven setup (not for the faint of heart, startup is slow on my box) you will be able to remote debug on port 5005 +```shell script mvn confluence:debug -Dproduct.version=7.4.0 +``` To redeploy use +```shell script mvn package confluence:install -Dproduct.version=7.4.0 +``` -As smtp server use -https://mailtrap.io/ +As smtp server use `https://mailtrap.io/` diff --git a/docs/privacy-policy.md b/docs/privacy-policy.md index f25afc5..7f6484a 100644 --- a/docs/privacy-policy.md +++ b/docs/privacy-policy.md @@ -1,5 +1,3 @@ -We do not transfer or store any data outside your Atlassian product. - -We have no access to any data your stored within your Atlassian product. - -You data is yours - no strings attached. +- We do not transfer or store any data outside your Atlassian product. +- We have no access to any data you stored within your Atlassian product. +- Your data is yours - no strings attached. diff --git a/icon/CREDITS b/icon/CREDITS index 1baf4bf..1fdaced 100644 --- a/icon/CREDITS +++ b/icon/CREDITS @@ -1 +1 @@ -Icon made by http://www.flaticon.com/authors/freepik \ No newline at end of file +Icon made by http://www.flaticon.com/authors/freepik diff --git a/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java b/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java index 448c56d..9b94410 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java @@ -1,76 +1,73 @@ package com.baloise.confluence.digitalsignature; -import static java.lang.String.format; - -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - import com.atlassian.sal.api.user.UserManager; import com.atlassian.sal.api.user.UserProfile; import com.baloise.confluence.digitalsignature.sal.DummyProfile; +import java.util.*; +import java.util.Map.Entry; + +import static java.lang.String.format; + public class ContextHelper { - public Object getOrderedSignatures(Signature signature) { - Comparator> comparator = new Comparator>() { - @Override - public int compare(Entry s1, Entry s2) { - int ret = s1.getValue().compareTo(s2.getValue()); - return ret == 0 ? s1.getKey().compareTo(s2.getKey()) : ret; - } - }; - SortedSet> ret = new TreeSet>(comparator); - ret.addAll(signature.getSignatures().entrySet()); - return ret; - } - public Map union(Map ...maps) { - Map union = new HashMap(); - for (Map map : maps) { - union.putAll(map); - } - return union; - } - - public Set union(Set ...sets) { - Set union = new HashSet(); - for (Set set : sets) { - union.addAll(set); - } - return union; - } - - public Map getProfiles(UserManager userManager, Set userNames) { - Map ret = new HashMap(); - if(Signature.isPetitionMode(userNames)) return ret; - for (String userName : userNames) { - ret.put(userName, getProfileNotNull(userManager, userName)); - } - return ret; - } - public UserProfile getProfileNotNull(UserManager userManager, String userName) { - UserProfile profile = userManager.getUserProfile(userName); - return profile == null ? new DummyProfile(userName) : profile; - } - - public SortedSet getOrderedProfiles(UserManager userManager, Set userNames) { - SortedSet ret = new TreeSet(new UserProfileByName()); - if(Signature.isPetitionMode(userNames)) return ret; - for (String userName : userNames) { - ret.add(getProfileNotNull(userManager, userName)); - } - return ret; - } - public String mailTo(UserProfile profile) { - return format("%s<%s>", profile.getFullName().trim(), profile.getEmail().trim()); - } - public boolean hasEmail(UserProfile profile) { - return profile != null && profile.getEmail() != null && !profile.getEmail().trim().isEmpty(); - } - + public Object getOrderedSignatures(Signature signature) { + Comparator> comparator = new Comparator>() { + @Override + public int compare(Entry s1, Entry s2) { + int ret = s1.getValue().compareTo(s2.getValue()); + return ret == 0 ? s1.getKey().compareTo(s2.getKey()) : ret; + } + }; + SortedSet> ret = new TreeSet>(comparator); + ret.addAll(signature.getSignatures().entrySet()); + return ret; + } + + public Map union(Map... maps) { + Map union = new HashMap(); + for (Map map : maps) { + union.putAll(map); + } + return union; + } + + public Set union(Set... sets) { + Set union = new HashSet(); + for (Set set : sets) { + union.addAll(set); + } + return union; + } + + public Map getProfiles(UserManager userManager, Set userNames) { + Map ret = new HashMap(); + if (Signature.isPetitionMode(userNames)) return ret; + for (String userName : userNames) { + ret.put(userName, getProfileNotNull(userManager, userName)); + } + return ret; + } + + public UserProfile getProfileNotNull(UserManager userManager, String userName) { + UserProfile profile = userManager.getUserProfile(userName); + return profile == null ? new DummyProfile(userName) : profile; + } + + public SortedSet getOrderedProfiles(UserManager userManager, Set userNames) { + SortedSet ret = new TreeSet(new UserProfileByName()); + if (Signature.isPetitionMode(userNames)) return ret; + for (String userName : userNames) { + ret.add(getProfileNotNull(userManager, userName)); + } + return ret; + } + + public String mailTo(UserProfile profile) { + return format("%s<%s>", profile.getFullName().trim(), profile.getEmail().trim()); + } + + public boolean hasEmail(UserProfile profile) { + return profile != null && profile.getEmail() != null && !profile.getEmail().trim().isEmpty(); + } + } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index 39220ba..3cafbba 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -1,29 +1,5 @@ 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.Collections.emptyMap; -import static java.util.Collections.emptySet; -import static java.util.stream.Collectors.toList; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Collection; -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.springframework.beans.factory.annotation.Autowired; - import com.atlassian.bandana.BandanaManager; import com.atlassian.confluence.content.render.xhtml.ConversionContext; import com.atlassian.confluence.core.ContentEntityObject; @@ -48,333 +24,348 @@ 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.springframework.beans.factory.annotation.Autowired; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.*; + +import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; +import static com.atlassian.confluence.security.ContentPermission.*; +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 { - private BandanaManager bandanaManager; - private UserManager userManager; - private BootstrapManager bootstrapManager; - private PageManager pageManager; - private final String REST_PATH = "/rest/signature/1.0"; - private final String DISPLAY_PATH = "/display"; - private ContextHelper contextHelper = new ContextHelper(); - private final transient Markdown markdown = new Markdown(); - private final PermissionManager permissionManager; - private GroupManager groupManager; - private final Set all = new HashSet(); - final int MAX_MAILTO_CHARACTER_COUNT = 500; - private I18nResolver i18nResolver; - - - @Autowired - public DigitalSignatureMacro( - @ComponentImport BandanaManager bandanaManager, - @ComponentImport UserManager userManager, - @ComponentImport BootstrapManager bootstrapManager, - @ComponentImport PageManager pageManager, - @ComponentImport PermissionManager permissionManager, - @ComponentImport GroupManager groupManager, - @ComponentImport I18nResolver i18nResolver - ) { - this.bandanaManager = bandanaManager; - this.userManager = userManager; - this.bootstrapManager = bootstrapManager; - this.pageManager = pageManager; - this.permissionManager = permissionManager; - this.groupManager = groupManager; - this.i18nResolver = i18nResolver; - all.add("*"); - } - - @Override - public String execute(Map params, String body, ConversionContext conversionContext) throws MacroExecutionException { - if(body != null && body.length() > 10) { - Set userGroups = getSet(params, "signerGroups"); - boolean petitionMode = Signature.isPetitionMode(userGroups); - @SuppressWarnings("unchecked") - Set signers = petitionMode ? all : contextHelper.union( - getSet(params, "signers"), - loadUserGroups(userGroups), - loadInheritedSigners(InheritSigners.ofValue(params.get("inheritSigners")), conversionContext) - ); - ContentEntityObject entity = conversionContext.getEntity(); - Signature signature = sync(new Signature( - entity.getLatestVersionId(), - body, - params.get("title")) - .withNotified(getSet(params, "notified")) - .withMaxSignatures(getLong(params, "maxSignatures", -1)), - signers - ); - ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); - String currentUserName = currentUser.getName(); - - boolean protectedContent = getBoolean(params, "protectedContent", false); - boolean protectedContentAccess = protectedContent && (permissionManager.hasPermission(currentUser, Permission.EDIT, entity) ||signature.hasSigned(currentUserName)); - - if(protectedContent && isPage(conversionContext)) { - Page protectedPage = pageManager.getPage(conversionContext.getSpaceKey(), signature.getProtectedKey()); - if(protectedPage == null) { - Page page = (Page) entity; - ContentPermissionSet editors = page.getContentPermissionSet(EDIT_PERMISSION); - if(editors == null || editors.size() == 0) { - return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent" ,"")); - } - protectedPage = new Page(); - protectedPage.setSpace(page.getSpace()); - protectedPage.setParentPage(page); - protectedPage.setVersion(1); - protectedPage.setCreator(page.getCreator()); - for (ContentPermission editor : editors) { - protectedPage.addPermission(createUserPermission(EDIT_PERMISSION, editor.getUserSubject())); - protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, editor.getUserSubject())); - } - for(String signedUserName : signature.getSignatures().keySet()) { - protectedPage.addPermission(createUserPermission(VIEW_PERMISSION,signedUserName)); - } - protectedPage.setTitle(signature.getProtectedKey()); - pageManager.saveContentEntity(protectedPage, DefaultSaveContext.DEFAULT); - page.addChild(protectedPage); - } - } - - Map context = defaultVelocityContext(); - context.put("date", new DateTool()); - context.put("markdown", markdown); - - if(signature.isSignatureMissing(currentUserName)) { - context.put("signAs", contextHelper.getProfileNotNull(userManager, currentUserName).getFullName()); - context.put("signAction", bootstrapManager.getWebAppContextPath()+ REST_PATH+"/sign"); - } - context.put("panel", getBoolean(params, "panel", true)); - context.put("protectedContent", protectedContentAccess); - if(protectedContentAccess && isPage(conversionContext)) { - Page page = (Page) entity; - context.put("protectedContentURL", bootstrapManager.getWebAppContextPath()+ DISPLAY_PATH+"/"+page.getSpaceKey()+"/"+signature.getProtectedKey()); - } - - boolean canExport = hideSignatures(params, signature, currentUserName); - Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); - Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); - - context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); - context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); - context.put("profiles", contextHelper.union(signed, missing)); - context.put("signature", signature); - context.put("mailtoSigned", getMailto(signed.values(), signature.getTitle(), true, signature)); - context.put("mailtoMissing", getMailto(missing.values(), signature.getTitle(), false, signature)); - context.put("UUID", UUID.randomUUID().toString().replace("-", "")); - context.put("downloadURL", canExport ? bootstrapManager.getWebAppContextPath()+ REST_PATH+"/export?key="+signature.getKey() : null); - return getRenderedTemplate("templates/macro.vm", context); - } - return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort")); - - - } - - private boolean hideSignatures(Map params, Signature signature, String currentUserName) { - boolean pendingVisible = true; - boolean signaturesVisible = true; - switch (SignaturesVisible.ofValue(params.get("pendingVisible"))) { - case IF_SIGNATORY: - if(!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { - pendingVisible = false; - } - break; - case IF_SIGNED: - if(!signature.hasSigned(currentUserName)) { - pendingVisible = false; - } - break; - case ALWAYS: - break; - } - switch (SignaturesVisible.ofValue(params.get("signaturesVisible"))) { - case IF_SIGNATORY: - if(!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { - signaturesVisible = false; - } - break; - case IF_SIGNED: - if(!signature.hasSigned(currentUserName)) { - signaturesVisible = false; - } - break; - case ALWAYS: - break; - } - if(!pendingVisible) signature.setMissingSignatures(emptySet()); - if(!signaturesVisible) signature.setSignatures(emptyMap()); - return pendingVisible && signaturesVisible; - } - - private boolean isPage(ConversionContext conversionContext) { - return conversionContext.getEntity()instanceof Page; - } - - private String warning(String message) { - return "
\n" + - "

\n" + - " "+i18nResolver.getText("com.baloise.confluence.digital-signature.signature.label")+"\n" + - "

\n" + - "

"+message+"

\n" + - "
"; - } - - private Set loadInheritedSigners(InheritSigners inheritSigners, ConversionContext conversionContext) { - Set users = new HashSet(); - switch (inheritSigners) { - case READERS_AND_WRITERS: - users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); - users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); - break; - case READERS_ONLY: - users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); - users.removeAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); - break; - case WRITERS_ONLY: - users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); - break; - case NONE: - break; - } - return users; - } - - private Set loadUsers(ConversionContext conversionContext, String permission) { - Set users = new HashSet(); - ContentPermissionSet contentPermissionSet = conversionContext.getEntity().getContentPermissionSet(permission); - if(contentPermissionSet != null) { - for (ContentPermission cp : contentPermissionSet) { - if(cp.getGroupName()!= null) { - users.addAll(loadUserGroup(cp.getGroupName())); - } - if(cp.getUserSubject() != null) { - users.add(cp.getUserSubject().getName()); - } - } - } - return users; - } - - private Set loadUserGroups(Iterable groupNames) { - Set ret = new HashSet(); - for (String groupName : groupNames) { - ret.addAll(loadUserGroup(groupName)); - } - return ret; - } - - private Set loadUserGroup(String groupName) { - Set ret = new HashSet(); - try { - if(groupName == null) return ret; - Group group = groupManager.getGroup(groupName.trim()); - if(group == null) return ret; - Pager pager = groupManager.getMemberNames(group); - while(!pager.onLastPage()) { - ret.addAll(pager.getCurrentPage()); - pager.nextPage(); - } - ret.addAll(pager.getCurrentPage()); - } catch (EntityException e) { - e.printStackTrace(); - } - return ret; - } - - private Boolean getBoolean(Map params, String key, Boolean fallback) { - String value = params.get(key); - return value == null ? fallback : Boolean.valueOf(value) ; - } - - private long getLong(Map params, String key, long fallback) { - String value = params.get(key); - return value == null ? fallback : Long.valueOf(value) ; - } - - private Set getSet(Map params, String key) { - String value = params.get(key); - return value == null || value.trim().isEmpty() ? new TreeSet() : new TreeSet(asList(value.split("[;, ]+"))); - } - - private Signature sync(Signature signature, Set signers) { - Signature loaded = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, signature.getKey()); - if(loaded != null) { - signature.setSignatures(loaded.getSignatures()); - boolean save = false; - - if(!Objects.equals(loaded.getNotify(),signature.getNotify())) { - loaded.setNotify(signature.getNotify()); - save = true; - } - - signers.removeAll(loaded.getSignatures().keySet()); - signature.setMissingSignatures(signers); - if(!Objects.equals(loaded.getMissingSignatures(),signature.getMissingSignatures())) { - loaded.setMissingSignatures(signature.getMissingSignatures()); - save = true; - } - if(loaded.getMaxSignatures() != signature.getMaxSignatures()) { - loaded.setMaxSignatures(signature.getMaxSignatures()); - save = true; - } - - if(save) save(loaded); - } else { - signature.setMissingSignatures(signers); - save(signature); - } - return signature; - } - - private void save(Signature signature) { - if(signature.hasMissingSignatures()) - bandanaManager.setValue(GLOBAL_CONTEXT, signature.getKey(), signature); - } - - @Override - public BodyType getBodyType() { - return BodyType.PLAIN_TEXT; - } - - @Override - public OutputType getOutputType() { - return OutputType.BLOCK; - } - - String getMailto(Collection profiles, String subject, boolean signed, Signature signature) { - if(profiles == null || profiles.isEmpty()) return null; - profiles = profiles.stream() - .filter(contextHelper::hasEmail) - .collect(toList()); - StringBuilder ret = new StringBuilder("mailto:"); - for (UserProfile profile : profiles) { - if(ret.length()>7) ret.append(','); - ret.append(contextHelper.mailTo(profile)); - } - ret.append("?Subject="+urlEncode(subject)); - if(ret.length() > MAX_MAILTO_CHARACTER_COUNT) { - ret.setLength(0); - ret.append("mailto:"); - for (UserProfile profile : profiles) { - if(ret.length()>7) ret.append(','); - ret.append(profile.getEmail().trim()); - } - ret.append("?Subject="+urlEncode(subject)); - } - if(ret.length() > MAX_MAILTO_CHARACTER_COUNT) { - return bootstrapManager.getWebAppContextPath()+ REST_PATH+"/emails?key="+signature.getKey()+"&signed="+signed; - } - return ret.toString(); - } - - public String urlEncode(String string) { - try { - return URLEncoder.encode(string, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(e); - } - } + private BandanaManager bandanaManager; + private UserManager userManager; + private BootstrapManager bootstrapManager; + private PageManager pageManager; + private final String REST_PATH = "/rest/signature/1.0"; + private final String DISPLAY_PATH = "/display"; + private ContextHelper contextHelper = new ContextHelper(); + private final transient Markdown markdown = new Markdown(); + private final PermissionManager permissionManager; + private GroupManager groupManager; + private final Set all = new HashSet(); + final int MAX_MAILTO_CHARACTER_COUNT = 500; + private I18nResolver i18nResolver; + + + @Autowired + public DigitalSignatureMacro( + @ComponentImport BandanaManager bandanaManager, + @ComponentImport UserManager userManager, + @ComponentImport BootstrapManager bootstrapManager, + @ComponentImport PageManager pageManager, + @ComponentImport PermissionManager permissionManager, + @ComponentImport GroupManager groupManager, + @ComponentImport I18nResolver i18nResolver + ) { + this.bandanaManager = bandanaManager; + this.userManager = userManager; + this.bootstrapManager = bootstrapManager; + this.pageManager = pageManager; + this.permissionManager = permissionManager; + this.groupManager = groupManager; + this.i18nResolver = i18nResolver; + all.add("*"); + } + + @Override + public String execute(Map params, String body, ConversionContext conversionContext) throws MacroExecutionException { + if (body != null && body.length() > 10) { + Set userGroups = getSet(params, "signerGroups"); + boolean petitionMode = Signature.isPetitionMode(userGroups); + @SuppressWarnings("unchecked") + Set signers = petitionMode ? all : contextHelper.union( + getSet(params, "signers"), + loadUserGroups(userGroups), + loadInheritedSigners(InheritSigners.ofValue(params.get("inheritSigners")), conversionContext) + ); + ContentEntityObject entity = conversionContext.getEntity(); + Signature signature = sync(new Signature( + entity.getLatestVersionId(), + body, + params.get("title")) + .withNotified(getSet(params, "notified")) + .withMaxSignatures(getLong(params, "maxSignatures", -1)), + signers + ); + ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); + String currentUserName = currentUser.getName(); + + boolean protectedContent = getBoolean(params, "protectedContent", false); + boolean protectedContentAccess = protectedContent && (permissionManager.hasPermission(currentUser, Permission.EDIT, entity) || signature.hasSigned(currentUserName)); + + if (protectedContent && isPage(conversionContext)) { + Page protectedPage = pageManager.getPage(conversionContext.getSpaceKey(), signature.getProtectedKey()); + if (protectedPage == null) { + Page page = (Page) entity; + ContentPermissionSet editors = page.getContentPermissionSet(EDIT_PERMISSION); + if (editors == null || editors.size() == 0) { + return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent", "")); + } + protectedPage = new Page(); + protectedPage.setSpace(page.getSpace()); + protectedPage.setParentPage(page); + protectedPage.setVersion(1); + protectedPage.setCreator(page.getCreator()); + for (ContentPermission editor : editors) { + protectedPage.addPermission(createUserPermission(EDIT_PERMISSION, editor.getUserSubject())); + protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, editor.getUserSubject())); + } + for (String signedUserName : signature.getSignatures().keySet()) { + protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, signedUserName)); + } + protectedPage.setTitle(signature.getProtectedKey()); + pageManager.saveContentEntity(protectedPage, DefaultSaveContext.DEFAULT); + page.addChild(protectedPage); + } + } + + Map context = defaultVelocityContext(); + context.put("date", new DateTool()); + context.put("markdown", markdown); + + if (signature.isSignatureMissing(currentUserName)) { + context.put("signAs", contextHelper.getProfileNotNull(userManager, currentUserName).getFullName()); + context.put("signAction", bootstrapManager.getWebAppContextPath() + REST_PATH + "/sign"); + } + context.put("panel", getBoolean(params, "panel", true)); + context.put("protectedContent", protectedContentAccess); + if (protectedContentAccess && isPage(conversionContext)) { + Page page = (Page) entity; + context.put("protectedContentURL", bootstrapManager.getWebAppContextPath() + DISPLAY_PATH + "/" + page.getSpaceKey() + "/" + signature.getProtectedKey()); + } + + boolean canExport = hideSignatures(params, signature, currentUserName); + Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); + Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); + + context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); + context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); + context.put("profiles", contextHelper.union(signed, missing)); + context.put("signature", signature); + context.put("mailtoSigned", getMailto(signed.values(), signature.getTitle(), true, signature)); + context.put("mailtoMissing", getMailto(missing.values(), signature.getTitle(), false, signature)); + context.put("UUID", UUID.randomUUID().toString().replace("-", "")); + context.put("downloadURL", canExport ? bootstrapManager.getWebAppContextPath() + REST_PATH + "/export?key=" + signature.getKey() : null); + return getRenderedTemplate("templates/macro.vm", context); + } + return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort")); + + + } + + private boolean hideSignatures(Map params, Signature signature, String currentUserName) { + boolean pendingVisible = true; + boolean signaturesVisible = true; + switch (SignaturesVisible.ofValue(params.get("pendingVisible"))) { + case IF_SIGNATORY: + if (!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { + pendingVisible = false; + } + break; + case IF_SIGNED: + if (!signature.hasSigned(currentUserName)) { + pendingVisible = false; + } + break; + case ALWAYS: + break; + } + switch (SignaturesVisible.ofValue(params.get("signaturesVisible"))) { + case IF_SIGNATORY: + if (!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { + signaturesVisible = false; + } + break; + case IF_SIGNED: + if (!signature.hasSigned(currentUserName)) { + signaturesVisible = false; + } + break; + case ALWAYS: + break; + } + if (!pendingVisible) signature.setMissingSignatures(emptySet()); + if (!signaturesVisible) signature.setSignatures(emptyMap()); + return pendingVisible && signaturesVisible; + } + + private boolean isPage(ConversionContext conversionContext) { + return conversionContext.getEntity() instanceof Page; + } + + private String warning(String message) { + return "
\n" + + "

\n" + + " " + i18nResolver.getText("com.baloise.confluence.digital-signature.signature.label") + "\n" + + "

\n" + + "

" + message + "

\n" + + "
"; + } + + private Set loadInheritedSigners(InheritSigners inheritSigners, ConversionContext conversionContext) { + Set users = new HashSet(); + switch (inheritSigners) { + case READERS_AND_WRITERS: + users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); + users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + break; + case READERS_ONLY: + users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); + users.removeAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + break; + case WRITERS_ONLY: + users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + break; + case NONE: + break; + } + return users; + } + + private Set loadUsers(ConversionContext conversionContext, String permission) { + Set users = new HashSet(); + ContentPermissionSet contentPermissionSet = conversionContext.getEntity().getContentPermissionSet(permission); + if (contentPermissionSet != null) { + for (ContentPermission cp : contentPermissionSet) { + if (cp.getGroupName() != null) { + users.addAll(loadUserGroup(cp.getGroupName())); + } + if (cp.getUserSubject() != null) { + users.add(cp.getUserSubject().getName()); + } + } + } + return users; + } + + private Set loadUserGroups(Iterable groupNames) { + Set ret = new HashSet(); + for (String groupName : groupNames) { + ret.addAll(loadUserGroup(groupName)); + } + return ret; + } + + private Set loadUserGroup(String groupName) { + Set ret = new HashSet(); + try { + if (groupName == null) return ret; + Group group = groupManager.getGroup(groupName.trim()); + if (group == null) return ret; + Pager pager = groupManager.getMemberNames(group); + while (!pager.onLastPage()) { + ret.addAll(pager.getCurrentPage()); + pager.nextPage(); + } + ret.addAll(pager.getCurrentPage()); + } catch (EntityException e) { + e.printStackTrace(); + } + return ret; + } + + private Boolean getBoolean(Map params, String key, Boolean fallback) { + String value = params.get(key); + return value == null ? fallback : Boolean.valueOf(value); + } + + private long getLong(Map params, String key, long fallback) { + String value = params.get(key); + return value == null ? fallback : Long.valueOf(value); + } + + private Set getSet(Map params, String key) { + String value = params.get(key); + return value == null || value.trim().isEmpty() ? new TreeSet() : new TreeSet(asList(value.split("[;, ]+"))); + } + + private Signature sync(Signature signature, Set signers) { + Signature loaded = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, signature.getKey()); + if (loaded != null) { + signature.setSignatures(loaded.getSignatures()); + boolean save = false; + + if (!Objects.equals(loaded.getNotify(), signature.getNotify())) { + loaded.setNotify(signature.getNotify()); + save = true; + } + + signers.removeAll(loaded.getSignatures().keySet()); + signature.setMissingSignatures(signers); + if (!Objects.equals(loaded.getMissingSignatures(), signature.getMissingSignatures())) { + loaded.setMissingSignatures(signature.getMissingSignatures()); + save = true; + } + if (loaded.getMaxSignatures() != signature.getMaxSignatures()) { + loaded.setMaxSignatures(signature.getMaxSignatures()); + save = true; + } + + if (save) save(loaded); + } else { + signature.setMissingSignatures(signers); + save(signature); + } + return signature; + } + + private void save(Signature signature) { + if (signature.hasMissingSignatures()) + bandanaManager.setValue(GLOBAL_CONTEXT, signature.getKey(), signature); + } + + @Override + public BodyType getBodyType() { + return BodyType.PLAIN_TEXT; + } + + @Override + public OutputType getOutputType() { + return OutputType.BLOCK; + } + + String getMailto(Collection profiles, String subject, boolean signed, Signature signature) { + if (profiles == null || profiles.isEmpty()) return null; + profiles = profiles.stream() + .filter(contextHelper::hasEmail) + .collect(toList()); + StringBuilder ret = new StringBuilder("mailto:"); + for (UserProfile profile : profiles) { + if (ret.length() > 7) ret.append(','); + ret.append(contextHelper.mailTo(profile)); + } + ret.append("?Subject=" + urlEncode(subject)); + if (ret.length() > MAX_MAILTO_CHARACTER_COUNT) { + ret.setLength(0); + ret.append("mailto:"); + for (UserProfile profile : profiles) { + if (ret.length() > 7) ret.append(','); + ret.append(profile.getEmail().trim()); + } + ret.append("?Subject=" + urlEncode(subject)); + } + if (ret.length() > MAX_MAILTO_CHARACTER_COUNT) { + return bootstrapManager.getWebAppContextPath() + REST_PATH + "/emails?key=" + signature.getKey() + "&signed=" + signed; + } + return ret.toString(); + } + + public String urlEncode(String string) { + try { + return URLEncoder.encode(string, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); + } + } } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java b/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java index 2e6b510..95d44b9 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java @@ -1,16 +1,15 @@ package com.baloise.confluence.digitalsignature; public enum InheritSigners { - NONE, READERS_AND_WRITERS, READERS_ONLY, WRITERS_ONLY - ; + NONE, READERS_AND_WRITERS, READERS_ONLY, WRITERS_ONLY; - public static InheritSigners ofValue(String v) { - try { - return InheritSigners.valueOf(v.toUpperCase().replaceAll("\\W+", "_")); - } catch (Exception e) { - return NONE; - } - - } + public static InheritSigners ofValue(String v) { + try { + return InheritSigners.valueOf(v.toUpperCase().replaceAll("\\W+", "_")); + } catch (Exception e) { + return NONE; + } + + } } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java index 43dede7..be50528 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java @@ -1,162 +1,183 @@ package com.baloise.confluence.digitalsignature; -import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; - import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; + +import static org.apache.commons.codec.digest.DigestUtils.sha256Hex; public class Signature implements Serializable { - - private static final long serialVersionUID = 1L; - - private String key = ""; - private String hash = ""; - private long pageId; - private String title = ""; - private String body = ""; - private long maxSignatures = -1; - private Map signatures = new HashMap(); - private Set missingSignatures = new TreeSet(); - private Set notified = new TreeSet(); - - public Signature() {} - public Signature(long pageId, String body,String title) { - this.pageId = pageId; - this.body = body; - this.title = title == null ? "" : title; - hash = sha256Hex(pageId +":"+ title +":" + body); - key = "signature."+hash; - } - public String getHash() { - if(hash == null) { - hash = getKey().replace("signature.", ""); - } - return hash; - } - public void setHash(String hash) { - this.hash = hash; - } - public String getKey() { - return key; - } - public String getProtectedKey() { - return "protected."+getHash(); - } - public void setKey(String key) { - this.key = key; - } - public long getPageId() { - return pageId; - } - public void setPageId(long pageId) { - this.pageId = pageId; - } - public String getBody() { - return body; - } - public void setBody(String body) { - this.body = body; - } - public Map getSignatures() { - return signatures; - } - public void setSignatures(Map signatures) { - this.signatures = signatures; - } - public Set getMissingSignatures() { - return missingSignatures; - } - public void setMissingSignatures(Set missingSignatures) { - this.missingSignatures = missingSignatures; - } - public long getMaxSignatures() { - return maxSignatures; - } - public void setMaxSignatures(long maxSignatures) { - this.maxSignatures = maxSignatures; - } - public String getTitle() { - return title; - } - public void setTitle(String title) { - this.title = title; - } - public Set getNotify() { - return notified; - } - public void setNotify(Set notify) { - this.notified = notify; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Signature other = (Signature) obj; - if (key == null) { - if (other.key != null) - return false; - } else if (!key.equals(other.key)) - return false; - return true; - } - - public Signature withNotified(Set notified) { - this.notified = notified; - return this; - } - - public Signature withMaxSignatures(long maxSignatures) { - this.maxSignatures = maxSignatures; - return this; - } - - public boolean hasSigned(String userName) { - return signatures.containsKey(userName); - } - - public boolean isPetitionMode() { - return isPetitionMode(getMissingSignatures()); - } - - public static boolean isPetitionMode(Set userGroups) { - return userGroups != null && userGroups.size() == 1 && userGroups.iterator().next().trim().equals("*"); - } - public boolean sign(String userName) { - if(!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { - return false; - } else { - getSignatures().put(userName, new Date()); - return true; - } - } - public boolean isMaxSignaturesReached() { - return maxSignatures > -1 && maxSignatures <= getSignatures().size(); - } - public boolean isSignatureMissing(String userName) { - return !isMaxSignaturesReached() && !hasSigned(userName) && isSignatory(userName); - } - - public boolean isSignatory(String userName) { - return isPetitionMode() || getMissingSignatures().contains(userName); - } - - public boolean hasMissingSignatures() { - return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); - } + + private static final long serialVersionUID = 1L; + + private String key = ""; + private String hash = ""; + private long pageId; + private String title = ""; + private String body = ""; + private long maxSignatures = -1; + private Map signatures = new HashMap(); + private Set missingSignatures = new TreeSet(); + private Set notified = new TreeSet(); + + public Signature() { + } + + public Signature(long pageId, String body, String title) { + this.pageId = pageId; + this.body = body; + this.title = title == null ? "" : title; + hash = sha256Hex(pageId + ":" + title + ":" + body); + key = "signature." + hash; + } + + public String getHash() { + if (hash == null) { + hash = getKey().replace("signature.", ""); + } + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public String getKey() { + return key; + } + + public String getProtectedKey() { + return "protected." + getHash(); + } + + public void setKey(String key) { + this.key = key; + } + + public long getPageId() { + return pageId; + } + + public void setPageId(long pageId) { + this.pageId = pageId; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public Map getSignatures() { + return signatures; + } + + public void setSignatures(Map signatures) { + this.signatures = signatures; + } + + public Set getMissingSignatures() { + return missingSignatures; + } + + public void setMissingSignatures(Set missingSignatures) { + this.missingSignatures = missingSignatures; + } + + public long getMaxSignatures() { + return maxSignatures; + } + + public void setMaxSignatures(long maxSignatures) { + this.maxSignatures = maxSignatures; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Set getNotify() { + return notified; + } + + public void setNotify(Set notify) { + this.notified = notify; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Signature other = (Signature) obj; + if (key == null) { + if (other.key != null) + return false; + } else if (!key.equals(other.key)) + return false; + return true; + } + + public Signature withNotified(Set notified) { + this.notified = notified; + return this; + } + + public Signature withMaxSignatures(long maxSignatures) { + this.maxSignatures = maxSignatures; + return this; + } + + public boolean hasSigned(String userName) { + return signatures.containsKey(userName); + } + + public boolean isPetitionMode() { + return isPetitionMode(getMissingSignatures()); + } + + public static boolean isPetitionMode(Set userGroups) { + return userGroups != null && userGroups.size() == 1 && userGroups.iterator().next().trim().equals("*"); + } + + public boolean sign(String userName) { + if (!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { + return false; + } else { + getSignatures().put(userName, new Date()); + return true; + } + } + + public boolean isMaxSignaturesReached() { + return maxSignatures > -1 && maxSignatures <= getSignatures().size(); + } + + public boolean isSignatureMissing(String userName) { + return !isMaxSignaturesReached() && !hasSigned(userName) && isSignatory(userName); + } + + public boolean isSignatory(String userName) { + return isPetitionMode() || getMissingSignatures().contains(userName); + } + + public boolean hasMissingSignatures() { + return !isMaxSignaturesReached() && (isPetitionMode() || !getMissingSignatures().isEmpty()); + } } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java b/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java index 74b0bba..ff1525d 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java @@ -1,16 +1,15 @@ package com.baloise.confluence.digitalsignature; public enum SignaturesVisible { - ALWAYS, IF_SIGNATORY, IF_SIGNED - ; + ALWAYS, IF_SIGNATORY, IF_SIGNED; - public static SignaturesVisible ofValue(String v) { - try { - return SignaturesVisible.valueOf(v.toUpperCase().replaceAll("\\W+", "_")); - } catch (Exception e) { - return ALWAYS; - } - - } + public static SignaturesVisible ofValue(String v) { + try { + return SignaturesVisible.valueOf(v.toUpperCase().replaceAll("\\W+", "_")); + } catch (Exception e) { + return ALWAYS; + } + + } } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java b/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java index 0700d60..b0e0c1c 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java @@ -1,23 +1,23 @@ package com.baloise.confluence.digitalsignature; -import java.util.Comparator; - import com.atlassian.sal.api.user.UserProfile; +import java.util.Comparator; + public class UserProfileByName implements Comparator { - - @Override - public int compare(UserProfile u1, UserProfile u2) { - int ret = nn(u1.getFullName()).compareTo(nn(u2.getFullName())); - if(ret != 0 ) return ret; - ret = nn(u1.getEmail()).compareTo(nn(u2.getEmail())); - if(ret != 0 ) return ret; - ret = nn(u1.getUsername()).compareTo(nn(u2.getUsername())); - if(ret != 0 ) return ret; - return Integer.compare(u1.hashCode(), u2.hashCode()); - } - private String nn(String string) { - return string == null ? "" : string; - } -} \ No newline at end of file + @Override + public int compare(UserProfile u1, UserProfile u2) { + int ret = nn(u1.getFullName()).compareTo(nn(u2.getFullName())); + if (ret != 0) return ret; + ret = nn(u1.getEmail()).compareTo(nn(u2.getEmail())); + if (ret != 0) return ret; + ret = nn(u1.getUsername()).compareTo(nn(u2.getUsername())); + if (ret != 0) return ret; + return Integer.compare(u1.hashCode(), u2.hashCode()); + } + + private String nn(String string) { + return string == null ? "" : string; + } +} diff --git a/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java b/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java index 178313e..1c92bf8 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java @@ -1,7 +1,7 @@ package com.baloise.confluence.digitalsignature.api; -public interface DigitalSignatureComponent -{ +public interface DigitalSignatureComponent { public final static String PLUGIN_KEY = "com.baloise.confluence:digital-signature"; - String getName(); -} \ No newline at end of file + + String getName(); +} diff --git a/src/main/java/com/baloise/confluence/digitalsignature/impl/DigitalSignatureComponentImpl.java b/src/main/java/com/baloise/confluence/digitalsignature/impl/DigitalSignatureComponentImpl.java index 03a6840..379b812 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/impl/DigitalSignatureComponentImpl.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/impl/DigitalSignatureComponentImpl.java @@ -8,29 +8,26 @@ import javax.inject.Inject; import javax.inject.Named; -@ExportAsService ({DigitalSignatureComponent.class}) -@Named ("digitalSignatureComponent") -public class DigitalSignatureComponentImpl implements DigitalSignatureComponent -{ +@ExportAsService({DigitalSignatureComponent.class}) +@Named("digitalSignatureComponent") +public class DigitalSignatureComponentImpl implements DigitalSignatureComponent { @ComponentImport private final ApplicationProperties applicationProperties; public DigitalSignatureComponentImpl() { - this(null); + this(null); } + @Inject - public DigitalSignatureComponentImpl(final ApplicationProperties applicationProperties) - { + public DigitalSignatureComponentImpl(final ApplicationProperties applicationProperties) { this.applicationProperties = applicationProperties; } - public String getName() - { - if(null != applicationProperties) - { + public String getName() { + if (null != applicationProperties) { return "digitalSignatureComponent:" + applicationProperties.getDisplayName(); } - + return "digitalSignatureComponent"; } -} \ No newline at end of file +} diff --git a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java index 7bab347..b2895e1 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java @@ -1,36 +1,4 @@ package com.baloise.confluence.digitalsignature.rest; -import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; -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 com.baloise.confluence.digitalsignature.api.DigitalSignatureComponent.PLUGIN_KEY; -import static java.lang.String.format; -import static java.net.URI.create; -import static java.util.stream.Collectors.toList; -import static javax.ws.rs.core.Response.status; -import static javax.ws.rs.core.Response.temporaryRedirect; - -import java.net.URI; -import java.text.MessageFormat; -import java.util.Date; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.function.Function; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - -import org.apache.velocity.tools.generic.DateTool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.atlassian.bandana.BandanaManager; import com.atlassian.confluence.pages.Page; @@ -53,170 +21,196 @@ import com.baloise.confluence.digitalsignature.ContextHelper; import com.baloise.confluence.digitalsignature.Markdown; import com.baloise.confluence.digitalsignature.Signature; +import org.apache.velocity.tools.generic.DateTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.net.URI; +import java.text.MessageFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.function.Function; + +import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; +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 com.baloise.confluence.digitalsignature.api.DigitalSignatureComponent.PLUGIN_KEY; +import static java.lang.String.format; +import static java.net.URI.create; +import static java.util.stream.Collectors.toList; +import static javax.ws.rs.core.Response.status; +import static javax.ws.rs.core.Response.temporaryRedirect; @Path("/") @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Scanned public class DigitalSigatureService { - private static final Logger log = LoggerFactory.getLogger(DigitalSigatureService.class); - private final BandanaManager bandanaManager; - private final SettingsManager settingsManager; - private final UserManager userManager; - private final LocalNotificationService notificationService; - private final MailServerManager mailServerManager; - private final ContextHelper contextHelper = new ContextHelper(); - private final transient Markdown markdown = new Markdown(); - private final PageManager pageManager; - private I18nResolver i18nResolver; - - public DigitalSigatureService( - @ComponentImport BandanaManager bandanaManager, - @ComponentImport SettingsManager settingsManager, - @ComponentImport UserManager userManager, - @ComponentImport LocalNotificationService notificationService, - @ComponentImport MailServerManager mailServerManager, - @ComponentImport PageManager pageManager, - @ComponentImport I18nResolver i18nResolver - ) { - this.settingsManager = settingsManager; - this.bandanaManager = bandanaManager; - this.notificationService = notificationService; - this.userManager = userManager; - this.mailServerManager = mailServerManager; - this.pageManager = pageManager; - this.i18nResolver = i18nResolver; - } - - @GET - @Path("sign") - public Response sign(@QueryParam("key") final String key, @Context UriInfo uriInfo) { - ConfluenceUser confluenceUser = AuthenticatedUserThreadLocal.get(); - String userName = confluenceUser.getName(); - Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); - if(!signature.sign(userName)) { - status(Response.Status.BAD_REQUEST) - .entity(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.error.badUser",userName, key)) - .type( MediaType.TEXT_PLAIN) - .build(); - } - bandanaManager.setValue(GLOBAL_CONTEXT, key, signature); - - String baseUrl = settingsManager.getGlobalSettings().getBaseUrl(); - for(String notifiedUser : signature.getNotify()) { - notify(notifiedUser,confluenceUser, signature, baseUrl); - } - Page parentPage = pageManager.getPage(signature.getPageId()); - Page protectedPage = pageManager.getPage(parentPage.getSpaceKey(), signature.getProtectedKey()); - if(protectedPage != null) { - protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, confluenceUser)); - pageManager.saveContentEntity(protectedPage,null); - } - URI pageUri = create(settingsManager.getGlobalSettings().getBaseUrl()+ "/pages/viewpage.action?pageId="+signature.getPageId()); - return temporaryRedirect(pageUri).build(); - } - - private void notify(final String notifiedUser, ConfluenceUser signedUser, final Signature signature, final String baseUrl) { - try { - UserProfile notifiedUserProfile = contextHelper.getProfileNotNull(userManager, notifiedUser); - - String user = format("%s", - baseUrl+ "/display/~"+signedUser.getName(), - signedUser.getFullName() - ); - String document = format("%s", - baseUrl+"/pages/viewpage.action?pageId="+signature.getPageId(), - signature.getTitle() - ); - String html = i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort", user, document); - if(signature.isMaxSignaturesReached()) { - html = html +"
" +i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.warning.maxSignaturesReached", signature.getMaxSignatures()); - } - String titleText = i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort", signedUser.getFullName(), signature.getTitle()); - - notificationService.createOrUpdate(notifiedUser, new NotificationBuilder() - .application(PLUGIN_KEY) // a unique key that identifies your plugin - .title(titleText) - .itemTitle(titleText) - .description(html) - .groupingId(PLUGIN_KEY+"-signature") // a key to aggregate notifications - .createNotification()).get(); - - SMTPMailServer mailServer = mailServerManager.getDefaultSMTPMailServer(); - - if(mailServer== null) { - log.warn("No default SMTP server found -> no signature notification sent."); - } else if(!contextHelper.hasEmail(notifiedUserProfile)) { - log.warn(notifiedUser +" is to be notified but has no email address. Skipping email notification"); - } else { - mailServer.send( - new Email(notifiedUserProfile.getEmail()) - .setSubject(titleText) - .setBody(html) - .setMimeType("text/html") - ); - } - } catch (IllegalArgumentException e) { - log.error("Could not send notification to "+notifiedUser, e); - } catch (InterruptedException e) { - log.error("Could not send notification to "+notifiedUser, e); - } catch (MailException e) { - log.error("Could not send notification to "+notifiedUser, e); - } catch (ExecutionException e) { - log.error("Could not send notification to "+notifiedUser, e); - } - } - - - - @GET - @Path("export") - @Produces("text/html; charset=UTF-8") - @HtmlSafe - public String export(@QueryParam("key") final String key) { - Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); - - Map context = defaultVelocityContext(); - context.put("signature", signature); - context.put("markdown", markdown); - Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); - Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); - context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); - context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); - context.put("profiles", contextHelper.union(signed, missing)); - - context.put("currentDate", new Date()); - context.put("date", new DateTool()); - - return getRenderedTemplate("templates/export.vm", context); - } - - @GET - @Path("emails") - @Produces("text/html; charset=UTF-8") - public Response emails(@QueryParam("key") final String key, @QueryParam("signed") final boolean signed, @QueryParam("emailOnly") final boolean emailOnly, @Context UriInfo uriInfo) { - Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); - Map profiles = contextHelper.getProfiles(userManager, signed ? signature.getSignatures().keySet() : signature.getMissingSignatures()); - - Map context = defaultVelocityContext(); - context.put("signature", signature); - String signatureText = format("%s ( %s )", signature.getTitle(), signature.getHash()); - String rawTemplate = signed ? - i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails"): - i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.unsignedUsersEmails"); - context.put("signedOrNotWithHtml", MessageFormat.format(rawTemplate, "", "", signatureText)); - context.put("withNamesChecked", emailOnly ? "" : "checked"); - context.put("signedChecked", signed ? "checked" : ""); - context.put("toggleWithNamesURL", uriInfo.getRequestUriBuilder().replaceQueryParam("emailOnly", !emailOnly).build()); - context.put("toggleSignedURL", uriInfo.getRequestUriBuilder().replaceQueryParam("signed", !signed).build()); - Function mapping = p -> (emailOnly ? p.getEmail() : contextHelper.mailTo(p)).trim(); - context.put("emails", profiles.values().stream() - .filter(contextHelper::hasEmail) - .map(mapping).collect(toList())); - - context.put("currentDate", new Date()); - context.put("date", new DateTool()); - return Response.ok(getRenderedTemplate("templates/email.vm", context)).build(); - } - -} \ No newline at end of file + private static final Logger log = LoggerFactory.getLogger(DigitalSigatureService.class); + private final BandanaManager bandanaManager; + private final SettingsManager settingsManager; + private final UserManager userManager; + private final LocalNotificationService notificationService; + private final MailServerManager mailServerManager; + private final ContextHelper contextHelper = new ContextHelper(); + private final transient Markdown markdown = new Markdown(); + private final PageManager pageManager; + private I18nResolver i18nResolver; + + public DigitalSigatureService( + @ComponentImport BandanaManager bandanaManager, + @ComponentImport SettingsManager settingsManager, + @ComponentImport UserManager userManager, + @ComponentImport LocalNotificationService notificationService, + @ComponentImport MailServerManager mailServerManager, + @ComponentImport PageManager pageManager, + @ComponentImport I18nResolver i18nResolver + ) { + this.settingsManager = settingsManager; + this.bandanaManager = bandanaManager; + this.notificationService = notificationService; + this.userManager = userManager; + this.mailServerManager = mailServerManager; + this.pageManager = pageManager; + this.i18nResolver = i18nResolver; + } + + @GET + @Path("sign") + public Response sign(@QueryParam("key") final String key, @Context UriInfo uriInfo) { + ConfluenceUser confluenceUser = AuthenticatedUserThreadLocal.get(); + String userName = confluenceUser.getName(); + Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); + if (!signature.sign(userName)) { + status(Response.Status.BAD_REQUEST) + .entity(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.error.badUser", userName, key)) + .type(MediaType.TEXT_PLAIN) + .build(); + } + bandanaManager.setValue(GLOBAL_CONTEXT, key, signature); + + String baseUrl = settingsManager.getGlobalSettings().getBaseUrl(); + for (String notifiedUser : signature.getNotify()) { + notify(notifiedUser, confluenceUser, signature, baseUrl); + } + Page parentPage = pageManager.getPage(signature.getPageId()); + Page protectedPage = pageManager.getPage(parentPage.getSpaceKey(), signature.getProtectedKey()); + if (protectedPage != null) { + protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, confluenceUser)); + pageManager.saveContentEntity(protectedPage, null); + } + URI pageUri = create(settingsManager.getGlobalSettings().getBaseUrl() + "/pages/viewpage.action?pageId=" + signature.getPageId()); + return temporaryRedirect(pageUri).build(); + } + + private void notify(final String notifiedUser, ConfluenceUser signedUser, final Signature signature, final String baseUrl) { + try { + UserProfile notifiedUserProfile = contextHelper.getProfileNotNull(userManager, notifiedUser); + + String user = format("%s", + baseUrl + "/display/~" + signedUser.getName(), + signedUser.getFullName() + ); + String document = format("%s", + baseUrl + "/pages/viewpage.action?pageId=" + signature.getPageId(), + signature.getTitle() + ); + String html = i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort", user, document); + if (signature.isMaxSignaturesReached()) { + html = html + "
" + i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.warning.maxSignaturesReached", signature.getMaxSignatures()); + } + String titleText = i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort", signedUser.getFullName(), signature.getTitle()); + + notificationService.createOrUpdate(notifiedUser, new NotificationBuilder() + .application(PLUGIN_KEY) // a unique key that identifies your plugin + .title(titleText) + .itemTitle(titleText) + .description(html) + .groupingId(PLUGIN_KEY + "-signature") // a key to aggregate notifications + .createNotification()).get(); + + SMTPMailServer mailServer = mailServerManager.getDefaultSMTPMailServer(); + + if (mailServer == null) { + log.warn("No default SMTP server found -> no signature notification sent."); + } else if (!contextHelper.hasEmail(notifiedUserProfile)) { + log.warn(notifiedUser + " is to be notified but has no email address. Skipping email notification"); + } else { + mailServer.send( + new Email(notifiedUserProfile.getEmail()) + .setSubject(titleText) + .setBody(html) + .setMimeType("text/html") + ); + } + } catch (IllegalArgumentException e) { + log.error("Could not send notification to " + notifiedUser, e); + } catch (InterruptedException e) { + log.error("Could not send notification to " + notifiedUser, e); + } catch (MailException e) { + log.error("Could not send notification to " + notifiedUser, e); + } catch (ExecutionException e) { + log.error("Could not send notification to " + notifiedUser, e); + } + } + + + @GET + @Path("export") + @Produces("text/html; charset=UTF-8") + @HtmlSafe + public String export(@QueryParam("key") final String key) { + Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); + + Map context = defaultVelocityContext(); + context.put("signature", signature); + context.put("markdown", markdown); + Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); + Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); + context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); + context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); + context.put("profiles", contextHelper.union(signed, missing)); + + context.put("currentDate", new Date()); + context.put("date", new DateTool()); + + return getRenderedTemplate("templates/export.vm", context); + } + + @GET + @Path("emails") + @Produces("text/html; charset=UTF-8") + public Response emails(@QueryParam("key") final String key, @QueryParam("signed") final boolean signed, @QueryParam("emailOnly") final boolean emailOnly, @Context UriInfo uriInfo) { + Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); + Map profiles = contextHelper.getProfiles(userManager, signed ? signature.getSignatures().keySet() : signature.getMissingSignatures()); + + Map context = defaultVelocityContext(); + context.put("signature", signature); + String signatureText = format("%s ( %s )", signature.getTitle(), signature.getHash()); + String rawTemplate = signed ? + i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails") : + i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.unsignedUsersEmails"); + context.put("signedOrNotWithHtml", MessageFormat.format(rawTemplate, "", "", signatureText)); + context.put("withNamesChecked", emailOnly ? "" : "checked"); + context.put("signedChecked", signed ? "checked" : ""); + context.put("toggleWithNamesURL", uriInfo.getRequestUriBuilder().replaceQueryParam("emailOnly", !emailOnly).build()); + context.put("toggleSignedURL", uriInfo.getRequestUriBuilder().replaceQueryParam("signed", !signed).build()); + Function mapping = p -> (emailOnly ? p.getEmail() : contextHelper.mailTo(p)).trim(); + context.put("emails", profiles.values().stream() + .filter(contextHelper::hasEmail) + .map(mapping).collect(toList())); + + context.put("currentDate", new Date()); + context.put("date", new DateTool()); + return Response.ok(getRenderedTemplate("templates/email.vm", context)).build(); + } + +} diff --git a/src/main/java/com/baloise/confluence/digitalsignature/sal/DummyProfile.java b/src/main/java/com/baloise/confluence/digitalsignature/sal/DummyProfile.java index ebe1051..ac26213 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/sal/DummyProfile.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/sal/DummyProfile.java @@ -1,51 +1,51 @@ package com.baloise.confluence.digitalsignature.sal; -import java.net.URI; - import com.atlassian.sal.api.user.UserKey; import com.atlassian.sal.api.user.UserProfile; +import java.net.URI; + public class DummyProfile implements UserProfile { - private String userKey; - - public DummyProfile(String userKey) { - this.userKey = userKey; - } - - @Override - public UserKey getUserKey() { - return new UserKey(userKey); - } - - @Override - public String getUsername() { - return userKey; - } - - @Override - public String getFullName() { - return userKey; - } - - @Override - public String getEmail() { - return ""; - } - - @Override - public URI getProfilePictureUri(int width, int height) { - return null; - } - - @Override - public URI getProfilePictureUri() { - return null; - } - - @Override - public URI getProfilePageUri() { - return null; - } + private String userKey; + + public DummyProfile(String userKey) { + this.userKey = userKey; + } + + @Override + public UserKey getUserKey() { + return new UserKey(userKey); + } + + @Override + public String getUsername() { + return userKey; + } + + @Override + public String getFullName() { + return userKey; + } + + @Override + public String getEmail() { + return ""; + } + + @Override + public URI getProfilePictureUri(int width, int height) { + return null; + } + + @Override + public URI getProfilePictureUri() { + return null; + } + + @Override + public URI getProfilePageUri() { + return null; + } } diff --git a/src/main/resources/META-INF/spring/plugin-context.xml b/src/main/resources/META-INF/spring/plugin-context.xml index b1f0519..8f0fba7 100644 --- a/src/main/resources/META-INF/spring/plugin-context.xml +++ b/src/main/resources/META-INF/spring/plugin-context.xml @@ -7,4 +7,4 @@ http://www.atlassian.com/schema/atlassian-scanner http://www.atlassian.com/schema/atlassian-scanner/atlassian-scanner.xsd"> - \ No newline at end of file + diff --git a/src/main/resources/digital-signature.properties b/src/main/resources/digital-signature.properties index eb3e6f3..8c615c9 100644 --- a/src/main/resources/digital-signature.properties +++ b/src/main/resources/digital-signature.properties @@ -4,7 +4,7 @@ com.baloise.confluence.digital-signature.signature.desc=Embeds a signature panel com.baloise.confluence.digital-signature.signature.param.title.label=Panel Title com.baloise.confluence.digital-signature.signature.param.title.desc=Text displayed at the top of the signature panel. com.baloise.confluence.digital-signature.signature.param.signers.label=Signatories -com.baloise.confluence.digital-signature.signature.param.signers.desc=Users who can sign the text within the panel, in addition to members of signatory groups (below) and signatories inherited from page permissions (below). +com.baloise.confluence.digital-signature.signature.param.signers.desc=Users who can sign the text within the panel, in addition to members of signatory groups (below) and signatories inherited from page permissions (below). com.baloise.confluence.digital-signature.signature.param.signerGroups.label=Signatory Groups com.baloise.confluence.digital-signature.signature.param.signerGroups.desc=Comma-separated list of Confluence groups whose members may sign the panel in addition to named signatories (above) and signatories inherited from page permissions (below). Group names must be entered exactly (e.g. group-name). Fill in * (asterisk) to permit any logged-in user who may view the page to sign. com.baloise.confluence.digital-signature.signature.param.inheritSigners.label=Inherit Signatories from Page Permissions diff --git a/src/main/resources/digital-signature_de.properties b/src/main/resources/digital-signature_de.properties index 22395a4..41d2c29 100644 --- a/src/main/resources/digital-signature_de.properties +++ b/src/main/resources/digital-signature_de.properties @@ -4,7 +4,7 @@ com.baloise.confluence.digital-signature.signature.desc=F com.baloise.confluence.digital-signature.signature.param.title.label=Titel com.baloise.confluence.digital-signature.signature.param.title.desc=Titel des unterzeichneten Bereichs. com.baloise.confluence.digital-signature.signature.param.signers.label=Unterzeichnende Benutzer -com.baloise.confluence.digital-signature.signature.param.signers.desc=Einzelne Benutzer, welche den Bereich unterzeichnen können. Zusätzlich zu den unterzeichnenden Gruppen und aus Seitenbeschränkungen vererbten Unterzeichnenden (siehe Unten). +com.baloise.confluence.digital-signature.signature.param.signers.desc=Einzelne Benutzer, welche den Bereich unterzeichnen können. Zusätzlich zu den unterzeichnenden Gruppen und aus Seitenbeschränkungen vererbten Unterzeichnenden (siehe Unten). com.baloise.confluence.digital-signature.signature.param.signerGroups.label=Unterzeichnende Gruppen com.baloise.confluence.digital-signature.signature.param.signerGroups.desc=Kommagetrennte Liste von Confluence Gruppen deren Mitglieder den Bereich unterzeichnen können. Zusätzlich zu den unterzeichnenden Benutzern (siehe oben) und aus Seitenbeschränkungen vererbten Unterzeichnenden (siehe Unten). Gruppennamen müssen exakt eingegeben werden (z.B. Gruppen-Name). Geben Sie * (Stern) ein um allen angemeldeten Benutzern die Unterschrift zu ermöglichen. com.baloise.confluence.digital-signature.signature.param.inheritSigners.label=Aus Seitenbeschränkungen vererbte Unterzeichnende @@ -42,6 +42,6 @@ com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionR 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 com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort={0} hat {1} unterzeichnet. -com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails=Emailadressen der Benutzer, welche {2} {0}unterzeichnet{1} haben +com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails=Emailadressen der Benutzer, welche {2} {0}unterzeichnet{1} haben com.baloise.confluence.digital-signature.signature.service.message.unsignedUsersEmails=Emailadressen der Benutzer, welche {2} {0}nicht unterzeichnet{1} haben -com.baloise.confluence.digital-signature.signature.service.warning.maxSignaturesReached=Die maximale Anzahl von {0} Unterschriften wurde erreicht. \ No newline at end of file +com.baloise.confluence.digital-signature.signature.service.warning.maxSignaturesReached=Die maximale Anzahl von {0} Unterschriften wurde erreicht. diff --git a/src/main/resources/templates/email.vm b/src/main/resources/templates/email.vm index bbdaa3f..0ae5326 100644 --- a/src/main/resources/templates/email.vm +++ b/src/main/resources/templates/email.vm @@ -1,12 +1,14 @@ #set( $dateFormatter = $action.getDateFormatter()) $signedOrNotWithHtml
- +
- +
-#foreach( $email in $emails)
+    #foreach( $email in $emails)
 $email
 #end
 
diff --git a/src/main/resources/templates/export.vm b/src/main/resources/templates/export.vm index e357750..dae8695 100644 --- a/src/main/resources/templates/export.vm +++ b/src/main/resources/templates/export.vm @@ -1,31 +1,32 @@ #set( $dateFormatter = $action.getDateFormatter())

$signature.getTitle()

#set($bodyWithHtml = $markdown.toHTML($signature.getBody()))

$bodyWithHtml

-#foreach ($date2userName in $orderedSignatures) - #set( $userName = $date2userName.key) - #set( $profile = $profiles.get($userName)) - - - - - -#end -#foreach( $profile in $orderedMissingSignatureProfiles) - - - - - -#end + #foreach ($date2userName in $orderedSignatures) + #set( $userName = $date2userName.key) + #set( $profile = $profiles.get($userName)) + + + + + + #end + #foreach( $profile in $orderedMissingSignatureProfiles) + + + + + + #end
$dateFormatter.formatDateTime($date2userName.value)$profile.getFullName()$profile.getEmail()
$profile.getFullName()$profile.getEmail()
$dateFormatter.formatDateTime($date2userName.value)$profile.getFullName()$profile.getEmail()
$profile.getFullName()$profile.getEmail()
diff --git a/src/main/resources/templates/macro.vm b/src/main/resources/templates/macro.vm index 492fb64..4676be3 100644 --- a/src/main/resources/templates/macro.vm +++ b/src/main/resources/templates/macro.vm @@ -2,48 +2,70 @@ #set( $title = $signature.getTitle()) #if( $panel )
- +
#else - $title + $title #end #set($bodyWithHtml = $markdown.toHTML($signature.getBody())) -

$bodyWithHtml

-
    - #foreach ($date2userName in $orderedSignatures) - #set( $userName = $date2userName.key) - #set( $profile = $profiles.get($userName)) -
  • $dateFormatter.formatDateTime($date2userName.value) - $profile.getFullName()
  • - #end - #foreach( $profile in $orderedMissingSignatureProfiles) -
  • $profile.getFullName()
  • - #end - #if($signAs) -
  • - #end -
+

$bodyWithHtml

+
    + #foreach ($date2userName in $orderedSignatures) + #set( $userName = $date2userName.key) + #set( $profile = $profiles.get($userName)) +
  • $dateFormatter.formatDateTime($date2userName.value) - $profile.getFullName()
  • + #end + #foreach( $profile in $orderedMissingSignatureProfiles) +
  • $profile.getFullName() +
  • + #end + #if($signAs) +
  • +
    + +
    +
  • + #end +
#if( $panel )
#end diff --git a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java index baef0e8..5bba5e9 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java @@ -1,65 +1,62 @@ package com.baloise.confluence.digitalsignature; +import com.atlassian.confluence.setup.BootstrapManager; +import com.atlassian.sal.api.user.UserProfile; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.util.ArrayList; -import java.util.List; +public class DigitalSignatureMacroTest { -import org.junit.Test; -import org.mockito.Mockito; + Signature signature = new Signature(1, "test", "title"); -import com.atlassian.confluence.setup.BootstrapManager; -import com.atlassian.sal.api.user.UserProfile; + BootstrapManager bootstrapManager = mock(BootstrapManager.class); -public class DigitalSignatureMacroTest { + @Test + public void getMailtoLong() { + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); + List profiles = new ArrayList(); + UserProfile profile = Mockito.mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + for (int i = 0; i < 20; i++) { + profiles.add(profile); + } + String mailto = macro.getMailto(profiles, "Subject", true, null); + assertEquals("mailto:heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com?Subject=Subject", mailto); + } + + @Test + public void getMailtoVeryLong() { + Mockito.when(bootstrapManager.getWebAppContextPath()).thenReturn("nirvana"); + + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, bootstrapManager, null, null, null, null); + List profiles = new ArrayList(); + UserProfile profile = Mockito.mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + for (int i = 0; i < 200; i++) { + profiles.add(profile); + } + String mailto = macro.getMailto(profiles, "Subject", true, signature); + assertEquals("nirvana/rest/signature/1.0/emails?key=signature.3224a4d6bba68cd0ece9b64252f8bf5677e24cf6b7c5f543e3176d419d34d517&signed=true", mailto); + } - Signature signature = new Signature(1, "test", "title"); - - BootstrapManager bootstrapManager = mock(BootstrapManager.class); - - - @Test - public void getMailtoLong() { - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - for (int i = 0; i < 20; i++) { - profiles.add(profile); - } - String mailto = macro.getMailto(profiles , "Subject", true, null); - assertEquals("mailto:heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com?Subject=Subject", mailto); - } - - @Test - public void getMailtoVeryLong() { - Mockito.when(bootstrapManager.getWebAppContextPath()).thenReturn("nirvana"); - - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, bootstrapManager, null, null, null, null); - List profiles = new ArrayList(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - for (int i = 0; i < 200; i++) { - profiles.add(profile); - } - String mailto = macro.getMailto(profiles , "Subject", true, signature); - assertEquals("nirvana/rest/signature/1.0/emails?key=signature.3224a4d6bba68cd0ece9b64252f8bf5677e24cf6b7c5f543e3176d419d34d517&signed=true", mailto); - } - - @Test - public void getMailtoShort() { - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - profiles.add(profile); - String mailto = macro.getMailto(profiles , "Subject", true, null); - assertEquals("mailto:Heinz Meier?Subject=Subject", mailto); - } - + @Test + public void getMailtoShort() { + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); + List profiles = new ArrayList(); + UserProfile profile = Mockito.mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + profiles.add(profile); + String mailto = macro.getMailto(profiles, "Subject", true, null); + assertEquals("mailto:Heinz Meier?Subject=Subject", mailto); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java index f77ee58..e5dc561 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java @@ -1,23 +1,25 @@ package com.baloise.confluence.digitalsignature; +import org.junit.Test; + import static com.baloise.confluence.digitalsignature.InheritSigners.*; import static org.junit.Assert.assertEquals; -import org.junit.Test; - public class InheritSignersTest { - @Test - public void READERS_ONLY() throws Exception { - assertEquals(READERS_ONLY, ofValue("readers only")); - } - @Test - public void NONE_NULL() throws Exception { - assertEquals(NONE, ofValue(null)); - } - @Test - public void NONE_IllegalArgument() throws Exception { - assertEquals(NONE, ofValue("asdasd")); - } + @Test + public void READERS_ONLY() throws Exception { + assertEquals(READERS_ONLY, ofValue("readers only")); + } + + @Test + public void NONE_NULL() throws Exception { + assertEquals(NONE, ofValue(null)); + } + + @Test + public void NONE_IllegalArgument() throws Exception { + assertEquals(NONE, ofValue("asdasd")); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java b/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java index 0604eb5..83b5f6b 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java @@ -1,40 +1,40 @@ package com.baloise.confluence.digitalsignature; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; + import static java.nio.file.Files.readAllLines; import static java.nio.file.Paths.get; import static java.util.stream.Collectors.joining; import static org.junit.Assert.assertEquals; -import java.io.IOException; -import java.net.URISyntaxException; -import org.junit.Before; -import org.junit.Test; +public class MarkdownTest { -public class MarkdownTest { + Markdown markdown; + + @Before + public void setUp() { + markdown = new Markdown(); + } + + + @Test + public void testToHTML() throws Exception { + assertEquals("

This is Sparta

\n", markdown.toHTML("This is *Sparta*")); + assertEquals("

Link

\n", markdown.toHTML("[Link](http://a.com)")); + assertEquals("

\n", markdown.toHTML("![Image](http://url/a.png)")); + assertEquals("

<b></b>

\n", markdown.toHTML("")); + assertEquals(readResource("commonmark.html").trim(), markdown.toHTML(readResource("commonmark.md")).trim()); + } + - - Markdown markdown; - - @Before - public void setUp() { - markdown = new Markdown(); - } - - - @Test - public void testToHTML() throws Exception { - assertEquals("

This is Sparta

\n", markdown.toHTML("This is *Sparta*")); - assertEquals("

Link

\n", markdown.toHTML("[Link](http://a.com)")); - assertEquals("

\n", markdown.toHTML("![Image](http://url/a.png)")); - assertEquals("

<b></b>

\n", markdown.toHTML("")); - assertEquals(readResource("commonmark.html").trim(), markdown.toHTML(readResource("commonmark.md")).trim()); - } - - - private String readResource(String name) throws IOException, URISyntaxException { - return readAllLines(get(getClass().getResource("/"+name).toURI())).stream().collect(joining("\n")); - } + private String readResource(String name) throws IOException, URISyntaxException { + return readAllLines(get(getClass().getResource("/" + name).toURI())).stream().collect(joining("\n")); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java index 09a2610..a1e2fd2 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java @@ -1,21 +1,21 @@ package com.baloise.confluence.digitalsignature; -import static org.junit.Assert.*; +import org.junit.Test; import java.text.MessageFormat; -import org.junit.Test; +import static org.junit.Assert.*; public class MessageFormatTest { - @Test - public void test() { - String rawTemplate = "Email addresses of users who {0}signed{1} {2}"; - String actual = MessageFormat.format(rawTemplate, "", "", "#123"); - assertEquals("Email addresses of users who signed #123", actual); - rawTemplate = "{2} was {0}signed{1}"; - actual = MessageFormat.format(rawTemplate, "", "", "#123"); - assertEquals("#123 was signed", actual); - } + @Test + public void test() { + String rawTemplate = "Email addresses of users who {0}signed{1} {2}"; + String actual = MessageFormat.format(rawTemplate, "", "", "#123"); + assertEquals("Email addresses of users who signed #123", actual); + rawTemplate = "{2} was {0}signed{1}"; + actual = MessageFormat.format(rawTemplate, "", "", "#123"); + assertEquals("#123 was signed", actual); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java index e5ee2dc..c72489f 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java @@ -1,7 +1,7 @@ package com.baloise.confluence.digitalsignature; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import jdk.nashorn.internal.ir.annotations.Ignore; +import org.junit.Test; import java.io.FileOutputStream; import java.io.IOException; @@ -9,35 +9,34 @@ import java.io.ObjectOutputStream; import java.util.Date; -import org.junit.Test; - -import jdk.nashorn.internal.ir.annotations.Ignore; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class SignatureSerialisationTest { - @Test - public void deserialise() throws IOException, ClassNotFoundException { - ObjectInputStream in = new ObjectInputStream(getClass().getResourceAsStream("/signature.ser")); - Signature signature = (Signature) in.readObject(); - in.close(); - assertEquals("signature.a077cdcc5bfcf275fe447ae2c609c1c361331b4e90cb85909582e0d824cbc5b3", signature.getKey()); - assertEquals("[missing1, missing2]", signature.getMissingSignatures().toString()); - assertEquals(1, signature.getSignatures().size()); - assertTrue( signature.getSignatures().containsKey("signed1")); - assertEquals(9999, signature.getSignatures().get("signed1").getTime()); - } - - @Test - @Ignore - public void serialise() throws IOException { - Signature signature = new Signature(123L, "body", "title"); - signature.getNotify().add("notify1"); - signature.getMissingSignatures().add("missing1"); - signature.getMissingSignatures().add("missing2"); - signature.getSignatures().put("signed1", new Date(9999)); - ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/test/resources/signature.ser")); - out.writeObject(signature); - out.close(); - } + @Test + public void deserialise() throws IOException, ClassNotFoundException { + ObjectInputStream in = new ObjectInputStream(getClass().getResourceAsStream("/signature.ser")); + Signature signature = (Signature) in.readObject(); + in.close(); + assertEquals("signature.a077cdcc5bfcf275fe447ae2c609c1c361331b4e90cb85909582e0d824cbc5b3", signature.getKey()); + assertEquals("[missing1, missing2]", signature.getMissingSignatures().toString()); + assertEquals(1, signature.getSignatures().size()); + assertTrue(signature.getSignatures().containsKey("signed1")); + assertEquals(9999, signature.getSignatures().get("signed1").getTime()); + } + + @Test + @Ignore + public void serialise() throws IOException { + Signature signature = new Signature(123L, "body", "title"); + signature.getNotify().add("notify1"); + signature.getMissingSignatures().add("missing1"); + signature.getMissingSignatures().add("missing2"); + signature.getSignatures().put("signed1", new Date(9999)); + ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/test/resources/signature.ser")); + out.writeObject(signature); + out.close(); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java index 8bbe1d4..133fcbd 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java @@ -1,48 +1,48 @@ package com.baloise.confluence.digitalsignature; -import static org.apache.velocity.app.Velocity.mergeTemplate; - -import java.io.BufferedWriter; -import java.io.StringWriter; -import java.io.Writer; - import org.apache.velocity.VelocityContext; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.junit.Test; +import java.io.BufferedWriter; +import java.io.StringWriter; +import java.io.Writer; + +import static org.apache.velocity.app.Velocity.mergeTemplate; + public class TemplatesTest { - @Test - public void test() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { - StringWriter sw = new StringWriter(); - //let's buffer Writer for better performace: - Writer writer = new BufferedWriter(sw); - VelocityContext context = new VelocityContext(); - //add your parameters to context - mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); - writer.flush(); - String result = sw.toString(); - System.out.println(result); - } - - @Test - public void test2() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { - StringWriter sw = new StringWriter(); - //let's buffer Writer for better performace: - Writer writer = new BufferedWriter(sw); - VelocityContext context = new VelocityContext(); - //add your parameters to context - mergeTemplate("src/main/resources/templates/export.vm", "UTF-8", context, writer); - writer.flush(); - String result = sw.toString(); - System.out.println(result); - } - - @Test - public void foo() { - System.out.println("https://test-confluence.baloisenet.com/atlassian/rest/signature/1.0/".split("rest/")[0]); - } + @Test + public void test() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { + StringWriter sw = new StringWriter(); + //let's buffer Writer for better performace: + Writer writer = new BufferedWriter(sw); + VelocityContext context = new VelocityContext(); + //add your parameters to context + mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); + writer.flush(); + String result = sw.toString(); + System.out.println(result); + } + + @Test + public void test2() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { + StringWriter sw = new StringWriter(); + //let's buffer Writer for better performace: + Writer writer = new BufferedWriter(sw); + VelocityContext context = new VelocityContext(); + //add your parameters to context + mergeTemplate("src/main/resources/templates/export.vm", "UTF-8", context, writer); + writer.flush(); + String result = sw.toString(); + System.out.println(result); + } + + @Test + public void foo() { + System.out.println("https://test-confluence.baloisenet.com/atlassian/rest/signature/1.0/".split("rest/")[0]); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java b/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java index 7d74372..6f21845 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java @@ -1,32 +1,31 @@ package com.baloise.confluence.digitalsignature; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; +import com.atlassian.sal.api.user.UserProfile; +import org.junit.Test; +import org.mockito.Mockito; import java.util.SortedSet; import java.util.TreeSet; -import org.junit.Test; -import org.mockito.Mockito; - -import com.atlassian.sal.api.user.UserProfile; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; public class UserProfileByNameTest { - @Test - public void testCompare() throws Exception { - UserProfile profile1 = Mockito.mock(UserProfile.class); - when(profile1.getFullName()).thenReturn("Heinz Meier"); - when(profile1.getEmail()).thenReturn("heinz.meier@meier.com"); - when(profile1.toString()).thenReturn("Heinz Meier"); - UserProfile profile2 = Mockito.mock(UserProfile.class); - when(profile2.getFullName()).thenReturn("Abraham Aebischer"); - when(profile2.getEmail()).thenReturn("Abraham Aebischer@meier.com"); - when(profile2.toString()).thenReturn("Abraham Aebischer"); - SortedSet profiles = new TreeSet(new UserProfileByName()); - profiles.add(profile1); - profiles.add(profile2); - profiles.add(profile1); - assertEquals("[Abraham Aebischer, Heinz Meier]", profiles.toString()); - } + @Test + public void testCompare() throws Exception { + UserProfile profile1 = Mockito.mock(UserProfile.class); + when(profile1.getFullName()).thenReturn("Heinz Meier"); + when(profile1.getEmail()).thenReturn("heinz.meier@meier.com"); + when(profile1.toString()).thenReturn("Heinz Meier"); + UserProfile profile2 = Mockito.mock(UserProfile.class); + when(profile2.getFullName()).thenReturn("Abraham Aebischer"); + when(profile2.getEmail()).thenReturn("Abraham Aebischer@meier.com"); + when(profile2.toString()).thenReturn("Abraham Aebischer"); + SortedSet profiles = new TreeSet(new UserProfileByName()); + profiles.add(profile1); + profiles.add(profile2); + profiles.add(profile1); + assertEquals("[Abraham Aebischer, Heinz Meier]", profiles.toString()); + } } diff --git a/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java b/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java index 21ae6eb..2ef29c0 100644 --- a/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java +++ b/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java @@ -14,4 +14,4 @@ public void testMyName() DigitalSignatureComponent component = new DigitalSignatureComponentImpl(null); assertEquals("names do not match!", "digitalSignatureComponent",component.getName()); } -} \ No newline at end of file +} diff --git a/src/test/resources/signature.ser b/src/test/resources/signature.ser index bb1b2bf22191927a6362a117688b5ba54538738b..34c8323f95b0c3cdd10b8ad824ffb6c5239134dd 100644 GIT binary patch delta 80 zcmbQn@|R_TvmmDz18;6(MQ~<%USdgUQEKr-7j-U{jKt!MLWVj9#)+BvQvacV0RpN^ a7+8|>Qz}as943BonD~4WBgf<_#yJ3;vmQGD delta 40 rcmey%GL2<|Gb8)N5cP@ex%> Date: Tue, 12 May 2020 10:25:35 +0200 Subject: [PATCH 02/15] syntactic refactoring --- .../digitalsignature/ContextHelper.java | 26 ++--- .../DigitalSignatureMacro.java | 110 ++++++++---------- .../digitalsignature/InheritSigners.java | 7 +- .../confluence/digitalsignature/Markdown.java | 1 - .../digitalsignature/Signature.java | 29 +++-- .../digitalsignature/SignaturesVisible.java | 6 +- .../digitalsignature/UserProfileByName.java | 3 + .../api/DigitalSignatureComponent.java | 2 +- .../rest/DigitalSigatureService.java | 38 +++--- .../DigitalSignatureMacroTest.java | 6 +- .../digitalsignature/InheritSignersTest.java | 8 +- .../digitalsignature/MarkdownTest.java | 11 +- .../digitalsignature/MessageFormatTest.java | 2 - .../SignatureSerialisationTest.java | 9 +- .../digitalsignature/TemplatesTest.java | 28 ++--- .../UserProfileByNameTest.java | 4 +- .../digitalsignature/MyComponentUnitTest.java | 8 +- 17 files changed, 128 insertions(+), 170 deletions(-) diff --git a/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java b/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java index 9b94410..e610b22 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/ContextHelper.java @@ -6,33 +6,30 @@ import java.util.*; import java.util.Map.Entry; +import java.util.function.Function; import static java.lang.String.format; public class ContextHelper { public Object getOrderedSignatures(Signature signature) { - Comparator> comparator = new Comparator>() { - @Override - public int compare(Entry s1, Entry s2) { - int ret = s1.getValue().compareTo(s2.getValue()); - return ret == 0 ? s1.getKey().compareTo(s2.getKey()) : ret; - } - }; - SortedSet> ret = new TreeSet>(comparator); + SortedSet> ret = new TreeSet<>(Comparator.comparing((Function, Date>) Entry::getValue) + .thenComparing(Entry::getKey)); ret.addAll(signature.getSignatures().entrySet()); return ret; } - public Map union(Map... maps) { - Map union = new HashMap(); + @SafeVarargs + public final Map union(Map... maps) { + Map union = new HashMap<>(); for (Map map : maps) { union.putAll(map); } return union; } - public Set union(Set... sets) { - Set union = new HashSet(); + @SafeVarargs + public final Set union(Set... sets) { + Set union = new HashSet<>(); for (Set set : sets) { union.addAll(set); } @@ -40,7 +37,7 @@ public Set union(Set... sets) { } public Map getProfiles(UserManager userManager, Set userNames) { - Map ret = new HashMap(); + Map ret = new HashMap<>(); if (Signature.isPetitionMode(userNames)) return ret; for (String userName : userNames) { ret.put(userName, getProfileNotNull(userManager, userName)); @@ -54,7 +51,7 @@ public UserProfile getProfileNotNull(UserManager userManager, String userName) { } public SortedSet getOrderedProfiles(UserManager userManager, Set userNames) { - SortedSet ret = new TreeSet(new UserProfileByName()); + SortedSet ret = new TreeSet<>(new UserProfileByName()); if (Signature.isPetitionMode(userNames)) return ret; for (String userName : userNames) { ret.add(getProfileNotNull(userManager, userName)); @@ -69,5 +66,4 @@ public String mailTo(UserProfile profile) { public boolean hasEmail(UserProfile profile) { return profile != null && profile.getEmail() != null && !profile.getEmail().trim().isEmpty(); } - } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index 3cafbba..2506a19 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -5,7 +5,6 @@ import com.atlassian.confluence.core.ContentEntityObject; import com.atlassian.confluence.core.DefaultSaveContext; import com.atlassian.confluence.macro.Macro; -import com.atlassian.confluence.macro.MacroExecutionException; import com.atlassian.confluence.pages.Page; import com.atlassian.confluence.pages.PageManager; import com.atlassian.confluence.security.ContentPermission; @@ -29,6 +28,7 @@ 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; @@ -42,21 +42,20 @@ @Scanned public class DigitalSignatureMacro implements Macro { + private final int MAX_MAILTO_CHARACTER_COUNT = 500; + private final String REST_PATH = "/rest/signature/1.0"; + private final String DISPLAY_PATH = "/display"; + private final transient Markdown markdown = new Markdown(); + private final PermissionManager permissionManager; + private final Set all = new HashSet<>(); private BandanaManager bandanaManager; private UserManager userManager; private BootstrapManager bootstrapManager; private PageManager pageManager; - private final String REST_PATH = "/rest/signature/1.0"; - private final String DISPLAY_PATH = "/display"; private ContextHelper contextHelper = new ContextHelper(); - private final transient Markdown markdown = new Markdown(); - private final PermissionManager permissionManager; private GroupManager groupManager; - private final Set all = new HashSet(); - final int MAX_MAILTO_CHARACTER_COUNT = 500; private I18nResolver i18nResolver; - @Autowired public DigitalSignatureMacro( @ComponentImport BandanaManager bandanaManager, @@ -78,7 +77,7 @@ public DigitalSignatureMacro( } @Override - public String execute(Map params, String body, ConversionContext conversionContext) throws MacroExecutionException { + public String execute(Map params, String body, ConversionContext conversionContext) { if (body != null && body.length() > 10) { Set userGroups = getSet(params, "signerGroups"); boolean petitionMode = Signature.isPetitionMode(userGroups); @@ -93,8 +92,8 @@ public String execute(Map params, String body, ConversionContext entity.getLatestVersionId(), body, params.get("title")) - .withNotified(getSet(params, "notified")) - .withMaxSignatures(getLong(params, "maxSignatures", -1)), + .withNotified(getSet(params, "notified")) + .withMaxSignatures(getLong(params, "maxSignatures", -1)), signers ); ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); @@ -159,44 +158,27 @@ public String execute(Map params, String body, ConversionContext return getRenderedTemplate("templates/macro.vm", context); } return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort")); - - } private boolean hideSignatures(Map params, Signature signature, String currentUserName) { - boolean pendingVisible = true; - boolean signaturesVisible = true; - switch (SignaturesVisible.ofValue(params.get("pendingVisible"))) { - case IF_SIGNATORY: - if (!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { - pendingVisible = false; - } - break; - case IF_SIGNED: - if (!signature.hasSigned(currentUserName)) { - pendingVisible = false; - } - break; - case ALWAYS: - break; - } - switch (SignaturesVisible.ofValue(params.get("signaturesVisible"))) { + 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()); + return pendingVisible && signaturesVisible; + } + + private boolean isVisible(Signature signature, String currentUserName, String signaturesVisibleParam) { + switch (SignaturesVisible.ofValue(signaturesVisibleParam)) { case IF_SIGNATORY: - if (!signature.hasSigned(currentUserName) && !signature.isSignatory(currentUserName)) { - signaturesVisible = false; - } - break; + return signature.hasSigned(currentUserName) || signature.isSignatory(currentUserName); case IF_SIGNED: - if (!signature.hasSigned(currentUserName)) { - signaturesVisible = false; - } - break; + return signature.hasSigned(currentUserName); case ALWAYS: - break; + return true; + default: + throw new InvalidParameterException(String.format("'%s' is an unknown value of SignaturesVisible!", signaturesVisibleParam)); } - if (!pendingVisible) signature.setMissingSignatures(emptySet()); - if (!signaturesVisible) signature.setSignatures(emptyMap()); - return pendingVisible && signaturesVisible; } private boolean isPage(ConversionContext conversionContext) { @@ -205,35 +187,37 @@ private boolean isPage(ConversionContext conversionContext) { private String warning(String message) { return "
\n" + - "

\n" + - " " + i18nResolver.getText("com.baloise.confluence.digital-signature.signature.label") + "\n" + - "

\n" + - "

" + message + "

\n" + - "
"; + "

\n" + + " " + i18nResolver.getText("com.baloise.confluence.digital-signature.signature.label") + "\n" + + "

\n" + + "

" + message + "

\n" + + ""; } private Set loadInheritedSigners(InheritSigners inheritSigners, ConversionContext conversionContext) { - Set users = new HashSet(); + Set users = new HashSet<>(); switch (inheritSigners) { case READERS_AND_WRITERS: - users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); - users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + users.addAll(loadUsers(conversionContext, VIEW_PERMISSION)); + users.addAll(loadUsers(conversionContext, EDIT_PERMISSION)); break; case READERS_ONLY: - users.addAll(loadUsers(conversionContext, ContentPermission.VIEW_PERMISSION)); - users.removeAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + users.addAll(loadUsers(conversionContext, VIEW_PERMISSION)); + users.removeAll(loadUsers(conversionContext, EDIT_PERMISSION)); break; case WRITERS_ONLY: - users.addAll(loadUsers(conversionContext, ContentPermission.EDIT_PERMISSION)); + users.addAll(loadUsers(conversionContext, EDIT_PERMISSION)); break; case NONE: break; + default: + throw new IllegalArgumentException(inheritSigners + " is unknown or not yet implemented!"); } return users; } private Set loadUsers(ConversionContext conversionContext, String permission) { - Set users = new HashSet(); + Set users = new HashSet<>(); ContentPermissionSet contentPermissionSet = conversionContext.getEntity().getContentPermissionSet(permission); if (contentPermissionSet != null) { for (ContentPermission cp : contentPermissionSet) { @@ -249,7 +233,7 @@ private Set loadUsers(ConversionContext conversionContext, String permis } private Set loadUserGroups(Iterable groupNames) { - Set ret = new HashSet(); + Set ret = new HashSet<>(); for (String groupName : groupNames) { ret.addAll(loadUserGroup(groupName)); } @@ -257,7 +241,7 @@ private Set loadUserGroups(Iterable groupNames) { } private Set loadUserGroup(String groupName) { - Set ret = new HashSet(); + Set ret = new HashSet<>(); try { if (groupName == null) return ret; Group group = groupManager.getGroup(groupName.trim()); @@ -281,12 +265,12 @@ private Boolean getBoolean(Map params, String key, Boolean fallb private long getLong(Map params, String key, long fallback) { String value = params.get(key); - return value == null ? fallback : Long.valueOf(value); + return value == null ? fallback : Long.parseLong(value); } private Set getSet(Map params, String key) { String value = params.get(key); - return value == null || value.trim().isEmpty() ? new TreeSet() : new TreeSet(asList(value.split("[;, ]+"))); + return value == null || value.trim().isEmpty() ? new TreeSet<>() : new TreeSet<>(asList(value.split("[;, ]+"))); } private Signature sync(Signature signature, Set signers) { @@ -306,6 +290,7 @@ private Signature sync(Signature signature, Set signers) { loaded.setMissingSignatures(signature.getMissingSignatures()); save = true; } + if (loaded.getMaxSignatures() != signature.getMaxSignatures()) { loaded.setMaxSignatures(signature.getMaxSignatures()); save = true; @@ -337,14 +322,14 @@ public OutputType getOutputType() { String getMailto(Collection profiles, String subject, boolean signed, Signature signature) { if (profiles == null || profiles.isEmpty()) return null; profiles = profiles.stream() - .filter(contextHelper::hasEmail) - .collect(toList()); + .filter(contextHelper::hasEmail) + .collect(toList()); StringBuilder ret = new StringBuilder("mailto:"); for (UserProfile profile : profiles) { if (ret.length() > 7) ret.append(','); ret.append(contextHelper.mailTo(profile)); } - ret.append("?Subject=" + urlEncode(subject)); + ret.append("?Subject=").append(urlEncode(subject)); if (ret.length() > MAX_MAILTO_CHARACTER_COUNT) { ret.setLength(0); ret.append("mailto:"); @@ -352,7 +337,7 @@ String getMailto(Collection profiles, String subject, boolean signe if (ret.length() > 7) ret.append(','); ret.append(profile.getEmail().trim()); } - ret.append("?Subject=" + urlEncode(subject)); + ret.append("?Subject=").append(urlEncode(subject)); } if (ret.length() > MAX_MAILTO_CHARACTER_COUNT) { return bootstrapManager.getWebAppContextPath() + REST_PATH + "/emails?key=" + signature.getKey() + "&signed=" + signed; @@ -367,5 +352,4 @@ public String urlEncode(String string) { throw new IllegalStateException(e); } } - } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java b/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java index 95d44b9..c603032 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/InheritSigners.java @@ -1,7 +1,10 @@ package com.baloise.confluence.digitalsignature; public enum InheritSigners { - NONE, READERS_AND_WRITERS, READERS_ONLY, WRITERS_ONLY; + NONE, + READERS_AND_WRITERS, + READERS_ONLY, + WRITERS_ONLY; public static InheritSigners ofValue(String v) { try { @@ -9,7 +12,5 @@ public static InheritSigners ofValue(String v) { } catch (Exception e) { return NONE; } - } - } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java b/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java index b2855c4..2c8526f 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java @@ -5,7 +5,6 @@ import com.vladsch.flexmark.util.data.MutableDataSet; public class Markdown { - private Parser parser; private HtmlRenderer renderer; diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java index be50528..4f29cc0 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java @@ -15,9 +15,9 @@ public class Signature implements Serializable { private String title = ""; private String body = ""; private long maxSignatures = -1; - private Map signatures = new HashMap(); - private Set missingSignatures = new TreeSet(); - private Set notified = new TreeSet(); + private Map signatures = new HashMap<>(); + private Set missingSignatures = new TreeSet<>(); + private Set notified = new TreeSet<>(); public Signature() { } @@ -30,6 +30,10 @@ public Signature(long pageId, String body, String title) { key = "signature." + hash; } + public static boolean isPetitionMode(Set userGroups) { + return userGroups != null && userGroups.size() == 1 && userGroups.iterator().next().trim().equals("*"); + } + public String getHash() { if (hash == null) { hash = getKey().replace("signature.", ""); @@ -45,14 +49,14 @@ public String getKey() { return key; } - public String getProtectedKey() { - return "protected." + getHash(); - } - public void setKey(String key) { this.key = key; } + public String getProtectedKey() { + return "protected." + getHash(); + } + public long getPageId() { return pageId; } @@ -127,11 +131,8 @@ public boolean equals(Object obj) { return false; Signature other = (Signature) obj; if (key == null) { - if (other.key != null) - return false; - } else if (!key.equals(other.key)) - return false; - return true; + return other.key == null; + } else return key.equals(other.key); } public Signature withNotified(Set notified) { @@ -152,10 +153,6 @@ public boolean isPetitionMode() { return isPetitionMode(getMissingSignatures()); } - public static boolean isPetitionMode(Set userGroups) { - return userGroups != null && userGroups.size() == 1 && userGroups.iterator().next().trim().equals("*"); - } - public boolean sign(String userName) { if (!isMaxSignaturesReached() && !isPetitionMode() && !getMissingSignatures().remove(userName)) { return false; diff --git a/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java b/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java index ff1525d..417b28b 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/SignaturesVisible.java @@ -1,7 +1,9 @@ package com.baloise.confluence.digitalsignature; public enum SignaturesVisible { - ALWAYS, IF_SIGNATORY, IF_SIGNED; + ALWAYS, + IF_SIGNATORY, + IF_SIGNED; public static SignaturesVisible ofValue(String v) { try { @@ -9,7 +11,5 @@ public static SignaturesVisible ofValue(String v) { } catch (Exception e) { return ALWAYS; } - } - } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java b/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java index b0e0c1c..ea02d57 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/UserProfileByName.java @@ -10,10 +10,13 @@ public class UserProfileByName implements Comparator { public int compare(UserProfile u1, UserProfile u2) { int ret = nn(u1.getFullName()).compareTo(nn(u2.getFullName())); if (ret != 0) return ret; + ret = nn(u1.getEmail()).compareTo(nn(u2.getEmail())); if (ret != 0) return ret; + ret = nn(u1.getUsername()).compareTo(nn(u2.getUsername())); if (ret != 0) return ret; + return Integer.compare(u1.hashCode(), u2.hashCode()); } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java b/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java index 1c92bf8..3825a8e 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/api/DigitalSignatureComponent.java @@ -1,7 +1,7 @@ package com.baloise.confluence.digitalsignature.api; public interface DigitalSignatureComponent { - public final static String PLUGIN_KEY = "com.baloise.confluence:digital-signature"; + String PLUGIN_KEY = "com.baloise.confluence:digital-signature"; String getName(); } diff --git a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java index b2895e1..eca5a79 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java @@ -130,12 +130,12 @@ private void notify(final String notifiedUser, ConfluenceUser signedUser, final String titleText = i18nResolver.getText("com.baloise.confluence.digital-signature.signature.service.message.hasSignedShort", signedUser.getFullName(), signature.getTitle()); notificationService.createOrUpdate(notifiedUser, new NotificationBuilder() - .application(PLUGIN_KEY) // a unique key that identifies your plugin - .title(titleText) - .itemTitle(titleText) - .description(html) - .groupingId(PLUGIN_KEY + "-signature") // a key to aggregate notifications - .createNotification()).get(); + .application(PLUGIN_KEY) // a unique key that identifies your plugin + .title(titleText) + .itemTitle(titleText) + .description(html) + .groupingId(PLUGIN_KEY + "-signature") // a key to aggregate notifications + .createNotification()).get(); SMTPMailServer mailServer = mailServerManager.getDefaultSMTPMailServer(); @@ -151,18 +151,11 @@ private void notify(final String notifiedUser, ConfluenceUser signedUser, final .setMimeType("text/html") ); } - } catch (IllegalArgumentException e) { - log.error("Could not send notification to " + notifiedUser, e); - } catch (InterruptedException e) { - log.error("Could not send notification to " + notifiedUser, e); - } catch (MailException e) { - log.error("Could not send notification to " + notifiedUser, e); - } catch (ExecutionException e) { + } catch (IllegalArgumentException | InterruptedException | MailException | ExecutionException e) { log.error("Could not send notification to " + notifiedUser, e); } } - @GET @Path("export") @Produces("text/html; charset=UTF-8") @@ -170,15 +163,15 @@ private void notify(final String notifiedUser, ConfluenceUser signedUser, final public String export(@QueryParam("key") final String key) { Signature signature = (Signature) bandanaManager.getValue(GLOBAL_CONTEXT, key); - Map context = defaultVelocityContext(); - context.put("signature", signature); - context.put("markdown", markdown); Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); + + Map context = defaultVelocityContext(); + context.put("markdown", markdown); context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); context.put("profiles", contextHelper.union(signed, missing)); - + context.put("signature", signature); context.put("currentDate", new Date()); context.put("date", new DateTool()); @@ -196,8 +189,8 @@ public Response emails(@QueryParam("key") final String key, @QueryParam("signed" context.put("signature", signature); String signatureText = format("%s ( %s )", signature.getTitle(), signature.getHash()); String rawTemplate = signed ? - i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails") : - i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.unsignedUsersEmails"); + i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.signedUsersEmails") : + i18nResolver.getRawText("com.baloise.confluence.digital-signature.signature.service.message.unsignedUsersEmails"); context.put("signedOrNotWithHtml", MessageFormat.format(rawTemplate, "", "", signatureText)); context.put("withNamesChecked", emailOnly ? "" : "checked"); context.put("signedChecked", signed ? "checked" : ""); @@ -205,12 +198,11 @@ public Response emails(@QueryParam("key") final String key, @QueryParam("signed" context.put("toggleSignedURL", uriInfo.getRequestUriBuilder().replaceQueryParam("signed", !signed).build()); Function mapping = p -> (emailOnly ? p.getEmail() : contextHelper.mailTo(p)).trim(); context.put("emails", profiles.values().stream() - .filter(contextHelper::hasEmail) - .map(mapping).collect(toList())); + .filter(contextHelper::hasEmail) + .map(mapping).collect(toList())); context.put("currentDate", new Date()); context.put("date", new DateTool()); return Response.ok(getRenderedTemplate("templates/email.vm", context)).build(); } - } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java index 5bba5e9..fe8c3df 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java @@ -21,7 +21,7 @@ public class DigitalSignatureMacroTest { @Test public void getMailtoLong() { DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList(); + List profiles = new ArrayList<>(); UserProfile profile = Mockito.mock(UserProfile.class); when(profile.getFullName()).thenReturn("Heinz Meier"); when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); @@ -37,7 +37,7 @@ public void getMailtoVeryLong() { Mockito.when(bootstrapManager.getWebAppContextPath()).thenReturn("nirvana"); DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, bootstrapManager, null, null, null, null); - List profiles = new ArrayList(); + List profiles = new ArrayList<>(); UserProfile profile = Mockito.mock(UserProfile.class); when(profile.getFullName()).thenReturn("Heinz Meier"); when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); @@ -51,7 +51,7 @@ public void getMailtoVeryLong() { @Test public void getMailtoShort() { DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList(); + List profiles = new ArrayList<>(); UserProfile profile = Mockito.mock(UserProfile.class); when(profile.getFullName()).thenReturn("Heinz Meier"); when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); diff --git a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java index e5dc561..147280f 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java @@ -6,20 +6,18 @@ import static org.junit.Assert.assertEquals; public class InheritSignersTest { - @Test - public void READERS_ONLY() throws Exception { + public void testOfValue_READERS_ONLY() { assertEquals(READERS_ONLY, ofValue("readers only")); } @Test - public void NONE_NULL() throws Exception { + public void testOfValue_NONE_NULL() { assertEquals(NONE, ofValue(null)); } @Test - public void NONE_IllegalArgument() throws Exception { + public void testOfValue_NONE_IllegalArgument() { assertEquals(NONE, ofValue("asdasd")); } - } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java b/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java index 83b5f6b..e87b7a6 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/MarkdownTest.java @@ -8,21 +8,16 @@ import static java.nio.file.Files.readAllLines; import static java.nio.file.Paths.get; -import static java.util.stream.Collectors.joining; import static org.junit.Assert.assertEquals; - public class MarkdownTest { - - - Markdown markdown; + private Markdown markdown; @Before public void setUp() { markdown = new Markdown(); } - @Test public void testToHTML() throws Exception { assertEquals("

This is Sparta

\n", markdown.toHTML("This is *Sparta*")); @@ -32,9 +27,7 @@ public void testToHTML() throws Exception { assertEquals(readResource("commonmark.html").trim(), markdown.toHTML(readResource("commonmark.md")).trim()); } - private String readResource(String name) throws IOException, URISyntaxException { - return readAllLines(get(getClass().getResource("/" + name).toURI())).stream().collect(joining("\n")); + return String.join("\n", readAllLines(get(getClass().getResource("/" + name).toURI()))); } - } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java index a1e2fd2..2c30cae 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.*; public class MessageFormatTest { - @Test public void test() { String rawTemplate = "Email addresses of users who {0}signed{1} {2}"; @@ -17,5 +16,4 @@ public void test() { actual = MessageFormat.format(rawTemplate, "", "", "#123"); assertEquals("#123 was signed", actual); } - } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java index c72489f..79e2cc2 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java @@ -1,6 +1,5 @@ package com.baloise.confluence.digitalsignature; -import jdk.nashorn.internal.ir.annotations.Ignore; import org.junit.Test; import java.io.FileOutputStream; @@ -13,7 +12,6 @@ import static org.junit.Assert.assertTrue; public class SignatureSerialisationTest { - @Test public void deserialise() throws IOException, ClassNotFoundException { ObjectInputStream in = new ObjectInputStream(getClass().getResourceAsStream("/signature.ser")); @@ -27,8 +25,7 @@ public void deserialise() throws IOException, ClassNotFoundException { } @Test - @Ignore - public void serialise() throws IOException { + public void serialise() throws IOException, ClassNotFoundException { Signature signature = new Signature(123L, "body", "title"); signature.getNotify().add("notify1"); signature.getMissingSignatures().add("missing1"); @@ -37,6 +34,8 @@ public void serialise() throws IOException { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/test/resources/signature.ser")); out.writeObject(signature); out.close(); - } + ObjectInputStream in = new ObjectInputStream(this.getClass().getResourceAsStream("/signature.ser")); + assertEquals(signature, in.readObject()); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java index 133fcbd..0ced516 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java @@ -1,9 +1,6 @@ package com.baloise.confluence.digitalsignature; import org.apache.velocity.VelocityContext; -import org.apache.velocity.exception.MethodInvocationException; -import org.apache.velocity.exception.ParseErrorException; -import org.apache.velocity.exception.ResourceNotFoundException; import org.junit.Test; import java.io.BufferedWriter; @@ -11,38 +8,41 @@ import java.io.Writer; import static org.apache.velocity.app.Velocity.mergeTemplate; +import static org.junit.Assert.assertEquals; public class TemplatesTest { + private static String normalize(String input) { + return input.replaceAll("[\n\r]", "") + .replaceAll(" +", " ") + .replaceAll("> <", "><") + .trim(); + } @Test - public void test() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { + public void testMacroVm() throws Exception { StringWriter sw = new StringWriter(); - //let's buffer Writer for better performace: + //lets use BufferedWriter for better performance: Writer writer = new BufferedWriter(sw); VelocityContext context = new VelocityContext(); //add your parameters to context mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); writer.flush(); String result = sw.toString(); - System.out.println(result); + assertEquals("$title

$bodyWithHtml

    ", normalize(result)); } @Test - public void test2() throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, Exception { + public void testExportVm() throws Exception { StringWriter sw = new StringWriter(); - //let's buffer Writer for better performace: + //lets use BufferedWriter for better performance: Writer writer = new BufferedWriter(sw); VelocityContext context = new VelocityContext(); //add your parameters to context mergeTemplate("src/main/resources/templates/export.vm", "UTF-8", context, writer); writer.flush(); String result = sw.toString(); - System.out.println(result); - } - - @Test - public void foo() { - System.out.println("https://test-confluence.baloisenet.com/atlassian/rest/signature/1.0/".split("rest/")[0]); + assertEquals("

    $signature.getTitle()

    $bodyWithHtml

    ", + normalize(result)); } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java b/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java index 6f21845..5c731c8 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/UserProfileByNameTest.java @@ -13,7 +13,7 @@ public class UserProfileByNameTest { @Test - public void testCompare() throws Exception { + public void testCompare() { UserProfile profile1 = Mockito.mock(UserProfile.class); when(profile1.getFullName()).thenReturn("Heinz Meier"); when(profile1.getEmail()).thenReturn("heinz.meier@meier.com"); @@ -22,7 +22,7 @@ public void testCompare() throws Exception { when(profile2.getFullName()).thenReturn("Abraham Aebischer"); when(profile2.getEmail()).thenReturn("Abraham Aebischer@meier.com"); when(profile2.toString()).thenReturn("Abraham Aebischer"); - SortedSet profiles = new TreeSet(new UserProfileByName()); + SortedSet profiles = new TreeSet<>(new UserProfileByName()); profiles.add(profile1); profiles.add(profile2); profiles.add(profile1); diff --git a/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java b/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java index 2ef29c0..b3e44db 100644 --- a/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java +++ b/src/test/java/ut/com/baloise/confluence/digitalsignature/MyComponentUnitTest.java @@ -6,12 +6,10 @@ import static org.junit.Assert.assertEquals; -public class MyComponentUnitTest -{ +public class MyComponentUnitTest { @Test - public void testMyName() - { + public void testMyName() { DigitalSignatureComponent component = new DigitalSignatureComponentImpl(null); - assertEquals("names do not match!", "digitalSignatureComponent",component.getName()); + assertEquals("names do not match!", "digitalSignatureComponent", component.getName()); } } From 92e7a27d364736ea46bbdd5e6e11e4e732c1baec Mon Sep 17 00:00:00 2001 From: tiliavir Date: Tue, 12 May 2020 12:29:54 +0200 Subject: [PATCH 03/15] fixes build warnings --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index dabff8a..e3089a7 100644 --- a/pom.xml +++ b/pom.xml @@ -121,14 +121,13 @@ ${confluence.version} ${confluence.data.version} false + false ${atlassian.plugin.key} com.baloise.confluence.digitalsignature.api - org.springframework.osgi.*;resolution:="optional", - org.eclipse.gemini.blueprint.*;resolution:="optional", com.sun.mail.imap, com.sun.mail.smtp, com.sun.mail.pop3, From 9acf173aacab7fb543bfb6c569d7c07ce7c7bcd0 Mon Sep 17 00:00:00 2001 From: tiliavir Date: Tue, 12 May 2020 12:42:46 +0200 Subject: [PATCH 04/15] fixes codacy issues --- .../DigitalSignatureMacro.java | 165 ++++++++++-------- .../rest/DigitalSigatureService.java | 6 +- src/main/resources/atlassian-plugin.xml | 113 ++++++------ src/main/resources/templates/macro.vm | 44 ++++- .../digitalsignature/InheritSignersTest.java | 6 +- .../digitalsignature/TemplatesTest.java | 2 +- 6 files changed, 191 insertions(+), 145 deletions(-) diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index 2506a19..4ad6b8d 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -24,6 +24,7 @@ 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; @@ -32,7 +33,9 @@ import java.util.*; import static com.atlassian.confluence.renderer.radeox.macros.MacroUtils.defaultVelocityContext; -import static com.atlassian.confluence.security.ContentPermission.*; +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; @@ -78,86 +81,98 @@ public DigitalSignatureMacro( @Override public String execute(Map params, String body, ConversionContext conversionContext) { - if (body != null && body.length() > 10) { - Set userGroups = getSet(params, "signerGroups"); - boolean petitionMode = Signature.isPetitionMode(userGroups); - @SuppressWarnings("unchecked") - Set signers = petitionMode ? all : contextHelper.union( - getSet(params, "signers"), - loadUserGroups(userGroups), - loadInheritedSigners(InheritSigners.ofValue(params.get("inheritSigners")), conversionContext) - ); - ContentEntityObject entity = conversionContext.getEntity(); - Signature signature = sync(new Signature( - entity.getLatestVersionId(), - body, - params.get("title")) - .withNotified(getSet(params, "notified")) - .withMaxSignatures(getLong(params, "maxSignatures", -1)), - signers - ); - ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); - String currentUserName = currentUser.getName(); - - boolean protectedContent = getBoolean(params, "protectedContent", false); - boolean protectedContentAccess = protectedContent && (permissionManager.hasPermission(currentUser, Permission.EDIT, entity) || signature.hasSigned(currentUserName)); - - if (protectedContent && isPage(conversionContext)) { - Page protectedPage = pageManager.getPage(conversionContext.getSpaceKey(), signature.getProtectedKey()); - if (protectedPage == null) { - Page page = (Page) entity; - ContentPermissionSet editors = page.getContentPermissionSet(EDIT_PERMISSION); - if (editors == null || editors.size() == 0) { - return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent", "")); - } - protectedPage = new Page(); - protectedPage.setSpace(page.getSpace()); - protectedPage.setParentPage(page); - protectedPage.setVersion(1); - protectedPage.setCreator(page.getCreator()); - for (ContentPermission editor : editors) { - protectedPage.addPermission(createUserPermission(EDIT_PERMISSION, editor.getUserSubject())); - protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, editor.getUserSubject())); - } - for (String signedUserName : signature.getSignatures().keySet()) { - protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, signedUserName)); - } - protectedPage.setTitle(signature.getProtectedKey()); - pageManager.saveContentEntity(protectedPage, DefaultSaveContext.DEFAULT); - page.addChild(protectedPage); - } + if (body == null || body.length() <= 10) { + return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort")); + } + + Set userGroups = getSet(params, "signerGroups"); + boolean petitionMode = Signature.isPetitionMode(userGroups); + @SuppressWarnings("unchecked") + Set signers = petitionMode ? all : contextHelper.union( + getSet(params, "signers"), + loadUserGroups(userGroups), + loadInheritedSigners(InheritSigners.ofValue(params.get("inheritSigners")), conversionContext) + ); + ContentEntityObject entity = conversionContext.getEntity(); + Signature signature = sync(new Signature( + entity.getLatestVersionId(), + body, + params.get("title")) + .withNotified(getSet(params, "notified")) + .withMaxSignatures(getLong(params, "maxSignatures", -1)), + signers + ); + + boolean protectedContent = getBoolean(params, "protectedContent", false); + if (protectedContent && isPage(conversionContext)) { + try { + ensureProtectedPage(conversionContext, (Page) entity, signature); + } catch (Exception e) { + return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.editPermissionRequiredForProtectedContent", "")); } + } + + return getRenderedTemplate("templates/macro.vm", buildContext(params, conversionContext, entity, signature, protectedContent)); + } + + @NotNull + private Map buildContext(Map params, ConversionContext conversionContext, ContentEntityObject page, Signature signature, boolean protectedContent) { + ConfluenceUser currentUser = AuthenticatedUserThreadLocal.get(); + String currentUserName = currentUser.getName(); + boolean protectedContentAccess = protectedContent && (permissionManager.hasPermission(currentUser, Permission.EDIT, page) || signature.hasSigned(currentUserName)); - Map context = defaultVelocityContext(); - context.put("date", new DateTool()); - context.put("markdown", markdown); + Map context = defaultVelocityContext(); + context.put("date", new DateTool()); + context.put("markdown", markdown); - if (signature.isSignatureMissing(currentUserName)) { - context.put("signAs", contextHelper.getProfileNotNull(userManager, currentUserName).getFullName()); - context.put("signAction", bootstrapManager.getWebAppContextPath() + REST_PATH + "/sign"); + if (signature.isSignatureMissing(currentUserName)) { + context.put("signAs", contextHelper.getProfileNotNull(userManager, currentUserName).getFullName()); + context.put("signAction", bootstrapManager.getWebAppContextPath() + REST_PATH + "/sign"); + } + context.put("panel", getBoolean(params, "panel", true)); + context.put("protectedContent", protectedContentAccess); + if (protectedContentAccess && isPage(conversionContext)) { + context.put("protectedContentURL", bootstrapManager.getWebAppContextPath() + DISPLAY_PATH + "/" + ((Page) page).getSpaceKey() + "/" + signature.getProtectedKey()); + } + + boolean canExport = hideSignatures(params, signature, currentUserName); + Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); + Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); + + context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); + context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); + context.put("profiles", contextHelper.union(signed, missing)); + context.put("signature", signature); + context.put("mailtoSigned", getMailto(signed.values(), signature.getTitle(), true, signature)); + context.put("mailtoMissing", getMailto(missing.values(), signature.getTitle(), false, signature)); + context.put("UUID", UUID.randomUUID().toString().replace("-", "")); + context.put("downloadURL", canExport ? bootstrapManager.getWebAppContextPath() + REST_PATH + "/export?key=" + signature.getKey() : null); + return context; + } + + private void ensureProtectedPage(ConversionContext conversionContext, Page page, Signature signature) { + Page protectedPage = pageManager.getPage(conversionContext.getSpaceKey(), signature.getProtectedKey()); + if (protectedPage == null) { + ContentPermissionSet editors = page.getContentPermissionSet(EDIT_PERMISSION); + if (editors == null || editors.size() == 0) { + throw new IllegalStateException("No editors found!"); } - context.put("panel", getBoolean(params, "panel", true)); - context.put("protectedContent", protectedContentAccess); - if (protectedContentAccess && isPage(conversionContext)) { - Page page = (Page) entity; - context.put("protectedContentURL", bootstrapManager.getWebAppContextPath() + DISPLAY_PATH + "/" + page.getSpaceKey() + "/" + signature.getProtectedKey()); + protectedPage = new Page(); + protectedPage.setSpace(page.getSpace()); + protectedPage.setParentPage(page); + protectedPage.setVersion(1); + protectedPage.setCreator(page.getCreator()); + for (ContentPermission editor : editors) { + protectedPage.addPermission(createUserPermission(EDIT_PERMISSION, editor.getUserSubject())); + protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, editor.getUserSubject())); } - - boolean canExport = hideSignatures(params, signature, currentUserName); - Map signed = contextHelper.getProfiles(userManager, signature.getSignatures().keySet()); - Map missing = contextHelper.getProfiles(userManager, signature.getMissingSignatures()); - - context.put("orderedSignatures", contextHelper.getOrderedSignatures(signature)); - context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); - context.put("profiles", contextHelper.union(signed, missing)); - context.put("signature", signature); - context.put("mailtoSigned", getMailto(signed.values(), signature.getTitle(), true, signature)); - context.put("mailtoMissing", getMailto(missing.values(), signature.getTitle(), false, signature)); - context.put("UUID", UUID.randomUUID().toString().replace("-", "")); - context.put("downloadURL", canExport ? bootstrapManager.getWebAppContextPath() + REST_PATH + "/export?key=" + signature.getKey() : null); - return getRenderedTemplate("templates/macro.vm", context); + for (String signedUserName : signature.getSignatures().keySet()) { + protectedPage.addPermission(createUserPermission(VIEW_PERMISSION, signedUserName)); + } + protectedPage.setTitle(signature.getProtectedKey()); + pageManager.saveContentEntity(protectedPage, DefaultSaveContext.DEFAULT); + page.addChild(protectedPage); } - return warning(i18nResolver.getText("com.baloise.confluence.digital-signature.signature.macro.warning.bodyToShort")); } private boolean hideSignatures(Map params, Signature signature, String currentUserName) { diff --git a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java index eca5a79..433bca9 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/rest/DigitalSigatureService.java @@ -25,7 +25,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index e3f34ac..9c8dc66 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -1,66 +1,63 @@ - - ${project.description} - ${project.version} - - images/pluginIcon.png - images/pluginLogo.png - + plugins-version="2"> + + ${project.description} + ${project.version} + + images/pluginIcon.png + images/pluginLogo.png + - - - - - - - com.atlassian.auiplugin:ajs + + + - - - - digital-signature - + + + com.atlassian.auiplugin:ajs - + + + + digital-signature + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Provides signature services. com.baloise.confluence.digitalsignature.rest diff --git a/src/main/resources/templates/macro.vm b/src/main/resources/templates/macro.vm index 4676be3..ae87bf1 100644 --- a/src/main/resources/templates/macro.vm +++ b/src/main/resources/templates/macro.vm @@ -1,18 +1,48 @@ #set( $dateFormatter = $action.getDateFormatter()) #set( $title = $signature.getTitle()) #if( $panel ) -
    -
    $title   -
    + +
    +
    $title   +
    #if($protectedContent) $i18n.getText( + >$i18n.getText( "com.baloise.confluence.digital-signature.signature.macro.panel.protected-content.label") #end #if($downloadURL) - $i18n.getText( "com.baloise.confluence.digital-signature.signature.macro.panel.export.label") @@ -45,7 +75,7 @@ #end #set($bodyWithHtml = $markdown.toHTML($signature.getBody()))

    $bodyWithHtml

    -
      +
        #foreach ($date2userName in $orderedSignatures) #set( $userName = $date2userName.key) #set( $profile = $profiles.get($userName)) @@ -54,7 +84,7 @@ href="mailto:$profile.getEmail()">$profile.getFullName() #end #foreach( $profile in $orderedMissingSignatureProfiles) -
      • $profile.getFullName() +
      • $profile.getFullName()
      • #end #if($signAs) diff --git a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java index 147280f..f69902c 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java @@ -7,17 +7,17 @@ public class InheritSignersTest { @Test - public void testOfValue_READERS_ONLY() { + public void testOfValueReadersOnly() { assertEquals(READERS_ONLY, ofValue("readers only")); } @Test - public void testOfValue_NONE_NULL() { + public void testOfValueNoneNull() { assertEquals(NONE, ofValue(null)); } @Test - public void testOfValue_NONE_IllegalArgument() { + public void testOfValueNoneIllegalArgument() { assertEquals(NONE, ofValue("asdasd")); } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java index 0ced516..eecdd34 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java @@ -28,7 +28,7 @@ public void testMacroVm() throws Exception { mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); writer.flush(); String result = sw.toString(); - assertEquals("$title

        $bodyWithHtml

          ", normalize(result)); + assertEquals("$title

          $bodyWithHtml

            ", normalize(result)); } @Test From bb31d699f2a2adf387654faa850dc98c09f53227 Mon Sep 17 00:00:00 2001 From: tiliavir Date: Tue, 19 May 2020 19:08:24 +0200 Subject: [PATCH 05/15] reverts signature.ser to the initial verison Uses signature-test.ser for SignatureSerialisationTest and compares the new with the initial file. signature-test.ser is not committed and added to .gitignore. --- .gitignore | 2 ++ .../SignatureSerialisationTest.java | 2 +- src/test/resources/signature.ser | Bin 637 -> 534 bytes 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1858b8b..6c03aa4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/src/test/resources/signature-test.ser + /.settings /.classpath /.project diff --git a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java index 79e2cc2..165ce7f 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/SignatureSerialisationTest.java @@ -31,7 +31,7 @@ public void serialise() throws IOException, ClassNotFoundException { signature.getMissingSignatures().add("missing1"); signature.getMissingSignatures().add("missing2"); signature.getSignatures().put("signed1", new Date(9999)); - ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/test/resources/signature.ser")); + ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("src/test/resources/signature-test.ser")); out.writeObject(signature); out.close(); diff --git a/src/test/resources/signature.ser b/src/test/resources/signature.ser index 34c8323f95b0c3cdd10b8ad824ffb6c5239134dd..bb1b2bf22191927a6362a117688b5ba54538738b 100644 GIT binary patch delta 40 rcmey%GL2<|Gb8)N5cP@ex%>Qz}as943BonD~4WBgf<_#yJ3;vmQGD From 9967ecc38071cfa118993778011d33021321e7bf Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Mon, 8 Jun 2020 13:37:44 +0200 Subject: [PATCH 06/15] re-adds org.springframework.osgi.* and org.eclipse.gemini.blueprint.* to Import-Package - org.springframework.osgi.* is required (error on plugin enable) - org.eclipse.gemini.blueprint.* might not be necessary, but it is part of the stub created with the atlassian plugin SDK --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index e3089a7..5e0dd5f 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,8 @@ com.baloise.confluence.digitalsignature.api + org.springframework.osgi.*;resolution:="optional", + org.eclipse.gemini.blueprint.*;resolution:="optional", com.sun.mail.imap, com.sun.mail.smtp, com.sun.mail.pop3, From 18a2739eb77c62a2e46107bd588fce75f296d8ea Mon Sep 17 00:00:00 2001 From: Matthias Cullmann Date: Tue, 1 Sep 2020 16:32:43 +0200 Subject: [PATCH 07/15] mvn package confluence:install as new deployment option --- development.txt | 5 ++++- pom.xml | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/development.txt b/development.txt index c475c1f..09873a3 100644 --- a/development.txt +++ b/development.txt @@ -16,11 +16,14 @@ set JPDA_TRANSPORT=dt_socket %CATALINA_HOME%\bin\catalina.bat jpda start http://127.0.0.1:8090/ + atlas-install-plugin -p 8090 --context-path / --plugin-key com.baloise.confluence.digital-signature +oruncomment the atlassian-pdk configuration in pom.xml and use +mvn package confluence:install ------------------- -Pure Maven setup ( not for the faint of heart, starup is slow on my box) +Pure Maven setup ( not for the faint of heart, start up is slow on my box) you will be able to remote debug on port 5005 mvn confluence:debug -Dproduct.version=7.4.0 diff --git a/pom.xml b/pom.xml index dabff8a..98b6de6 100644 --- a/pom.xml +++ b/pom.xml @@ -112,6 +112,15 @@ + com.atlassian.maven.plugins confluence-maven-plugin From 323918e2d956610cdce797d978fd4d0c6c294582 Mon Sep 17 00:00:00 2001 From: Matthias Cullmann Date: Tue, 1 Sep 2020 16:33:05 +0200 Subject: [PATCH 08/15] mvn package confluence:install as new deployment option fix typo --- development.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/development.txt b/development.txt index 09873a3..1990f96 100644 --- a/development.txt +++ b/development.txt @@ -18,7 +18,7 @@ set JPDA_TRANSPORT=dt_socket http://127.0.0.1:8090/ atlas-install-plugin -p 8090 --context-path / --plugin-key com.baloise.confluence.digital-signature -oruncomment the atlassian-pdk configuration in pom.xml and use +or uncomment the atlassian-pdk configuration in pom.xml and use mvn package confluence:install ------------------- From 845aedafe49c85c85c1bb02c677e70bed3575d44 Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Sun, 30 Aug 2020 23:56:02 +0200 Subject: [PATCH 09/15] #26: allows to configure a limit of visible signees with a toggle button to show all --- .../DigitalSignatureMacro.java | 9 ++- .../confluence/digitalsignature/Markdown.java | 4 +- .../digitalsignature/Signature.java | 14 ++++ src/main/resources/atlassian-plugin.xml | 1 + src/main/resources/css/digital-signature.css | 28 ++++++++ .../resources/digital-signature.properties | 2 + .../resources/digital-signature_de.properties | 2 + .../digital-signature_ja_JP.properties | 2 + .../digital-signature_ja_JP.properties.utf8 | 2 + src/main/resources/js/digital-signature.js | 38 ++++++++++ src/main/resources/templates/macro.vm | 71 +++++++------------ .../digitalsignature/TemplatesTest.java | 10 ++- 12 files changed, 129 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index 4ad6b8d..fbae49d 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -99,7 +99,8 @@ public String execute(Map params, String body, ConversionContext body, params.get("title")) .withNotified(getSet(params, "notified")) - .withMaxSignatures(getLong(params, "maxSignatures", -1)), + .withMaxSignatures(getLong(params, "maxSignatures", -1)) + .withVisibilityLimit(getLong(params, "visibilityLimit", -1)), signers ); @@ -143,6 +144,7 @@ private Map buildContext(Map params, ConversionC context.put("orderedMissingSignatureProfiles", contextHelper.getOrderedProfiles(userManager, signature.getMissingSignatures())); context.put("profiles", contextHelper.union(signed, missing)); context.put("signature", signature); + context.put("visibilityLimit", signature.getVisibilityLimit()); context.put("mailtoSigned", getMailto(signed.values(), signature.getTitle(), true, signature)); context.put("mailtoMissing", getMailto(missing.values(), signature.getTitle(), false, signature)); context.put("UUID", UUID.randomUUID().toString().replace("-", "")); @@ -311,6 +313,11 @@ private Signature sync(Signature signature, Set signers) { save = true; } + if (loaded.getVisibilityLimit() != signature.getVisibilityLimit()) { + loaded.setVisibilityLimit(signature.getVisibilityLimit()); + save = true; + } + if (save) save(loaded); } else { signature.setMissingSignatures(signers); diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java b/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java index 2c8526f..abf2f99 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Markdown.java @@ -5,8 +5,8 @@ import com.vladsch.flexmark.util.data.MutableDataSet; public class Markdown { - private Parser parser; - private HtmlRenderer renderer; + private final Parser parser; + private final HtmlRenderer renderer; public Markdown() { MutableDataSet options = new MutableDataSet(); diff --git a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java index 4f29cc0..64f588e 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/Signature.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/Signature.java @@ -15,6 +15,7 @@ public class Signature implements Serializable { private String title = ""; private String body = ""; private long maxSignatures = -1; + private long visibilityLimit = -1; private Map signatures = new HashMap<>(); private Set missingSignatures = new TreeSet<>(); private Set notified = new TreeSet<>(); @@ -89,6 +90,14 @@ public void setMissingSignatures(Set missingSignatures) { this.missingSignatures = missingSignatures; } + public long getVisibilityLimit() { + return visibilityLimit; + } + + public void setVisibilityLimit(long visibilityLimit) { + this.visibilityLimit = visibilityLimit; + } + public long getMaxSignatures() { return maxSignatures; } @@ -145,6 +154,11 @@ public Signature withMaxSignatures(long maxSignatures) { return this; } + public Signature withVisibilityLimit(long visibilityLimit) { + this.visibilityLimit = visibilityLimit; + return this; + } + public boolean hasSigned(String userName) { return signatures.containsKey(userName); } diff --git a/src/main/resources/atlassian-plugin.xml b/src/main/resources/atlassian-plugin.xml index 9c8dc66..ef33be4 100644 --- a/src/main/resources/atlassian-plugin.xml +++ b/src/main/resources/atlassian-plugin.xml @@ -42,6 +42,7 @@ + diff --git a/src/main/resources/css/digital-signature.css b/src/main/resources/css/digital-signature.css index e69de29..4fa5a95 100644 --- a/src/main/resources/css/digital-signature.css +++ b/src/main/resources/css/digital-signature.css @@ -0,0 +1,28 @@ +.panel { + border-width: 1px; +} + +.panel .panelHeader { + border-bottom-width: 1px; + color: #bbb; +} + +.panel .panelHeader .aui-buttons { + float: right +} + +.panel .panelHeader .aui-icon.aui-icon-small.aui-iconfont-attachment { + margin-right: 20px; +} + +.panel .panelHeader .aui-icon.aui-icon-small.aui-iconfont-file-pdf { + float: right; +} + +.body-list { + list-style-type: none; +} + +.body-list .body-list-item { + color: #bbb; +} diff --git a/src/main/resources/digital-signature.properties b/src/main/resources/digital-signature.properties index 8c615c9..26f012b 100644 --- a/src/main/resources/digital-signature.properties +++ b/src/main/resources/digital-signature.properties @@ -23,6 +23,7 @@ com.baloise.confluence.digital-signature.signature.param.pendingVisible.desc= com.baloise.confluence.digital-signature.signature.param.pendingVisible.always.desc=always com.baloise.confluence.digital-signature.signature.param.pendingVisible.if\ signatory.desc=if user is allowed to sign com.baloise.confluence.digital-signature.signature.param.pendingVisible.if\ signed.desc=if user has signed +com.baloise.confluence.digital-signature.signature.param.visibilityLimit.label=Limit of visible signees com.baloise.confluence.digital-signature.signature.param.maxSignatures.label=Maximum Signatures com.baloise.confluence.digital-signature.signature.param.maxSignatures.desc=Maximum number of signatures accepted on the panel. (Fill in 0 to disable signing without modifying existing signatures.) com.baloise.confluence.digital-signature.signature.param.notified.label=Notified Users @@ -32,6 +33,7 @@ com.baloise.confluence.digital-signature.signature.param.panel.desc=Show a visib com.baloise.confluence.digital-signature.signature.param.protectedContent.label=Create Protected Child Page com.baloise.confluence.digital-signature.signature.param.protectedContent.desc=Create a protected child page underneath the current page, which can only be viewed+edited by users who have permission to edit the current page, and viewed by users who have signed the panel. Because the protected child page uses the same key as the panel, you should finalise the panel title and text and only then check this option to generate the protected child page. com.baloise.confluence.digital-signature.signature.macro.button.sign-as.label=Sign as {0} +com.baloise.confluence.digital-signature.signature.macro.button.show-all.label=Show all com.baloise.confluence.digital-signature.signature.macro.panel.protected-content.label=Go to protected page com.baloise.confluence.digital-signature.signature.macro.panel.export.label=Export signature panel com.baloise.confluence.digital-signature.signature.macro.panel.email.label=Send e-mail to signatories diff --git a/src/main/resources/digital-signature_de.properties b/src/main/resources/digital-signature_de.properties index 41d2c29..1d6637d 100644 --- a/src/main/resources/digital-signature_de.properties +++ b/src/main/resources/digital-signature_de.properties @@ -23,6 +23,7 @@ com.baloise.confluence.digital-signature.signature.param.pendingVisible.desc= com.baloise.confluence.digital-signature.signature.param.pendingVisible.always.desc=immer com.baloise.confluence.digital-signature.signature.param.pendingVisible.if\ signatory.desc=den Unterzeichnenden com.baloise.confluence.digital-signature.signature.param.pendingVisible.if\ signed.desc=nach der Unterschrift +com.baloise.confluence.digital-signature.signature.param.visibilityLimit.label=Maximal sichtbare Unterschriften com.baloise.confluence.digital-signature.signature.param.maxSignatures.label=Maximale Anzahl Unterschriften com.baloise.confluence.digital-signature.signature.param.maxSignatures.desc=Geben Sie 0 ein um das Unterzeichnen zu verhindern, ohne bestehnende Unterschriften zu beeinflussen. com.baloise.confluence.digital-signature.signature.param.notified.label=Benachrichtige Benutzer @@ -32,6 +33,7 @@ com.baloise.confluence.digital-signature.signature.param.panel.desc=Einen Rahmen com.baloise.confluence.digital-signature.signature.param.protectedContent.label=Geschützte untergeordnete Seite erstellen com.baloise.confluence.digital-signature.signature.param.protectedContent.desc=Erstellt einge geschützte Unterseite zum geschützten Bereich. Jeder Unterzeichnende bekommt automatisch Leserechte auf der geschützen Unterseite. Da die Unterseite den selben Schlüssel verwendet wie der unterzeichnete Bereich, sollten Sie erst Titel und Inhalt des Bereichs fertigstellen, bevor die Unterseite aktiviert wird. com.baloise.confluence.digital-signature.signature.macro.button.sign-as.label=Unterzeichnen als {0} +com.baloise.confluence.digital-signature.signature.macro.button.show-all.label=Alle anzeigen com.baloise.confluence.digital-signature.signature.macro.panel.protected-content.label=Geschützte Seite aufrufen com.baloise.confluence.digital-signature.signature.macro.panel.export.label=Geschützten Bereicht exportieren com.baloise.confluence.digital-signature.signature.macro.panel.email.label=Email an Unterzeichnende diff --git a/src/main/resources/digital-signature_ja_JP.properties b/src/main/resources/digital-signature_ja_JP.properties index 7b4469a..67d9ce9 100644 --- a/src/main/resources/digital-signature_ja_JP.properties +++ b/src/main/resources/digital-signature_ja_JP.properties @@ -15,6 +15,7 @@ com.baloise.confluence.digital-signature.signature.param.inheritSigners.none.des com.baloise.confluence.digital-signature.signature.param.inheritSigners.readers\ only.desc=\u8aad\u307f\u53d6\u6a29\u9650\u30e6\u30fc\u30b6\u30fc\u3060\u3051 com.baloise.confluence.digital-signature.signature.param.inheritSigners.writers\ only.desc=\u7de8\u96c6\u6a29\u9650\u30e6\u30fc\u30b6\u30fc\u3060\u3051 com.baloise.confluence.digital-signature.signature.param.inheritSigners.readers\ and\ writers.desc=\u305d\u306e\u53cc\u65b9\u6a29\u9650\u30e6\u30fc\u30b6\u30fc +com.baloise.confluence.digital-signature.signature.param.visibilityLimit.label=\u8868\u793a\u3055\u308c\u308b\u7f72\u540d\u8005\u306e\u5236\u9650 com.baloise.confluence.digital-signature.signature.param.maxSignatures.label=\u6700\u591a\u7f72\u540d\u6570 com.baloise.confluence.digital-signature.signature.param.maxSignatures.desc=\u30d1\u30cd\u30eb\u4e0a\u3067\u8a8d\u3081\u3089\u308c\u308b\u6700\u591a\u7f72\u540d\u6570\u3002(\u65e2\u5b58\u7f72\u540d\u306e\u5909\u66f4\u306a\u3057\u3067\u306e\u7f72\u540d\u3092\u7121\u52b9\u306b\u3059\u308b\u306b\u306f\u30010\u3092\u8a18\u5165\u3057\u3066\u304f\u3060\u3055\u3044\u3002) com.baloise.confluence.digital-signature.signature.param.notified.label=\u901a\u77e5\u3055\u308c\u308b\u30e6\u30fc\u30b6\u30fc @@ -24,6 +25,7 @@ com.baloise.confluence.digital-signature.signature.param.panel.desc=\u7f72\u540d com.baloise.confluence.digital-signature.signature.param.protectedContent.label=\u4fdd\u8b77\u3055\u308c\u305f\u5b50\u30da\u30fc\u30b8\u3092\u4f5c\u6210\u3059\u308b com.baloise.confluence.digital-signature.signature.param.protectedContent.desc=\u73fe\u5728\u30da\u30fc\u30b8\u306e\u4e0b\u306b\u4fdd\u8b77\u3055\u308c\u305f\u5b50\u30da\u30fc\u30b8\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002\u73fe\u5728\u30da\u30fc\u30b8\u306e\u7de8\u96c6\u6a29\u9650\u3092\u6709\u3059\u308b\u30e6\u30fc\u30b6\u30fc\u304c\u3001\u3053\u308c\u3092\u95b2\u89a7\u304a\u3088\u3073\u7de8\u96c6\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u3001\u30d1\u30cd\u30eb\u3092\u7f72\u540d\u3057\u305f\u30e6\u30fc\u30b6\u30fc\u304c\u3001\u3053\u308c\u3092\u95b2\u89a7\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u4fdd\u8b77\u3055\u308c\u305f\u5b50\u30da\u30fc\u30b8\u306f\u30d1\u30cd\u30eb\u3068\u540c\u3058\u30ad\u30fc\u3092\u4f7f\u3046\u305f\u3081\u3001\u30d1\u30cd\u30eb\u30bf\u30a4\u30c8\u30eb\u3068\u30c6\u30ad\u30b9\u30c8\u306e\u5165\u529b\u3092\u5b8c\u4e86\u3057\u3001\u305d\u306e\u5f8c\u3053\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u30c1\u30a7\u30c3\u30af\u3092\u5165\u308c\u3066\u304b\u3089\u3001\u4fdd\u8b77\u3055\u308c\u305f\u5b50\u30da\u30fc\u30b8\u3092\u751f\u6210\u3059\u308b\u5fc5\u8981\u304c\u308a\u307e\u3059\u3002 com.baloise.confluence.digital-signature.signature.macro.button.sign-as.label={0}\u3068\u3057\u3066\u7f72\u540d\u3059\u308b +com.baloise.confluence.digital-signature.signature.macro.button.show-all.label=\u3059\u3079\u3066\u8868\u793a\u3059\u308b com.baloise.confluence.digital-signature.signature.macro.panel.protected-content.label=\u4fdd\u8b77\u3055\u308c\u305f\u30da\u30fc\u30b8\u3078\u9032\u3080 com.baloise.confluence.digital-signature.signature.macro.panel.export.label=\u7f72\u540d\u30d1\u30cd\u30eb\u3092\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3059\u308b com.baloise.confluence.digital-signature.signature.macro.panel.email.label=\u7f72\u540d\u8005\u306bE\u30e1\u30fc\u30eb\u3092\u9001\u308b diff --git a/src/main/resources/digital-signature_ja_JP.properties.utf8 b/src/main/resources/digital-signature_ja_JP.properties.utf8 index bb804b6..737989d 100644 --- a/src/main/resources/digital-signature_ja_JP.properties.utf8 +++ b/src/main/resources/digital-signature_ja_JP.properties.utf8 @@ -15,6 +15,7 @@ com.baloise.confluence.digital-signature.signature.param.inheritSigners.none.des com.baloise.confluence.digital-signature.signature.param.inheritSigners.readers\ only.desc=読ã¿å–権é™ãƒ¦ãƒ¼ã‚¶ãƒ¼ã ã‘ com.baloise.confluence.digital-signature.signature.param.inheritSigners.writers\ only.desc=編集権é™ãƒ¦ãƒ¼ã‚¶ãƒ¼ã ã‘ com.baloise.confluence.digital-signature.signature.param.inheritSigners.readers\ and\ writers.desc=ãã®åŒæ–¹æ¨©é™ãƒ¦ãƒ¼ã‚¶ãƒ¼ +com.baloise.confluence.digital-signature.signature.param.visibilityLimit.label=表示ã•ã‚Œã‚‹ç½²å者ã®åˆ¶é™ com.baloise.confluence.digital-signature.signature.param.maxSignatures.label=最多署åæ•° com.baloise.confluence.digital-signature.signature.param.maxSignatures.desc=パãƒãƒ«ä¸Šã§èªã‚られる最多署å数。(既存署åã®å¤‰æ›´ãªã—ã§ã®ç½²åを無効ã«ã™ã‚‹ã«ã¯ã€0を記入ã—ã¦ãã ã•ã„。) com.baloise.confluence.digital-signature.signature.param.notified.label=通知ã•ã‚Œã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ @@ -24,6 +25,7 @@ com.baloise.confluence.digital-signature.signature.param.panel.desc=ç½²åã•ã‚Œ com.baloise.confluence.digital-signature.signature.param.protectedContent.label=ä¿è­·ã•ã‚ŒãŸå­ãƒšãƒ¼ã‚¸ã‚’作æˆã™ã‚‹ com.baloise.confluence.digital-signature.signature.param.protectedContent.desc=ç¾åœ¨ãƒšãƒ¼ã‚¸ã®ä¸‹ã«ä¿è­·ã•ã‚ŒãŸå­ãƒšãƒ¼ã‚¸ã‚’作æˆã—ã¾ã™ã€‚ç¾åœ¨ãƒšãƒ¼ã‚¸ã®ç·¨é›†æ¨©é™ã‚’有ã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã€ã“れを閲覧ãŠã‚ˆã³ç·¨é›†ã™ã‚‹ã“ã¨ãŒã§ãã€ãƒ‘ãƒãƒ«ã‚’ç½²åã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã€ã“れを閲覧ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ä¿è­·ã•ã‚ŒãŸå­ãƒšãƒ¼ã‚¸ã¯ãƒ‘ãƒãƒ«ã¨åŒã˜ã‚­ãƒ¼ã‚’使ã†ãŸã‚ã€ãƒ‘ãƒãƒ«ã‚¿ã‚¤ãƒˆãƒ«ã¨ãƒ†ã‚­ã‚¹ãƒˆã®å…¥åŠ›ã‚’完了ã—ã€ãã®å¾Œã“ã®ã‚ªãƒ—ションã«ãƒã‚§ãƒƒã‚¯ã‚’入れã¦ã‹ã‚‰ã€ä¿è­·ã•ã‚ŒãŸå­ãƒšãƒ¼ã‚¸ã‚’生æˆã™ã‚‹å¿…è¦ãŒã‚Šã¾ã™ã€‚ com.baloise.confluence.digital-signature.signature.macro.button.sign-as.label={0}ã¨ã—ã¦ç½²åã™ã‚‹ +com.baloise.confluence.digital-signature.signature.macro.button.show-all.label=ã™ã¹ã¦è¡¨ç¤ºã™ã‚‹ com.baloise.confluence.digital-signature.signature.macro.panel.protected-content.label=ä¿è­·ã•ã‚ŒãŸãƒšãƒ¼ã‚¸ã¸é€²ã‚€ com.baloise.confluence.digital-signature.signature.macro.panel.export.label=ç½²åパãƒãƒ«ã‚’エクスãƒãƒ¼ãƒˆã™ã‚‹ com.baloise.confluence.digital-signature.signature.macro.panel.email.label=ç½²å者ã«Eメールをé€ã‚‹ diff --git a/src/main/resources/js/digital-signature.js b/src/main/resources/js/digital-signature.js index e69de29..dfd80d8 100644 --- a/src/main/resources/js/digital-signature.js +++ b/src/main/resources/js/digital-signature.js @@ -0,0 +1,38 @@ +function bindCollapse(ul, limit, showMore) { + if (limit < 0) { + return; + } + + let $ul = AJS.$(ul); + + hideElements($ul, limit); + $ul.prepend("
          • " + showMore + "
          • ") + .bind("click", function() { + showAllElements(this); + }); +} + +function hideElements($ul, limit) { + const signedList = $ul.find("li.signeelist-signed"); + const missingList = $ul.find("li.signeelist-missing"); + + let remainingCount = limit; + + if (signedList.length > 0) { + let shownSignees = Math.min(signedList.length, Math.ceil(remainingCount / 2)); + remainingCount = remainingCount - shownSignees; + for (let i = 0; i < signedList.length - shownSignees; i++) { + AJS.$(signedList[i]).hide(); + } + } + + for (let i = 0; i < missingList.length - remainingCount; i++) { + AJS.$(missingList[i]).hide(); + } +} + +function showAllElements(button) { + let $button = AJS.$(button); + $button.closest("ul").find("li").show(); + $button.remove(); +} diff --git a/src/main/resources/templates/macro.vm b/src/main/resources/templates/macro.vm index ae87bf1..ba00fd9 100644 --- a/src/main/resources/templates/macro.vm +++ b/src/main/resources/templates/macro.vm @@ -1,36 +1,8 @@ +#requireResource("com.baloise.confluence.digital-signature:digital-signature-resources") + #set( $dateFormatter = $action.getDateFormatter()) #set( $title = $signature.getTitle()) -#if( $panel ) - +#if( $panel)
            $title  
            @@ -73,31 +45,40 @@ #else $title #end + #set($bodyWithHtml = $markdown.toHTML($signature.getBody()))

            $bodyWithHtml

            -
              +
                #foreach ($date2userName in $orderedSignatures) #set( $userName = $date2userName.key) #set( $profile = $profiles.get($userName)) -
              • + $dateFormatter.formatDateTime($date2userName.value) - $profile.getFullName()
              • - #end - #foreach( $profile in $orderedMissingSignatureProfiles) -
              • $profile.getFullName() + href="mailto:$profile.getEmail()">$profile.getFullName()
              • #end - #if($signAs) -
              • -
                - -
                + #foreach( $profile in $orderedMissingSignatureProfiles) +
              • + $profile.getFullName()
              • #end
              -#if( $panel ) + #if($signAs) +
              +
              + +
              +
              + #end +#if($panel)
            #end - + diff --git a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java index eecdd34..47dce41 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java @@ -27,8 +27,8 @@ public void testMacroVm() throws Exception { //add your parameters to context mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); writer.flush(); - String result = sw.toString(); - assertEquals("$title

            $bodyWithHtml

              ", normalize(result)); + String expected = "#requireResource(\"com.baloise.confluence.digital-signature:digital-signature-resources\") $title

              $bodyWithHtml

                "; + assertEquals(expected, normalize(sw.toString())); } @Test @@ -40,9 +40,7 @@ public void testExportVm() throws Exception { //add your parameters to context mergeTemplate("src/main/resources/templates/export.vm", "UTF-8", context, writer); writer.flush(); - String result = sw.toString(); - assertEquals("

                $signature.getTitle()

                $bodyWithHtml

                ", - normalize(result)); + String expected = "

                $signature.getTitle()

                $bodyWithHtml

                "; + assertEquals(expected, normalize(sw.toString())); } - } From 8ee06c4fbf7f08fc0d15fd16a821821d1a2eb559 Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Mon, 31 Aug 2020 13:48:42 +0200 Subject: [PATCH 10/15] #26: fixes visibility and function of "show more" button --- src/main/resources/js/digital-signature.js | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/resources/js/digital-signature.js b/src/main/resources/js/digital-signature.js index dfd80d8..4ce1c0f 100644 --- a/src/main/resources/js/digital-signature.js +++ b/src/main/resources/js/digital-signature.js @@ -5,11 +5,12 @@ function bindCollapse(ul, limit, showMore) { let $ul = AJS.$(ul); - hideElements($ul, limit); - $ul.prepend("
              • " + showMore + "
              • ") - .bind("click", function() { - showAllElements(this); - }); + if (hideElements($ul, limit)) { + $ul.prepend("
              • " + showMore + "
              • ") + .bind("click", function () { + showAllElements($ul); + }); + } } function hideElements($ul, limit) { @@ -18,21 +19,25 @@ function hideElements($ul, limit) { let remainingCount = limit; + let isSomethingHidden = false; if (signedList.length > 0) { let shownSignees = Math.min(signedList.length, Math.ceil(remainingCount / 2)); remainingCount = remainingCount - shownSignees; for (let i = 0; i < signedList.length - shownSignees; i++) { - AJS.$(signedList[i]).hide(); + AJS.$(signedList[i]).hide() + isSomethingHidden = true; } } for (let i = 0; i < missingList.length - remainingCount; i++) { AJS.$(missingList[i]).hide(); + isSomethingHidden = true; } + + return isSomethingHidden; } -function showAllElements(button) { - let $button = AJS.$(button); - $button.closest("ul").find("li").show(); - $button.remove(); +function showAllElements($ul) { + $ul.find("li").show(); + $ul.find("li.show-all").remove(); } From e4d12cddffe1afdf4eb35e775ca0233adfaafd3d Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Mon, 31 Aug 2020 15:06:00 +0200 Subject: [PATCH 11/15] #26: fixes issue with multiple macros on one singe page Previously the JavaScript affected all digital signature macros on a page. E.g. the expander button affected all macros and was rendered multiple times for each macro... --- src/main/resources/templates/macro.vm | 11 ++++++----- .../confluence/digitalsignature/TemplatesTest.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/resources/templates/macro.vm b/src/main/resources/templates/macro.vm index ba00fd9..be6ef39 100644 --- a/src/main/resources/templates/macro.vm +++ b/src/main/resources/templates/macro.vm @@ -1,8 +1,9 @@ #requireResource("com.baloise.confluence.digital-signature:digital-signature-resources") -#set( $dateFormatter = $action.getDateFormatter()) -#set( $title = $signature.getTitle()) -#if( $panel) +#set($dateFormatter = $action.getDateFormatter()) +#set($title = $signature.getTitle()) +#set($macroId = $signature.getKey().replace("signature.", "")) +#if($panel)
                $title  
                @@ -48,7 +49,7 @@ #set($bodyWithHtml = $markdown.toHTML($signature.getBody()))

                $bodyWithHtml

                -
                  +
                    #foreach ($date2userName in $orderedSignatures) #set( $userName = $date2userName.key) #set( $profile = $profiles.get($userName)) @@ -78,7 +79,7 @@ diff --git a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java index 47dce41..e4930a3 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/TemplatesTest.java @@ -27,7 +27,7 @@ public void testMacroVm() throws Exception { //add your parameters to context mergeTemplate("src/main/resources/templates/macro.vm", "UTF-8", context, writer); writer.flush(); - String expected = "#requireResource(\"com.baloise.confluence.digital-signature:digital-signature-resources\") $title

                    $bodyWithHtml

                      "; + String expected = "#requireResource(\"com.baloise.confluence.digital-signature:digital-signature-resources\") $title

                      $bodyWithHtml

                        "; assertEquals(expected, normalize(sw.toString())); } From 895f784c437dd2310515db7e271c2df5ff6a8013 Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Tue, 1 Sep 2020 21:33:46 +0200 Subject: [PATCH 12/15] #26: CR changes: moves 'show all' out of the ul and below the signee list --- src/main/resources/js/digital-signature.js | 10 +- .../DigitalSignatureMacroTest.java | 94 +++++++++---------- .../digitalsignature/InheritSignersTest.java | 24 ++--- .../digitalsignature/MessageFormatTest.java | 24 ++--- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/main/resources/js/digital-signature.js b/src/main/resources/js/digital-signature.js index 4ce1c0f..6ae5a8e 100644 --- a/src/main/resources/js/digital-signature.js +++ b/src/main/resources/js/digital-signature.js @@ -6,10 +6,10 @@ function bindCollapse(ul, limit, showMore) { let $ul = AJS.$(ul); if (hideElements($ul, limit)) { - $ul.prepend("
                      • " + showMore + "
                      • ") - .bind("click", function () { - showAllElements($ul); - }); + $ul.after("" + showMore + ""); + $ul.siblings("a.show-all").bind("click", function () { + showAllElements($ul); + }); } } @@ -39,5 +39,5 @@ function hideElements($ul, limit) { function showAllElements($ul) { $ul.find("li").show(); - $ul.find("li.show-all").remove(); + $ul.siblings("a.show-all").remove(); } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java index fe8c3df..72326fc 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java @@ -1,62 +1,62 @@ package com.baloise.confluence.digitalsignature; -import com.atlassian.confluence.setup.BootstrapManager; -import com.atlassian.sal.api.user.UserProfile; -import org.junit.Test; -import org.mockito.Mockito; - import java.util.ArrayList; import java.util.List; +import org.junit.Test; + +import com.atlassian.confluence.setup.BootstrapManager; +import com.atlassian.sal.api.user.UserProfile; + import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class DigitalSignatureMacroTest { - Signature signature = new Signature(1, "test", "title"); - - BootstrapManager bootstrapManager = mock(BootstrapManager.class); - - @Test - public void getMailtoLong() { - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList<>(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - for (int i = 0; i < 20; i++) { - profiles.add(profile); - } - String mailto = macro.getMailto(profiles, "Subject", true, null); - assertEquals("mailto:heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com?Subject=Subject", mailto); - } + Signature signature = new Signature(1, "test", "title"); - @Test - public void getMailtoVeryLong() { - Mockito.when(bootstrapManager.getWebAppContextPath()).thenReturn("nirvana"); - - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, bootstrapManager, null, null, null, null); - List profiles = new ArrayList<>(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - for (int i = 0; i < 200; i++) { - profiles.add(profile); - } - String mailto = macro.getMailto(profiles, "Subject", true, signature); - assertEquals("nirvana/rest/signature/1.0/emails?key=signature.3224a4d6bba68cd0ece9b64252f8bf5677e24cf6b7c5f543e3176d419d34d517&signed=true", mailto); - } + BootstrapManager bootstrapManager = mock(BootstrapManager.class); - @Test - public void getMailtoShort() { - DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); - List profiles = new ArrayList<>(); - UserProfile profile = Mockito.mock(UserProfile.class); - when(profile.getFullName()).thenReturn("Heinz Meier"); - when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); - profiles.add(profile); - String mailto = macro.getMailto(profiles, "Subject", true, null); - assertEquals("mailto:Heinz Meier?Subject=Subject", mailto); + @Test + public void getMailtoLong() { + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); + List profiles = new ArrayList<>(); + UserProfile profile = mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + for (int i = 0; i < 20; i++) { + profiles.add(profile); + } + String mailto = macro.getMailto(profiles, "Subject", true, null); + assertEquals("mailto:heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com,heinz.meier@meier.com?Subject=Subject", mailto); + } + + @Test + public void getMailtoVeryLong() { + when(bootstrapManager.getWebAppContextPath()).thenReturn("nirvana"); + + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, bootstrapManager, null, null, null, null); + List profiles = new ArrayList<>(); + UserProfile profile = mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + for (int i = 0; i < 200; i++) { + profiles.add(profile); } + String mailto = macro.getMailto(profiles, "Subject", true, signature); + assertEquals("nirvana/rest/signature/1.0/emails?key=signature.3224a4d6bba68cd0ece9b64252f8bf5677e24cf6b7c5f543e3176d419d34d517&signed=true", mailto); + } + + @Test + public void getMailtoShort() { + DigitalSignatureMacro macro = new DigitalSignatureMacro(null, null, null, null, null, null, null); + List profiles = new ArrayList<>(); + UserProfile profile = mock(UserProfile.class); + when(profile.getFullName()).thenReturn("Heinz Meier"); + when(profile.getEmail()).thenReturn("heinz.meier@meier.com"); + profiles.add(profile); + String mailto = macro.getMailto(profiles, "Subject", true, null); + assertEquals("mailto:Heinz Meier?Subject=Subject", mailto); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java index f69902c..90c3651 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java @@ -6,18 +6,18 @@ import static org.junit.Assert.assertEquals; public class InheritSignersTest { - @Test - public void testOfValueReadersOnly() { - assertEquals(READERS_ONLY, ofValue("readers only")); - } + @Test + public void testOfValueReadersOnly() { + assertEquals(READERS_ONLY, ofValue("readers only")); + } - @Test - public void testOfValueNoneNull() { - assertEquals(NONE, ofValue(null)); - } + @Test + public void testOfValueNoneNull() { + assertEquals(NONE, ofValue(null)); + } - @Test - public void testOfValueNoneIllegalArgument() { - assertEquals(NONE, ofValue("asdasd")); - } + @Test + public void testOfValueNoneIllegalArgument() { + assertEquals(NONE, ofValue("asdasd")); + } } diff --git a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java index 2c30cae..4d2dde1 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/MessageFormatTest.java @@ -1,19 +1,19 @@ package com.baloise.confluence.digitalsignature; -import org.junit.Test; - import java.text.MessageFormat; -import static org.junit.Assert.*; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; public class MessageFormatTest { - @Test - public void test() { - String rawTemplate = "Email addresses of users who {0}signed{1} {2}"; - String actual = MessageFormat.format(rawTemplate, "", "", "#123"); - assertEquals("Email addresses of users who signed #123", actual); - rawTemplate = "{2} was {0}signed{1}"; - actual = MessageFormat.format(rawTemplate, "", "", "#123"); - assertEquals("#123 was signed", actual); - } + @Test + public void test() { + String rawTemplate = "Email addresses of users who {0}signed{1} {2}"; + String actual = MessageFormat.format(rawTemplate, "", "", "#123"); + assertEquals("Email addresses of users who signed #123", actual); + rawTemplate = "{2} was {0}signed{1}"; + actual = MessageFormat.format(rawTemplate, "", "", "#123"); + assertEquals("#123 was signed", actual); + } } From 0b627953e04618b02ee844ad1a7d77fbfd13c47d Mon Sep 17 00:00:00 2001 From: tiliavir Date: Sun, 13 Sep 2020 16:27:15 +0200 Subject: [PATCH 13/15] fixes code style issues --- .../DigitalSignatureMacro.java | 12 +++---- src/main/resources/css/digital-signature.css | 16 +++++----- src/main/resources/js/digital-signature.js | 32 +++++++++---------- .../DigitalSignatureMacroTest.java | 5 ++- .../digitalsignature/InheritSignersTest.java | 4 ++- 5 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java index fbae49d..953ee4a 100644 --- a/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java +++ b/src/main/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacro.java @@ -341,13 +341,13 @@ public OutputType getOutputType() { return OutputType.BLOCK; } - String getMailto(Collection profiles, String subject, boolean signed, Signature signature) { + protected String getMailto(Collection profiles, String subject, boolean signed, Signature signature) { if (profiles == null || profiles.isEmpty()) return null; - profiles = profiles.stream() - .filter(contextHelper::hasEmail) - .collect(toList()); + Collection profilesWithMail = profiles.stream() + .filter(contextHelper::hasEmail) + .collect(toList()); StringBuilder ret = new StringBuilder("mailto:"); - for (UserProfile profile : profiles) { + for (UserProfile profile : profilesWithMail) { if (ret.length() > 7) ret.append(','); ret.append(contextHelper.mailTo(profile)); } @@ -355,7 +355,7 @@ String getMailto(Collection profiles, String subject, boolean signe if (ret.length() > MAX_MAILTO_CHARACTER_COUNT) { ret.setLength(0); ret.append("mailto:"); - for (UserProfile profile : profiles) { + for (UserProfile profile : profilesWithMail) { if (ret.length() > 7) ret.append(','); ret.append(profile.getEmail().trim()); } diff --git a/src/main/resources/css/digital-signature.css b/src/main/resources/css/digital-signature.css index 4fa5a95..a0d8fb9 100644 --- a/src/main/resources/css/digital-signature.css +++ b/src/main/resources/css/digital-signature.css @@ -1,28 +1,28 @@ .panel { - border-width: 1px; + border-width: 1px; } .panel .panelHeader { - border-bottom-width: 1px; - color: #bbb; + border-bottom-width: 1px; + color: #bbb; } .panel .panelHeader .aui-buttons { - float: right + float: right; } .panel .panelHeader .aui-icon.aui-icon-small.aui-iconfont-attachment { - margin-right: 20px; + margin-right: 20px; } .panel .panelHeader .aui-icon.aui-icon-small.aui-iconfont-file-pdf { - float: right; + float: right; } .body-list { - list-style-type: none; + list-style-type: none; } .body-list .body-list-item { - color: #bbb; + color: #bbb; } diff --git a/src/main/resources/js/digital-signature.js b/src/main/resources/js/digital-signature.js index 6ae5a8e..fc75990 100644 --- a/src/main/resources/js/digital-signature.js +++ b/src/main/resources/js/digital-signature.js @@ -1,18 +1,3 @@ -function bindCollapse(ul, limit, showMore) { - if (limit < 0) { - return; - } - - let $ul = AJS.$(ul); - - if (hideElements($ul, limit)) { - $ul.after("" + showMore + ""); - $ul.siblings("a.show-all").bind("click", function () { - showAllElements($ul); - }); - } -} - function hideElements($ul, limit) { const signedList = $ul.find("li.signeelist-signed"); const missingList = $ul.find("li.signeelist-missing"); @@ -24,7 +9,7 @@ function hideElements($ul, limit) { let shownSignees = Math.min(signedList.length, Math.ceil(remainingCount / 2)); remainingCount = remainingCount - shownSignees; for (let i = 0; i < signedList.length - shownSignees; i++) { - AJS.$(signedList[i]).hide() + AJS.$(signedList[i]).hide(); isSomethingHidden = true; } } @@ -41,3 +26,18 @@ function showAllElements($ul) { $ul.find("li").show(); $ul.siblings("a.show-all").remove(); } + +function bindCollapse(ul, limit, showMore) { + if (limit < 0) { + return; + } + + let $ul = AJS.$(ul); + + if (hideElements($ul, limit)) { + $ul.after("" + showMore + ""); + $ul.siblings("a.show-all").bind("click", function () { + showAllElements($ul); + }); + } +} diff --git a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java index 72326fc..44bb605 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/DigitalSignatureMacroTest.java @@ -14,9 +14,8 @@ public class DigitalSignatureMacroTest { - Signature signature = new Signature(1, "test", "title"); - - BootstrapManager bootstrapManager = mock(BootstrapManager.class); + private final Signature signature = new Signature(1, "test", "title"); + private final BootstrapManager bootstrapManager = mock(BootstrapManager.class); @Test public void getMailtoLong() { diff --git a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java index 90c3651..3d60ce5 100644 --- a/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java +++ b/src/test/java/com/baloise/confluence/digitalsignature/InheritSignersTest.java @@ -2,7 +2,9 @@ import org.junit.Test; -import static com.baloise.confluence.digitalsignature.InheritSigners.*; +import static com.baloise.confluence.digitalsignature.InheritSigners.NONE; +import static com.baloise.confluence.digitalsignature.InheritSigners.READERS_ONLY; +import static com.baloise.confluence.digitalsignature.InheritSigners.ofValue; import static org.junit.Assert.assertEquals; public class InheritSignersTest { From 4d7a5a595aac77f9117d40706f2c2440cf7d7ec1 Mon Sep 17 00:00:00 2001 From: Markus Lindenmann Date: Sun, 27 Sep 2020 20:53:00 +0200 Subject: [PATCH 14/15] Version bump to 7.0.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 62eff84..7519547 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 com.baloise.confluence digital-signature - 7.0.1 + 7.0.2 Baloise From 2d802e9c85f260e24da606d7fed3a81c96b50231 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2020 21:18:21 +0000 Subject: [PATCH 15/15] Bump junit from 4.13 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 86f5781..f50f4ca 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ junit junit - 4.13 + 4.13.1 test