1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.web

File CreateAction.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

44
99
10
1
392
191
33
0.33
9.9
10
3.3

Classes

Class Line # Actions
CreateAction 46 99 0% 33 11
0.928104692.8%
 

Contributing tests

This file is covered by 39 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.web;
21   
22    import javax.inject.Provider;
23    import javax.script.ScriptContext;
24   
25    import org.apache.commons.lang3.StringUtils;
26    import org.xwiki.model.reference.DocumentReference;
27    import org.xwiki.model.reference.DocumentReferenceResolver;
28    import org.xwiki.model.reference.EntityReferenceSerializer;
29    import org.xwiki.model.reference.SpaceReference;
30    import org.xwiki.security.authorization.ContextualAuthorizationManager;
31    import org.xwiki.security.authorization.Right;
32   
33    import com.xpn.xwiki.XWiki;
34    import com.xpn.xwiki.XWikiContext;
35    import com.xpn.xwiki.XWikiException;
36    import com.xpn.xwiki.doc.XWikiDocument;
37    import com.xpn.xwiki.objects.BaseObject;
38    import com.xpn.xwiki.util.Util;
39   
40    /**
41    * Create document action.
42    *
43    * @version $Id: 3fff6036e03a2c7a3ec88f53fc3fb9bee40c80a2 $
44    * @since 2.4M2
45    */
 
46    public class CreateAction extends XWikiAction
47    {
48    /**
49    * The name of the create.vm template to render.
50    */
51    private static final String CREATE_TEMPLATE = "create";
52   
53    /**
54    * The name of the parent parameter.
55    */
56    private static final String PARENT = "parent";
57   
58    /**
59    * The name of the space reference parameter.
60    */
61    private static final String SPACE_REFERENCE = "spaceReference";
62   
63    /**
64    * The name parameter.
65    */
66    private static final String NAME = "name";
67   
68    /**
69    * The name of the template field inside the template provider, or the template parameter which can be sent
70    * directly, without passing through the template provider.
71    */
72    private static final String TEMPLATE = "template";
73   
74    /**
75    * Internal name for a flag determining if we are creating a Nested Space or a terminal document.
76    */
77    private static final String IS_SPACE = "isSpace";
78   
79    /**
80    * Space homepage document name.
81    */
82    private static final String WEBHOME = "WebHome";
83   
84    /**
85    * Local entity reference serializer hint.
86    */
87    private static final String LOCAL_SERIALIZER_HINT = "local";
88   
89    /**
90    * Current entity reference resolver hint.
91    */
92    private static final String CURRENT_MIXED_RESOLVER_HINT = "currentmixed";
93   
94    /**
95    * Default constructor.
96    */
 
97  44 toggle public CreateAction()
98    {
99  44 this.waitForXWikiInitialization = false;
100    }
101   
 
102  98 toggle @Override
103    public String render(XWikiContext context) throws XWikiException
104    {
105  98 CreateActionRequestHandler handler = new CreateActionRequestHandler(context);
106   
107    // Read the request and extract the passed information.
108  98 handler.processRequest();
109   
110    // Save the determined values so we have them available in the action template.
111  98 ScriptContext scontext = getCurrentScriptContext();
112  98 scontext.setAttribute(SPACE_REFERENCE, handler.getSpaceReference(), ScriptContext.ENGINE_SCOPE);
113  98 scontext.setAttribute(NAME, handler.getName(), ScriptContext.ENGINE_SCOPE);
114  98 scontext.setAttribute(IS_SPACE, handler.isSpace(), ScriptContext.ENGINE_SCOPE);
115    // put the available templates on the context, for the .vm to not compute them again
116  98 scontext.setAttribute("availableTemplateProviders", handler.getAvailableTemplateProviders(),
117    ScriptContext.ENGINE_SCOPE);
118   
119  98 DocumentReference newDocumentReference = handler.getNewDocumentReference();
120  98 if (newDocumentReference == null) {
121    // There is information still missing, go back to the template and fill it.
122  22 return CREATE_TEMPLATE;
123    }
124   
125    // Check if the creation in the spaceReference is allowed.
126  76 if (!handler.isTemplateProviderAllowedToCreateInCurrentSpace()) {
127    // The selected template provider is not usable in the selected location. Go back to the template and pick
128    // something else.
129  3 return CREATE_TEMPLATE;
130    }
131   
132    // Checking the rights to create the new document.
133    // Note: Note checking the logical spaceReference, but the space of the final actual document reference, since
134    // that is where we are creating the new document.
135  73 checkRights(newDocumentReference.getLastSpaceReference(), context);
136   
137    // Check if the document to create already exists.
138  73 XWikiDocument newDocument = context.getWiki().getDocument(newDocumentReference, context);
139  73 if (handler.isDocumentAlreadyExisting(newDocument)) {
140  4 return CREATE_TEMPLATE;
141    }
142   
143    // Verify if the "type" of document to create has been set, even if we currently do not use it in the action.
144    // The goal is let the user be able to chose it, which have some consequences in the UI (thanks to javascript).
145    // See: http://jira.xwiki.org/browse/XWIKI-12580
146    // Note: we do not need the "type" if we have a template provider: the type of the new document will be the type
147    // of the template.
148    // TODO: handle this type in doCreate() that we call above (see: http://jira.xwiki.org/browse/XWIKI-12585).
149  69 if (StringUtils.isBlank(handler.getType()) && !handler.hasTemplate()) {
150  11 return CREATE_TEMPLATE;
151    }
152   
153    // create is finally valid, can be executed
154  58 doCreate(context, newDocument, handler.isSpace(), handler.getTemplateProvider());
155   
156  58 return null;
157    }
158   
159    /**
160    * @param context the XWiki context
161    * @param spaceReference the reference of the space where the new document will be created
162    * @throws XWikiException in case the permission to create a new document in the specified space is denied
163    */
 
164  73 toggle private void checkRights(SpaceReference spaceReference, XWikiContext context) throws XWikiException
165    {
166  73 ContextualAuthorizationManager authManager = Utils.getComponent(ContextualAuthorizationManager.class);
167  73 if (!authManager.hasAccess(Right.EDIT, spaceReference)) {
168  0 Object[] args = { spaceReference.toString(), context.getUser() };
169  0 throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS, XWikiException.ERROR_XWIKI_ACCESS_DENIED,
170    "The creation of a document into the space {0} has been denied to user {1}", null, args);
171    }
172    }
173   
174    /**
175    * Actually executes the create, after all preconditions have been verified.
176    *
177    * @param context the context of this action
178    * @param newDocument the document to be created
179    * @param isSpace whether the document is a space webhome or a page
180    * @param templateProvider the template provider to create from
181    * @throws XWikiException in case anything goes wrong accessing xwiki documents
182    */
 
