Confluence CLI cannot add a label to an attachment

Simon Tideswell April 18, 2013

Hello

The environment is Confluence 5.02 on CentOS 6.4 x86_64 with PostgreSQL 8.4.13. I am using Confluence CLI 3.1.0. I am running the CLI from a shell-script.

If I do ...

$CONFLUENCE -a addLabels --labels "$id" --id "$id"

... then it works perfectly if $id is the Id of a page returned from 'getPageList'. However if I use the Id returned from getAttachmentList it fails, like this ...

"Client error: Page with id 13959177 not found or you are not authorized to it."

I was intending on adding a label to all content (pages and attachments) in order to assist with searchability.

Because I'm just trying to get a job done and don't care how I do it, here's some background. Perhaps you have a plugin that achieves what I'm trying in another way? I have been asked to use Confluence as a knowledgebase and to have each article searchable by Id. This seems like a reasonable request, having a consistent Id to refer to each piece of content by would be a good idea. Is the behaviour I'm seeing a bug? Is it likely to be fixed at some stage? I assure you that the Confluence web UI does allow you to add a label to an attachment.

Thanks for any help you can give. Simon.

11 answers

1 accepted

4 votes
Answer accepted
Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
April 30, 2013

I got tired of seeing questions on this site where the answer is "you can't do this with the remote API, sorry", so I'm starting work on a plugin that adds in the missing features.

First cab off the rank is starting with adding labels to attachments! I've just released a first version, which you can grab and install using the "Manage Add-ons" console from here: https://maven.atlassian.com/contrib//au/id/jaysee/confluence/plugins/confluence-missing-api/1.0/confluence-missing-api-1.0.jar

And here's some sample usage:

curl -u admin:admin -H "Content-Type: application/json" -H "Accept: application/json" -d @data.txt http://localhost:1
990/confluence/rpc/json-rpc/missing-api/addLabelToAttachmentByName?os_authType=basic

You'll need to replace "admin:admin" with your own username and password that you want to login with, and you'll need to use your own Confluence URL.

Here's the contents of my data.txt. The three values are the label name, the parent page/blog ID, and the attachment filename:

["my label", "98334", "my-attachment-file.txt"]

This plugin is completely un-official and not supported by Atlassian, and we offer no warranties as to what might happen if you install it. I'm happy to help sort out any problems with it, though :)

Hanchel C September 22, 2013

Joseph, does this plugin work with Conf 4.x?

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
October 1, 2013

Yes, it certainly should. Let me know if it doesn't.

Hanchel C November 4, 2013

Joseph,
Whenever I try to label the attachment, I receive an html response telling me the page cannot be found. I have the correct page ID and attachment name in the data.txt and I can definitely access the Confluence page since I created it and attached the attachment myself. Have you encountered this problem before? Do you know what may be a possible cause?
Thanks!!

1 vote
Simon Tideswell May 6, 2013

Hello Joseph

BINGO!!! It works like a charm. No restart of Confluence was required (Confluence 5.02 on CentOS 6.4 x86_64/Postgres 8.4.13).

Thanks for your help. This plugin is a life-saver.

Simon

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 7, 2013

Woot :-) No problem, glad to help. When I have some time I'll tidy it up and put it on the Marketplace for others to use.

0 votes
Simon Tideswell November 6, 2013

Hello Joseph

I've found what may be another problem with this plugin. If the attachment has weird characters in the filename then the label addition fails.

An example filename that fails is ...

$ ls Vmware\ –\ Adding\ Memory\ and\ Enabling\ Hot\ Add.docx | hexdump -C

00000000 56 6d 77 61 72 65 20 e2 80 93 20 41 64 64 69 6e |Vmware ... Addin|

00000010 67 20 4d 65 6d 6f 72 79 20 61 6e 64 20 45 6e 61 |g Memory and Ena|

00000020 62 6c 69 6e 67 20 48 6f 74 20 41 64 64 2e 64 6f |bling Hot Add.do|

00000030 63 78 0a |cx.|

00000033

... which contains a long dash in the filename (e2 80 93) which is presumably some unicode character. Unfortunately this is happening quite frequently with people who use M$ Word and copy the document title into the filename.

The error returned is

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=67E5F82B25DB9772F6EA3AE87CEE71E8; Path=/; HttpOnly
X-Seraph-LoginReason: OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 06 Nov 2013 19:56:06 GMT

