1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package com.xpn.xwiki.web

File CreateAction.java

 

Coverage histogram

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

Code metrics

44
100
10
1
394
193
33
0.33
10
10
3.3

Classes

Class Line # Actions
CreateAction 46 100 0% 33 11
0.928571492.9%
 

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: 25f0f7821f12b80e1b656b4ce01e90ded6912b43 $
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  45 toggle public CreateAction()
98    {
99  45 this.waitForXWikiInitialization = false;
100    }
101   
 
102  104 toggle @Override
103    public String render(XWikiContext context) throws XWikiException
104    {
105  104 CreateActionRequestHandler handler = new CreateActionRequestHandler(context);
106   
107    // Read the request and extract the passed information.
108  104 handler.processRequest();
109   
110    // Save the determined values so we have them available in the action template.
111  104 ScriptContext scontext = getCurrentScriptContext();
112  104 scontext.setAttribute(SPACE_REFERENCE, handler.getSpaceReference(), ScriptContext.ENGINE_SCOPE);
113  104 scontext.setAttribute(NAME, handler.getName(), ScriptContext.ENGINE_SCOPE);
114  104 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  104 scontext.setAttribute("availableTemplateProviders", handler.getAvailableTemplateProviders(),
117    ScriptContext.ENGINE_SCOPE);
118  104 scontext.setAttribute("recommendedTemplateProviders", handler.getRecommendedTemplateProviders(),
119    ScriptContext.ENGINE_SCOPE);
120   
121  104 DocumentReference newDocumentReference = handler.getNewDocumentReference();
122  104 if (newDocumentReference == null) {
123    // There is information still missing, go back to the template and fill it.
124  28 return CREATE_TEMPLATE;
125    }
126   
127    // Check if the creation in the spaceReference is allowed.
128  76 if (!handler.isTemplateProviderAllowedToCreateInCurrentSpace()) {
129    // The selected template provider is not usable in the selected location. Go back to the template and pick
130    // something else.
131  3 return CREATE_TEMPLATE;
132    }
133   
134    // Checking the rights to create the new document.
135    // Note: Note checking the logical spaceReference, but the space of the final actual document reference, since
136    // that is where we are creating the new document.
137  73 checkRights(newDocumentReference.getLastSpaceReference(), context);
138   
139    // Check if the document to create already exists.
140  73 XWikiDocument newDocument = context.getWiki().getDocument(newDocumentReference, context);
141  73 if (handler.isDocumentAlreadyExisting(newDocument)) {
142  4 return CREATE_TEMPLATE;
143    }
144   
145    // Verify if the "type" of document to create has been set, even if we currently do not use it in the action.
146    // The goal is let the user be able to chose it, which have some consequences in the UI (thanks to javascript).
147    // See: https://jira.xwiki.org/browse/XWIKI-12580
148    // Note: we do not need the "type" if we have a template provider: the type of the new document will be the type
149    // of the template.
150    // TODO: handle this type in doCreate() that we call above (see: https://jira.xwiki.org/browse/XWIKI-12585).
151  69 if (StringUtils.isBlank(handler.getType()) && !handler.hasTemplate()) {
152  11 return CREATE_TEMPLATE;
153    }
154   
155    // create is finally valid, can be executed
156  58 doCreate(context, newDocument, handler.isSpace(), handler.getTemplateProvider());
157   
158  58 return null;
159    }
160   
161    /**
162    * @param context the XWiki context
163    * @param spaceReference the reference of the space where the new document will be created
164    * @throws XWikiException in case the permission to create a new document in the specified space is denied
165    */
 
166  73 toggle private void checkRights(SpaceReference spaceReference, XWikiContext context) throws XWikiException
167    {
168  73 ContextualAuthorizationManager authManager = Utils.getComponent(ContextualAuthorizationManager.class);
169  73 if (!authManager.hasAccess(Right.EDIT, spaceReference)) {
170  0 Object[] args = { spaceReference.toString(), context.getUser() };
171  0 throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS, XWikiException.ERROR_XWIKI_ACCESS_DENIED,
172    "The creation of a document into the space {0} has been denied to user {1}", null, args);
173    }
174    }
175   
176    /**
177    * Actually executes the create, after all preconditions have been verified.
178    *
179    * @param context the context of this action
180    * @param newDocument the document to be created
181    * @param isSpace whether the document is a space webhome or a page
182    * @param templateProvider the template provider to create from
183    * @throws XWikiException in case anything goes wrong accessing xwiki documents
184    */
 