183  58 toggle private void doCreate(XWikiContext context, XWikiDocument newDocument, boolean isSpace, BaseObject templateProvider)
184    throws XWikiException
185    {
186  58 XWikiRequest request = context.getRequest();
187  58 XWikiDocument doc = context.getDoc();
188   
189    // resolver to use to resolve references received in request parameters
190  58 DocumentReferenceResolver<String> resolver =
191    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, CURRENT_MIXED_RESOLVER_HINT);
192   
193  58 String parent = getParent(request, doc, isSpace, context);
194   
195    // get the title of the page to create, as specified in the parameters
196  58 String title = getTitle(request, newDocument, isSpace);
197   
198    // get the template from the template parameter, to allow creation directly from template, without
199    // forcing to create a template provider for each template creation
200  58 String template = getTemplate(templateProvider, request);
201   
202    // from the template provider, find out if the document should be saved before edited
203  58 boolean toSave = getSaveBeforeEdit(templateProvider);
204   
205  58 String redirectParams = null;
206  58 String editMode = null;
207  58 if (toSave) {
208  1 XWiki xwiki = context.getWiki();
209   
210  1 DocumentReference templateReference = resolver.resolve(template);
211  1 newDocument.readFromTemplate(templateReference, context);
212  1 if (!StringUtils.isEmpty(parent)) {
213  1 DocumentReference parentReference = resolver.resolve(parent);
214  1 newDocument.setParentReference(parentReference);
215    }
216  1 if (title != null) {
217  1 newDocument.setTitle(title);
218    }
219  1 DocumentReference currentUserReference = context.getUserReference();
220  1 newDocument.setAuthorReference(currentUserReference);
221  1 newDocument.setCreatorReference(currentUserReference);
222   
223  1 xwiki.saveDocument(newDocument, context);
224  1 editMode = newDocument.getDefaultEditMode(context);
225    } else {
226    // put all the data in the redirect params, to be passed to the edit mode
227  57 redirectParams = getRedirectParameters(parent, title, template);
228   
229    // Get the edit mode of the document to create from the specified template
230  57 editMode = getEditMode(template, resolver, context);
231    }
232   
233    // Perform a redirection to the edit mode of the new document
234  58 String redirectURL = newDocument.getURL(editMode, redirectParams, context);
235  58 redirectURL = context.getResponse().encodeRedirectURL(redirectURL);
236  58 if (context.getRequest().getParameterMap().containsKey("ajax")) {
237    // If this template is displayed from a modal popup, send a header in the response notifying that a
238    // redirect must be performed in the calling page.
239  0 context.getResponse().setHeader("redirect", redirectURL);
240    } else {
241    // Perform the redirect
242  58 sendRedirect(context.getResponse(), redirectURL);
243    }
244    }
245   
246    /**
247    * @param context
248    * @param parent
249    * @param title
250    * @param template
251    * @return
252    */
 
253  57 toggle private String getRedirectParameters(String parent, String title, String template)
254    {
255  57 String redirectParams;
256  57 redirectParams = "template=" + Util.encodeURI(template, null);
257  57 if (parent != null) {
258  57 redirectParams += "&parent=" + Util.encodeURI(parent, null);
259    }
260  57 if (title != null) {
261  57 redirectParams += "&title=" + Util.encodeURI(title, null);
262    }
263  57 return redirectParams;
264    }
265   
266    /**
267    * @param templateProvider the set template provider, if any
268    * @param request the request on which to fallback
269    * @return the string reference of the document to use as template or {@code ""} if none set
270    */
 
