Move/Rename XWiki page via REST?

Hi all,
is there a built-in REST method that exposes the functionality of “Manage: Move/Rename” web gui element to allow the programmatic renaming of a page and its children? (At least according to REST API (XWiki.org) there isn’t, but on the other hand that document is almost one year old) Or perhaps an extension that offers this as REST functionality?

Best,
Andreas

Hi,

to my knowledge there’s no such thing. One of the reason is that the move/rename operation is generally not a unique operation: when you do that from the UI you also perform several refactoring checks and operations, such as renaming links. It could also trigger questions, like when you try to move a space containing some extension pages.

Now we do provide a script service for refactoring operations (see: https://www.xwiki.org/xwiki/bin/view/ScriptingDocumentation/?url=http:%2F%2Fnexus.xwiki.org%2Fnexus%2Fservice%2Flocal%2Frepositories%2Fpublic%2Farchive%2Forg%2Fxwiki%2Fplatform%2Fxwiki-platform-refactoring-api%2F13.10.3%2Fxwiki-platform-refactoring-api-13.10.3-javadoc.jar%2F!%2Forg%2Fxwiki%2Frefactoring%2Fscript%2FRefactoringScriptService.html) so it could be discussed to have a REST endpoint for same operations, but it would need proper design to support what I mentioned probably.

In the meantime, we have a generic REST endpoint to start any kind of job. See REST API (XWiki.org).

It’s not always easy to generate the right request body unless you are in Java, in which case you can reuse the org.xwiki.rest.internal.ModelFactory component and its #toRestJobRequest which makes things easier. Unfortunately it’s internal so not recommended to count on it on the long run but there will always be a helper like this in a form or another since we need it.

1 Like

Thanks for your your replies guys, I’m trying to go with tmortagne’s pointer for now; I don’t really mind using internal APIs here, since I’m planning to just learn the form of the xml document and use it as a text template later, swapping out parameter values as needed. However, trying to generate the request body via this code

// JAVA START
RenameRequest request = new RenameRequest();
// RenameRequest class definition taken from here:
// Performing Asynchronous Tasks (XWiki.org)
var xwiki = new WikiReference(“xwiki”);
request.setId(UUID.randomUUID().toString());
request.setSpaceReference(new SpaceReference(“TestPage1”, xwiki));
request.setNewSpaceName(“TestPage2”);
request.setCheckRights(false);
request.setInteractive(false);
request.setUserReference(new DocumentReference(new LocalDocumentReference(“Home”, “myuser”), xwiki));

ModelFactory mf = new ModelFactory();
JobRequest rjr = mf.toRestJobRequest(request); // NullPointerException is thrown here
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(JobRequest.class);
Marshaller m = context.createMarshaller();
m.marshal(rjr, writer);
// JAVA END

results in

// STACK TRACE START
Exception in thread “main” java.lang.NullPointerException: Cannot invoke “org.xwiki.rest.internal.JAXBConverter.serializeAny(Object)” because “this.jaxbConverter” is null
at org.xwiki.rest.internal.ModelFactory.toRestMapEntry(ModelFactory.java:1095)
at org.xwiki.rest.internal.ModelFactory.toRestJobRequest(ModelFactory.java:1070)
at xwikitest.XwikiTest.main(XwikiTest.java:81)
// STACK TRACE END

Complete nonsense request parameters aside, this supposedly happens because I’m executing that piece of code standalone outside of a full xwiki instance, and ModelFactory.jaxbConverter isn’t properly injected (the field carries the @inject annotation). Is there a quick-and-easy way to fix this, or is there a factory of factories that I need to use instead of ModelFactory’s constructor?

Thanks,
Andreas

Indeed, ModelFactory is designed to be used inside an XWiki instance.

The simplest would probably be to move your code to a {{groovy}} macro (if you don’t know Groovy it’s OK as the Java syntax mostly works in it, it just adds some shortcuts) in a page of an XWiki instance.
In the Groovy script, you can get the ModelFactory component with services.component.getInstance(org.xwiki.rest.internal.ModelFactory.class).

Thanks again for your help, finally got the XML job request generation to work. However, the result of the HTTP PUT to “https://xwiki.myserver.local/xwiki/rest/jobs” is a code 500 (internal server error) and the helpful error message “Failed to start job” (nothing more).
The job request XML chunk contains verbose=true, remote=true, interactive=false, the job id is randomly generated. I know that it is not an auth problem (in that case the error code is 401). The source space of the renaming operation exists, the target space doesn’t, and the user has all permissions for the parent and its descendants.
Is the REST endpoint URL the right one? Is there a way to get more debug info in the reply?

Thanks,
Andreas

JobRequest.xml
<jobRequest xmlns="http://www.xwiki.org">
  <id>
      <element>9c6157a6-c259-4b4b-aed8-8f0cf17f4f7e</element>
  </id>
  <interactive>false</interactive>
  <remote>true</remote>
  <verbose>true</verbose>
  <property>
      <key>newSpaceName</key>
      <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Notes.Andreas.TestPage2</value>
  </property>
  <property>
      <key>interactive</key>
      <value>
          <boolean>false</boolean>
      </value>
  </property>
  <property>
      <key>spaceReference</key>
      <value>
           <org.xwiki.model.reference.SpaceReference>
               <name>TestPage1</name>
               <parent class="org.xwiki.model.reference.SpaceReference">
                   <name>Andreas</name>
                   <parent class="org.xwiki.model.reference.SpaceReference">
                       <name>Notes</name>
                       <parent class="org.xwiki.model.reference.WikiReference">
                           <name>xwiki</name>
                           <type>WIKI</type>
                       </parent>
                       <type>SPACE</type>
                   </parent>
                   <type>SPACE</type>
               </parent>
               <type>SPACE</type>
           </org.xwiki.model.reference.SpaceReference>
      </value>
  </property>
  <property>
      <key>checkrights</key>
      <value>
          <boolean>false</boolean>
      </value>
  </property>
  <property>
      <key>user.reference</key>
      <value>
          <org.xwiki.model.reference.DocumentReference>
              <name>xwiki</name>
              <parent class="org.xwiki.model.reference.SpaceReference">
                  <name>XWiki</name>
                  <parent class="org.xwiki.model.reference.WikiReference">
                      <name>Andreas</name>
                      <type>WIKI</type>
                  </parent>
                  <type>SPACE</type>
              </parent>
              <type>DOCUMENT</type>
          </org.xwiki.model.reference.DocumentReference>
      </value>
  </property>
</jobRequest>

P. S.: It just hit me that nowhere in my jobRequest xml chunk I state what kind of job I would like performed. How do I get this across? Is it a REST endpoint other than /xwiki/rest/jobs, or an additional property or element in the XML?

As indicated on REST API (XWiki.org) there is a jobType URL parameter to pass.