{"jsonrpc":"2.0","id":null,"error":{"message":"The application was unable to serve your request: java.lang.IllegalArgumentException: The validated object is null","data":"java.lang.IllegalArgumentException: The validated object is null\njava.lang.IllegalArgumentException: The validated object is null\n\tat org.apache.commons.lang.Validate.notNull(Validate.java:192)\n\tat org.apache.commons.lang.Validate.notNull(Validate.java:178)\n\tat au.id.jaysee.confluence.plugins.stuffs.LabelStuff$1.doInTransaction(LabelStuff.java:63)\n\tat au.id.jaysee.confluence.plugins.stuffs.LabelStuff$1.doInTransaction(LabelStuff.java:51)\n\tat com.atlassian.sal.core.transaction.HostContextTransactionTemplate$1.doInTransaction(HostContextTransactionTemplate.java:25)\n\tat com.atlassian.sal.spring.component.SpringHostContextAccessor$1.doInTransaction(SpringHostContextAccessor.java:88)\n\tat org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:128)\n\tat com.atla
ssian.sal.spring.component.SpringHostContextAccessor.doInTransaction(SpringHostContextAccessor.java:82)\n\tat sun.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\n\tat java.lang.reflect.Method.invoke(Unknown Source)\n\tat com.atlassian.plugin.osgi.hostcomponents.impl.DefaultComponentRegistrar$ContextClassLoaderSettingInvocationHandler.invoke(DefaultComponentRegistrar.java:129)\n\tat com.sun.proxy.$Proxy198.doInTransaction(Unknown Source)\n\tat sun.reflect.GeneratedMethodAccessor105.invoke(Unknown Source)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\n\tat java.lang.reflect.Method.invoke(Unknown Source)\n\tat com.atlassian.plugin.osgi.bridge.external.HostComponentFactoryBean$DynamicServiceInvocationHandler.invoke(HostComponentFactoryBean.java:154)\n\tat com.sun.proxy.$Proxy198.doInTransaction(Unknown Source)\n\tat com.atlassian.sal.core.transaction.HostContextTransactionTemp
 late.execute(HostContextTransactionTemplate.java:21)\n\tat sun.reflect.GeneratedMethodAccessor432.invoke(Unknown Source)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\n\tat java.lang.reflect.Method.invoke(Unknown Source)\n\tat org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)\n\tat org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58)\n\tat org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)\n\tat org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)\n\tat org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)\n\tat org.springframework.aop.framework.ReflectiveMeth
 odInvocation.proceed(ReflectiveMethodInvocation.java:171)\n\tat org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:56)\n\tat org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:39)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)\n\tat org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)\n\tat org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)\n\tat org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveM
 ethodInvocation.java:171)\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)\n\tat com.sun.proxy.$Proxy1508.execute(Unknown Source)\n\tat au.id.jaysee.confluence.plugins.stuffs.LabelStuff.addLabelToAttachmentByName(LabelStuff.java:50)\n\tat au.id.jaysee.confluence.plugins.MissingConfluenceApiImpl.addLabelToAttachmentByName(MissingConfluenceApiImpl.java:21)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)\n\tat java.lang.reflect.Method.invoke(Unknown Source)\n\tat com.atlassian.rpc.jsonrpc.SoapModuleMethodMapper.call(SoapModuleMethodMapper.java:120)\n\tat com.atlassian.voorhees.JsonRpcHandler.executeMethod(JsonRpcHandler.java:235)\n\tat com.atlassian.voorhees.JsonRpcHandler.process(JsonRpcHandler.java:83)\n\tat com.atlassian.rpc.jsonrpc.JsonRpcFilter.doFilter(JsonRpcFilter.java:76)\
 n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.plugin.remotable.plugin.module.permission.ApiScopingFilter.doFilter(ApiScopingFilter.java:62)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n
 \tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerFilter.java:77)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerFilter.java:63)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.core.filters.ServletContextThreadLocalFilter.doFilter(ServletContextThreadLocalFilter.java:21)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.conf
 luence.util.LoggingContextFilter.doFilter(LoggingContextFilter.java:40)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.seraph.filter.SecurityFilter.doFilter(SecurityFilter.java:211)\n\tat com.atlassian.confluence.web.filter.ConfluenceSecurityFilter.doFilter(ConfluenceSecurityFilter.java:28)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.web.filter.ThreadLocalCacheFilter.doFilter(ThreadLocalCacheFilter.java:22)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina
 .core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.security.auth.trustedapps.filter.TrustedApplicationsFilter.doFilter(TrustedApplicationsFilter.java:98)\n\tat com.atlassian.confluence.util.AbstractBootstrapHotSwappingFilter.doFilter(AbstractBootstrapHotSwappingFilter.java:30)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.seraph.filter.BaseLoginFilter.doFilter(BaseLoginFilter.java:150)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java
 :46)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.oauth.serviceprovider.internal.servlet.OAuthFilter.doFilter(OAuthFilter.java:55)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerF
 ilter.java:77)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerFilter.java:63)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.util.ClusterHeaderFilter.doFilter(ClusterHeaderFilter.java:37)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.util.profiling.filters.ProfilingFilter.doFilter(ProfilingFilter.java:99)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.gzipfilter.GzipFilter.doFilterInterna
 l(GzipFilter.java:80)\n\tat com.atlassian.gzipfilter.GzipFilter.doFilter(GzipFilter.java:51)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.core.filters.cache.AbstractCachingFilter.doFilter(AbstractCachingFilter.java:33)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:46)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.plugin.remotable.plugin.module.oauth.OAuth2LOFilter.doFilter(OAuth2LOFilter.
 java:70)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.plugin.remotable.host.common.service.http.bigpipe.BigPipeRequestIdFilter.doFilter(BigPipeRequestIdFilter.java:35)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.prettyurls.filter.PrettyUrlsCombinedMatchDispatcherFilter.doFilter(PrettyUrlsCombinedMatchDispatcherFilter.java:61)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(Dele
 gatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter$1.doFilter(DelegatingPluginFilter.java:66)\n\tat com.atlassian.confluence.extra.webdav.servlet.filter.ReverseProxyFilter.doFilter(ReverseProxyFilter.java:427)\n\tat com.atlassian.confluence.extra.webdav.servlet.filter.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:34)\n\tat com.atlassian.plugin.servlet.filter.DelegatingPluginFilter.doFilter(DelegatingPluginFilter.java:74)\n\tat com.atlassian.plugin.servlet.filter.IteratingFilterChain.doFilter(IteratingFilterChain.java:42)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerFilter.java:77)\n\tat com.atlassian.plugin.servlet.filter.ServletFilterModuleContainerFilter.doFilter(ServletFilterModuleContainerFilter.java:63)\n\tat org.apache.catalina.core.ApplicationFilterChai
 n.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.web.filter.validateparam.RequestParamValidationFilter.doFilter(RequestParamValidationFilter.java:58)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.web.filter.TranslationModeFilter.doFilter(TranslationModeFilter.java:43)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.conflue
 nce.plugin.servlet.filter.ActionContextCleanUp.doFilter(ActionContextCleanUp.java:71)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.web.filter.LanguageExtractionFilter.doFilter(LanguageExtractionFilter.java:53)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.util.RequestCacheThreadLocalFilter.doFilter(RequestCacheThreadLocalFilter.java:25)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.
 java:206)\n\tat com.atlassian.confluence.web.filter.DebugFilter.doFilter(DebugFilter.java:44)\n\tat com.atlassian.core.filters.AbstractHttpFilter.doFilter(AbstractHttpFilter.java:31)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.core.filters.HeaderSanitisingFilter.doFilter(HeaderSanitisingFilter.java:44)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)\n\tat com.atlassian.confluence.servlet.FourOhFourErrorLoggingFilter.doFilter(FourOhFourErrorLoggingFilter.java:65)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java
 :206)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)\n\tat org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)\n\tat org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)\n\tat org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)\n\tat java.lang.Thread.run(Unknown Source)\n","code":500}}