271  58 toggle private String getTemplate(BaseObject templateProvider, XWikiRequest request)
272    {
273  58 String result = "";
274   
275  58 if (templateProvider != null) {
276  18 result = templateProvider.getStringValue(TEMPLATE);
277  40 } else if (request.getParameter(TEMPLATE) != null) {
278  5 result = request.getParameter(TEMPLATE);
279    }
280   
281  58 return result;
282    }
283   
284    /**
285    * @param request the current request for which this action is executed
286    * @param doc the current document
287    * @param isSpace {@code true} if the request is to create a space, {@code false} if a page should be created
288    * @param context the XWiki context
289    * @return the serialized reference of the parent to create the document for
290    */
 
291  58 toggle private String getParent(XWikiRequest request, XWikiDocument doc, boolean isSpace, XWikiContext context)
292    {
293    // This template can be passed a parent document reference in parameter (using the "parent" parameter).
294    // If a parent parameter is passed, use it to set the parent when creating the new Page or Space.
295    // If no parent parameter was passed:
296    // * use the current document
297    // ** if we're creating a new page and if the current document exists or
298    // * use the Main space's WebHome
299    // ** if we're creating a new page and the current document does not exist.
300  58 String parent = request.getParameter(PARENT);
301  58 if (StringUtils.isEmpty(parent)) {
302  53 EntityReferenceSerializer<String> localSerializer =
303    Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, LOCAL_SERIALIZER_HINT);
304   
305  53 if (doc.isNew()) {
306    // Use the Main space's WebHome.
307  20 Provider<DocumentReference> defaultDocumentReferenceProvider =
308    Utils.getComponent(DocumentReference.TYPE_PROVIDER);
309   
310  20 DocumentReference parentRef =
311    defaultDocumentReferenceProvider.get().setWikiReference(context.getWikiReference());
312   
313  20 parent = localSerializer.serialize(parentRef);
314    } else {
315    // Use the current document.
316  33 DocumentReference parentRef = doc.getDocumentReference();
317   
318  33 parent = localSerializer.serialize(parentRef);
319    }
320    }
321   
322  58 return parent;
323    }
324   
325    /**
326    * @param request the current request for which this action is executed
327    * @param newDocument the document to be created
328    * @param isSpace {@code true} if the request is to create a space, {@code false} if a page should be created
329    * @return the title of the page to be created. If no request parameter is set, the page name is returned for a new
330    * page and the space name is returned for a new space
331    */
 
332  58 toggle private String getTitle(XWikiRequest request, XWikiDocument newDocument, boolean isSpace)
333    {
334  58 String title = request.getParameter("title");
335  58 if (StringUtils.isEmpty(title)) {
336  40 if (isSpace) {
337  22 title = newDocument.getDocumentReference().getLastSpaceReference().getName();
338    } else {
339  18 title = newDocument.getDocumentReference().getName();
340    // Avoid WebHome titles for pages that are really space homepages.
341  18 if (WEBHOME.equals(title)) {
342  0 title = newDocument.getDocumentReference().getLastSpaceReference().getName();
343    }
344    }
345    }
346   
347  58 return title;
348    }
349   
350    /**
351    * @param templateProvider the template provider for this creation
352    * @return {@code true} if the created document should be saved on create, before editing, {@code false} otherwise
353    */
 
354  58 toggle boolean getSaveBeforeEdit(BaseObject templateProvider)
355    {
356  58 boolean toSave = false;
357   
358  58 if (templateProvider != null) {
359    // get the action to execute and compare it to saveandedit value
360  18 String action = templateProvider.getStringValue("action");
361  18 if ("saveandedit".equals(action)) {
362  1 toSave = true;
363    }
364    }
365   
366  58 return toSave;
367    }
368   
369    /**
370    * @param template the template to create document from
371    * @param resolver the resolver to use to resolve the template document reference
372    * @param context the context of the current request
373    * @return the default edit mode for a document created from the passed template
374    * @throws XWikiException in case something goes wrong accessing template document
375    */
 
376  57 toggle private String getEditMode(String template, DocumentReferenceResolver<String> resolver, XWikiContext context)
377    throws XWikiException
378    {
379    // Determine the edit action (edit/inline) for the newly created document, if a template is passed it is
380    // used to determine the action. Default is 'edit'.
381  57 String editAction = "edit";
382  57 XWiki xwiki = context.getWiki();
383  57 if (!StringUtils.isEmpty(template)) {
384  22 DocumentReference templateReference = resolver.resolve(template);
385  22 if (xwiki.exists(templateReference, context)) {
386  21 editAction = xwiki.getDocument(templateReference, context).getDefaultEditMode(context);
387    }
388    }
389   
390  57 return editAction;
391    }
392    }