185  58 toggle private void doCreate(XWikiContext context, XWikiDocument newDocument, boolean isSpace, BaseObject templateProvider)
186    throws XWikiException
187    {
188  58 XWikiRequest request = context.getRequest();
189  58 XWikiDocument doc = context.getDoc();
190   
191    // resolver to use to resolve references received in request parameters
192  58 DocumentReferenceResolver<String> resolver =
193    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, CURRENT_MIXED_RESOLVER_HINT);
194   
195  58 String parent = getParent(request, doc, isSpace, context);
196   
197    // get the title of the page to create, as specified in the parameters
198  58 String title = getTitle(request, newDocument, isSpace);
199   
200    // get the template from the template parameter, to allow creation directly from template, without
201    // forcing to create a template provider for each template creation
202  58 String template = getTemplate(templateProvider, request);
203   
204    // from the template provider, find out if the document should be saved before edited
205  58 boolean toSave = getSaveBeforeEdit(templateProvider);
206   
207  58 String redirectParams = null;
208  58 String editMode = null;
209  58 if (toSave) {
210  1 XWiki xwiki = context.getWiki();
211   
212  1 DocumentReference templateReference = resolver.resolve(template);
213  1 newDocument.readFromTemplate(templateReference, context);
214  1 if (!StringUtils.isEmpty(parent)) {
215  1 DocumentReference parentReference = resolver.resolve(parent);
216  1 newDocument.setParentReference(parentReference);
217    }
218  1 if (title != null) {
219  1 newDocument.setTitle(title);
220    }
221  1 DocumentReference currentUserReference = context.getUserReference();
222  1 newDocument.setAuthorReference(currentUserReference);
223  1 newDocument.setCreatorReference(currentUserReference);
224   
225  1 xwiki.saveDocument(newDocument, context);
226  1 editMode = newDocument.getDefaultEditMode(context);
227    } else {
228    // put all the data in the redirect params, to be passed to the edit mode
229  57 redirectParams = getRedirectParameters(parent, title, template);
230   
231    // Get the edit mode of the document to create from the specified template
232  57 editMode = getEditMode(template, resolver, context);
233    }
234   
235    // Perform a redirection to the edit mode of the new document
236  58 String redirectURL = newDocument.getURL(editMode, redirectParams, context);
237  58 redirectURL = context.getResponse().encodeRedirectURL(redirectURL);
238  58 if (context.getRequest().getParameterMap().containsKey("ajax")) {
239    // If this template is displayed from a modal popup, send a header in the response notifying that a
240    // redirect must be performed in the calling page.
241  0 context.getResponse().setHeader("redirect", redirectURL);
242    } else {
243    // Perform the redirect
244  58 sendRedirect(context.getResponse(), redirectURL);
245    }
246    }
247   
248    /**
249    * @param xcontext
250    * @param parent
251    * @param title
252    * @param template
253    * @return
254    */
 
255  57 toggle private String getRedirectParameters(String parent, String title, String template)
256    {
257  57 String redirectParams;
258  57 redirectParams = "template=" + Util.encodeURI(template, null);
259  57 if (parent != null) {
260  57 redirectParams += "&parent=" + Util.encodeURI(parent, null);
261    }
262  57 if (title != null) {
263  57 redirectParams += "&title=" + Util.encodeURI(title, null);
264    }
265  57 return redirectParams;
266    }
267   
268    /**
269    * @param templateProvider the set template provider, if any
270    * @param request the request on which to fallback
271    * @return the string reference of the document to use as template or {@code ""} if none set
272    */
 
273  58 toggle private String getTemplate(BaseObject templateProvider, XWikiRequest request)
274    {
275  58 String result = "";
276   
277  58 if (templateProvider != null) {
278  18 result = templateProvider.getStringValue(TEMPLATE);
279  40 } else if (request.getParameter(TEMPLATE) != null) {
280  5 result = request.getParameter(TEMPLATE);
281    }
282   
283  58 return result;
284    }
285   
286    /**
287    * @param request the current request for which this action is executed
288    * @param doc the current document
289    * @param isSpace {@code true} if the request is to create a space, {@code false} if a page should be created
290    * @param context the XWiki context
291    * @return the serialized reference of the parent to create the document for
292    */
 