0 votes
Simon Tideswell May 17, 2013

Hello Joseph

It does happen. It is on a page that was created by importing from a Word document by the look of it. I can show you more evidence of this kind of scenario if you wish, it definitely occurs? However on our Confluence server it only happens on this single page, it happens 19 times on that page, but only that page shows any sign of this.

I created the list of attachments and labels using the Confluence CLI, from memory, so it isn’t hard to find the attachment Id. A direct DB query will obviously achieve the same thing.

If you are of the opinion that it can’t happen - but clearly it can :o) – then we can probably safely assume that the circumstance that caused the creation of these ‘duplicate attachments’ is very unlikely and will almost certainly not occur again. In that case I’m happy to leave things as they are, manually fix up these entries and treat this as a ‘one-off’.

Simon

0 votes
Simon Tideswell May 12, 2013

Hello Joseph

So you are gonna really hate me, but I've discovered a minor deficiency with the missing API plugin in relation to label management on attachments.

Believe it or not it is possible for a file attachment with name X to appear twice under the same parent page, and when the plugin labels the attachment there is currently no way of distinguishing which copy of the attachment the label should apply to. The example below will help illustrate.

Two copies of file worddav815c41d775e43c98108d1e0cc43b4a91.png appear under parent page 16842763.

confluence=# select * from attachments where title = 'worddav815c41d775e43c98108d1e0cc43b4a91.png';