293  58 toggle private String getParent(XWikiRequest request, XWikiDocument doc, boolean isSpace, XWikiContext context)
294    {
295    // This template can be passed a parent document reference in parameter (using the "parent" parameter).
296    // If a parent parameter is passed, use it to set the parent when creating the new Page or Space.
297    // If no parent parameter was passed:
298    // * use the current document
299    // ** if we're creating a new page and if the current document exists or
300    // * use the Main space's WebHome
301    // ** if we're creating a new page and the current document does not exist.
302  58 String parent = request.getParameter(PARENT);
303  58 if (StringUtils.isEmpty(parent)) {
304  53 EntityReferenceSerializer<String> localSerializer =
305    Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, LOCAL_SERIALIZER_HINT);
306   
307  53 if (doc.isNew()) {
308    // Use the Main space's WebHome.
309  20 Provider<DocumentReference> defaultDocumentReferenceProvider =
310    Utils.getComponent(DocumentReference.TYPE_PROVIDER);
311   
312  20 DocumentReference parentRef =
313    defaultDocumentReferenceProvider.get().setWikiReference(context.getWikiReference());
314   
315  20 parent = localSerializer.serialize(parentRef);
316    } else {
317    // Use the current document.
318  33 DocumentReference parentRef = doc.getDocumentReference();
319   
320  33 parent = localSerializer.serialize(parentRef);
321    }
322    }
323   
324  58 return parent;
325    }
326   
327    /**
328    * @param request the current request for which this action is executed
329    * @param newDocument the document to be created
330    * @param isSpace {@code true} if the request is to create a space, {@code false} if a page should be created
331    * @return the title of the page to be created. If no request parameter is set, the page name is returned for a new
332    * page and the space name is returned for a new space
333    */
 
334  58 toggle private String getTitle(XWikiRequest request, XWikiDocument newDocument, boolean isSpace)
335    {
336  58 String title = request.getParameter("title");
337  58 if (StringUtils.isEmpty(title)) {
338  40 if (isSpace) {
339  22 title = newDocument.getDocumentReference().getLastSpaceReference().getName();
340    } else {
341  18 title = newDocument.getDocumentReference().getName();
342    // Avoid WebHome titles for pages that are really space homepages.
343  18 if (WEBHOME.equals(title)) {
344  0 title = newDocument.getDocumentReference().getLastSpaceReference().getName();
345    }
346    }
347    }
348   
349  58 return title;
350    }
351   
352    /**
353    * @param templateProvider the template provider for this creation
354    * @return {@code true} if the created document should be saved on create, before editing, {@code false} otherwise
355    */
 
356  58 toggle boolean getSaveBeforeEdit(BaseObject templateProvider)
357    {
358  58 boolean toSave = false;
359   
360  58 if (templateProvider != null) {
361    // get the action to execute and compare it to saveandedit value
362  18 String action = templateProvider.getStringValue("action");
363  18 if ("saveandedit".equals(action)) {
364  1 toSave = true;
365    }
366    }
367   
368  58 return toSave;
369    }
370   
371    /**
372    * @param template the template to create document from
373    * @param resolver the resolver to use to resolve the template document reference
374    * @param context the context of the current request
375    * @return the default edit mode for a document created from the passed template
376    * @throws XWikiException in case something goes wrong accessing template document
377    */
 
378  57 toggle private String getEditMode(String template, DocumentReferenceResolver<String> resolver, XWikiContext context)
379    throws XWikiException
380    {
381    // Determine the edit action (edit/inline) for the newly created document, if a template is passed it is
382    // used to determine the action. Default is 'edit'.
383  57 String editAction = "edit";
384  57 XWiki xwiki = context.getWiki();
385  57 if (!StringUtils.isEmpty(template)) {
386  22 DocumentReference templateReference = resolver.resolve(template);
387  22 if (xwiki.exists(templateReference, context)) {
388  21 editAction = xwiki.getDocument(templateReference, context).getDefaultEditMode(context);
389    }
390    }
391   
392  57 return editAction;
393    }
394    }