attachmentid | title | contenttype | pageid | creator | creationdate | lastmodifier | lastmoddate | filesize | attachment_comment | at

tversion | prevver

--------------+---------------------------------------------+-------------+----------+---------+-------------------------+--------------+-------------------------+----------+-------------------------------+---

---------+---------

16908312 | worddav815c41d775e43c98108d1e0cc43b4a91.png | image/png | 16842763 | johncr | 2013-04-07 21:14:20.115 | johncr | 2013-04-07 21:14:20.115 | 113830 | imported from a Word document |

1 |

16908329 | worddav815c41d775e43c98108d1e0cc43b4a91.png | image/png | 16842763 | johncr | 2013-04-07 21:14:26.694 | johncr | 2013-04-07 21:14:26.694 | 113830 | imported from a Word document |

1 |

(2 rows)

The missing API plugin has created the two labels I desired (I'm labelling each attachment with a string the same as the attachmentid).

confluence=# select * from label where name = '16908312' or name = '16908329';

labelid | name | owner | namespace | creationdate | lastmoddate

----------+----------+-------+-----------+-------------------------+-------------------------

20846851 | 16908329 | | global | 2013-05-13 11:55:45.617 | 2013-05-13 11:55:45.617

20846868 | 16908312 | | global | 2013-05-13 11:55:47.718 | 2013-05-13 11:55:47.718

(2 rows)

But the labels have both been applied to the attachment with attachmentid 16908312.

confluence=# select * from content_label where labelid = 20846851 or labelid = 20846868;

id | labelid | contentid | owner | creationdate | lastmoddate | attachmentid | pagetemplateid | labelableid | labelabletype

----------+----------+-----------+-------+-------------------------+-------------------------+--------------+----------------+-------------+---------------

20879619 | 20846851 | | admin | 2013-05-13 11:55:45.617 | 2013-05-13 11:55:45.617 | 16908312 | | 16908312 | ATTACHMENT

20879636 | 20846868 | | admin | 2013-05-13 11:55:47.718 | 2013-05-13 11:55:47.718 | 16908312 | | 16908312 | ATTACHMENT

(2 rows)

Believe it or not there a quite a few such occurences in our live Confluence wiki - that's the beauty of real, live, end-user data, it throws up these oddities.
This issue is not a big deal: it only affects 19 attachments out of some hundreds, but it would be nice to resolve it by making the missing API distinguish which attachment it was going to label by attachmentid rather than (or additionally to) the filename.
Simon
Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 16, 2013

Well, that's a bit strange! That is supposed to never happen - all of Confluence's code relies on uniquely identifying an attachment by its filename and parent page ID! The attachment ID is just used to enforce uniqueness in the database - it's not used anywhere else.

I could give you an API to call where you can provide the attachment ID instead of the page Id/filename, but then you'd need a way to get the ID of the attachment in the first place. As an end-user, when applying a label to two attachments with the same filename, how would you even tell which is the one you want to apply the label to anyway? :)

0 votes
Simon Tideswell May 5, 2013

Maaate, you are an absolute pearl, thanks for agreeing to sort out that aspect. Other than that minor problem the plugin is exactly 'what the doctor ordered'.

Thanks, Simon.

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 5, 2013

Here's the latest version with the bugfix we discussed - https://maven.atlassian.com/contrib//au/id/jaysee/confluence/plugins/confluence-missing-api/1.1/confluence-missing-api-1.1.jar

Note that due to a bug in Confluence, you might need to restart your Confluence server after installing the new version of this plugin over the old one.

Let me know if it works (or doesn't!) :)

0 votes
Simon Tideswell May 5, 2013

Hello

When I saw that someone else had accepted this answer it prompted me to give it another try, after my initial failed attempt. I have noticed that the plugin does work, but it has a significant bug.

The bug is that the plugin only works if I have only one version of an attachment, if I have multiple versions of an attachment (and in my use case that is exactly what happens) then the plugin fails. What actually happens is the plugin doesn't put the label on the latest version of the attachment (the one with highest 'attversion' column value and a NULL value in the 'prevver' column).

Here's some example data.

First I only have a single version of the attachment called Simon.txt on pageid 11240138.

confluence=# select * from label where name = 'lovelylabel';

labelid | name | owner | namespace | creationdate | lastmoddate

----------+-------------+-------+-----------+-------------------------+-------------------------

20709377 | lovelylabel | | global | 2013-05-06 11:39:33.465 | 2013-05-06 11:39:33.465

(1 row)

confluence=# select * from content_label where labelid = '20709377';

id | labelid | contentid | owner | creationdate | lastmoddate | attachmentid | pagetemplateid | labelableid | labelabletype

----------+----------+-----------+-------+-------------------------+-------------------------+--------------+----------------+-------------+---------------

20742147 | 20709377 | | admin | 2013-05-06 12:09:40.058 | 2013-05-06 12:09:40.058 | 20774914 | | 20774914 | ATTACHMENT

(1 row)

confluence=# select * from attachments where attachmentid = 20774914;

attachmentid | title | contenttype | pageid | creator | creationdate | lastmodifier | lastmoddate | filesize | attachment_comment |

attversion | prevver

--------------+-----------+-------------+----------+---------+-------------------------+--------------+-------------------------+----------+--------------------+

------------+---------

20774914 | Simon.txt | text/plain | 11240138 | simont | 2013-05-06 12:08:43.349 | simont | 2013-05-06 12:08:43.349 | 8 | |

1 |

(1 row)

Then if I remove the label, upload multiple versions of the attachment and then run the same command to add a label I get ...
confluence=# select * from label where name = 'lovelylabel';
labelid | name | owner | namespace | creationdate | lastmoddate
----------+-------------+-------+-----------+------------------------+------------------------
20709378 | lovelylabel | | global | 2013-05-06 12:17:23.25 | 2013-05-06 12:17:23.25
(1 row)
confluence=# select * from content_label where labelid = '20709378';
id | labelid | contentid | owner | creationdate | lastmoddate | attachmentid | pagetemplateid | labelableid | labelabletype
----------+----------+-----------+-------+-------------------------+-------------------------+--------------+----------------+-------------+---------------
20742148 | 20709378 | | admin | 2013-05-06 12:17:23.252 | 2013-05-06 12:17:23.252 | 20774915 | | 20774915 | ATTACHMENT
(1 row)
confluence=# select * from attachments where title = 'Simon.txt';
attachmentid | title | contenttype | pageid | creator | creationdate | lastmodifier | lastmoddate | filesize | attachment_comment |
attversion | prevver
--------------+-----------+-------------+----------+---------+-------------------------+--------------+-------------------------+----------+--------------------+
------------+----------
20774914 | Simon.txt | text/plain | 11240138 | simont | 2013-05-06 12:16:31.705 | simont | 2013-05-06 12:16:31.705 | 70 | |
4 |
20774915 | Simon.txt | text/plain | 11240138 | simont | 2013-05-06 12:08:43.349 | simont | 2013-05-06 12:08:43.349 | 8 | |
1 | 20774914
20774916 | Simon.txt | text/plain | 11240138 | simont | 2013-05-06 12:15:58.664 | simont | 2013-05-06 12:15:58.664 | 21 | |
2 | 20774914
20774917 | Simon.txt | text/plain | 11240138 | simont | 2013-05-06 12:16:16.638 | simont | 2013-05-06 12:16:16.638 | 48 | |
3 | 20774914
(4 rows)

The label should have been placed on attachmentid 20774914 not 20774915. If this could be fixed the plugin would save me a lot of bother.

Simon

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 5, 2013

Aha! Well spotted. I was about to do some more investigation on this today. I'll fix this problem up and release a new version for you.

(I will also un-mark the accepted answer until you're satisfied with my solution... not sure why it got accepted in the first place :))

0 votes
Simon Tideswell May 1, 2013

Hello Joseph

I removed "/confluence" from the URL and got a better result. However the label was still not created. The logs don't show any errors, nor does the output below. I'll double-check all the details again, but I'm pretty sure I've followed the instructions quite accurately.

Simon

* About to connect() to 127.0.0.1 port 8080 (#0)

* Trying 127.0.0.1... connected

* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)

* Server auth using Basic with user 'admin'

> POST /rpc/json-rpc/missing-api/addLabelToAttachmentByName?os_authType=basic HTTP/1.1

> Authorization: Basic **************************

> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.6.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2

> Host: 127.0.0.1:8080

> Content-Type: application/json

> Accept: application/json

> Content-Length: 61

>

< HTTP/1.1 200 OK

< Server: Apache-Coyote/1.1

< Set-Cookie: JSESSIONID=A726C265B9EC008E38966DD98C61C36F; Path=/; HttpOnly

< X-Seraph-LoginReason: OK

< Content-Length: 0

< Date: Thu, 02 May 2013 07:57:51 GMT

<

* Connection #0 to host 127.0.0.1 left intact

* Closing connection #0

0 votes
Simon Tideswell May 1, 2013

Hello

I also thought the details of the plugin, as viewed in 'Manage Add-ons' might be useful. It doesn't mention the JSON-RPC module in the list of modules, but that may be entirely as expected?

Simon

The Confluence Missing API Plugin (XML-RPC, JSON-RPC and SOAP)

Missing Confluence API methods accessible via SOAP

(missing-api-soap)

Exposes the Confluence Missing API over SOAP

Missing Confluence API methods accessible via XML-RPC

(missing-api-xmlrpc)

Exposes the Confluence Missing API over XML-RPC

transactionTemplate

Import the com.atlassian.sal.api.transaction.TransactionTemplate

Miscellaneous label-related code

(labelStuff)

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 1, 2013

yep, that's normal. The JSON-RPC stuff is enabled "for free" by Confluence over the top of any SOAP module. Plugins don't have to write any code in order to enable JSON-RPC support.

0 votes
Simon Tideswell May 1, 2013

Hello Joseph

Thanks for your response. I spent a fair bit of time writing a Perl script to make the necessary changes to the underlying tables (label and content_label) which works well, but alas the changes are not reliably picked up by Confluence until you remove the Lucene indexes and bounce Confluence, which is 'do-able' but not desirable. So then I was considering using 'Luke' to try and muck around with the indexes from a script after the labels have been created - that was going to consume more time. So it is good news that you have developed this plugin to achieve exactly what I'm after. Thanks for doing that.

I installed your plugin and tested it out but am getting a HTTP 404 error. Excerpts below ...

> POST /confluence/rpc/json-rpc/missing-api/addLabelToAttachmentByName?os_authType=basic HTTP/1.1

> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.13.6.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2

> Host: 127.0.0.1:8080

> Content-Type: application/json

> Accept: application/json

< HTTP/1.1 404 Not Found

< Server: Apache-Coyote/1.1

... yes I know this is heavily edited, but I believe the relevant portions are there. Apart from installing the plugin is there anything else I need to do to the Confluence server for the request to get appropriately directed?

Thanks, Simon.

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
May 1, 2013

Hey Simon, does your Confluence server have a context path of "/confluence"? For example, to access the dashboard of my local instance, it's "http://localhost:1990/confluence/dashboard.action".

Whereas, for you, the dashboard may be located at "http://localhost:8080/dashboard.action". If you don't have "/confluence" in your base URL, then drop it from the curl command.

Apologies if you're intimately familiar with base URL problems :-)

Alternatively, see if you can hit the URL to get the generated WSDL for the SOAP endpoint.

It should be at: http://CONFLUENCE-URL/rpc/soap-axis/missing-api?wsdl

You should get an XML WSDL response. If you get a 404 Not Found there, then go into the Manage Add-ons console and make sure that the missing API plugin is enabled and that all of the modules are enabled.

Failing that, could you please have a look in your application log file for any errors or exceptions? You can locate the confluence log by following our docs: https://confluence.atlassian.com/display/DOC/Working+with+Confluence+Logs#WorkingwithConfluenceLogs-FindingtheConfluenceLogFiles

0 votes
Bob Swift OSS (Bob Swift Atlassian Apps)
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 18, 2013

addLabels action is only valid for pages, blog posts, and spaces. You can open an improvement request, but there is no remote API support currently available for adding labels to attachments.

Bob Swift OSS (Bob Swift Atlassian Apps)
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
September 22, 2013

CSOAP-210 was opened and fixed. The support is avaiable in release 3.6. No plugin is required, so this will work on OnDemand.

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events