1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.watchlist.internal

File DefaultWatchListEventHTMLDiffExtractor.java

 

Coverage histogram

../../../../img/srcFileCovDistChart5.png
74% of files have more coverage

Code metrics

16
76
5
1
276
150
18
0.24
15.2
5
3.6

Classes

Class Line # Actions
DefaultWatchListEventHTMLDiffExtractor 54 76 0% 18 54
0.4432989744.3%
 

Contributing tests

No tests hitting this source file were found.

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 org.xwiki.watchlist.internal;
21   
22    import java.util.List;
23   
24    import javax.inject.Inject;
25    import javax.inject.Provider;
26    import javax.inject.Singleton;
27   
28    import org.apache.commons.lang3.StringUtils;
29    import org.apache.ecs.html.Div;
30    import org.apache.ecs.html.Span;
31    import org.slf4j.Logger;
32    import org.xwiki.component.annotation.Component;
33    import org.xwiki.watchlist.internal.api.WatchListEvent;
34    import org.xwiki.watchlist.internal.api.WatchListEventType;
35    import org.xwiki.watchlist.internal.api.WatchListException;
36   
37    import com.xpn.xwiki.XWikiContext;
38    import com.xpn.xwiki.XWikiException;
39    import com.xpn.xwiki.doc.AttachmentDiff;
40    import com.xpn.xwiki.doc.MetaDataDiff;
41    import com.xpn.xwiki.doc.XWikiDocument;
42    import com.xpn.xwiki.objects.ObjectDiff;
43    import com.xpn.xwiki.plugin.diff.DiffPluginApi;
44   
45    /**
46    * Default implementation for {@link WatchListEventHTMLDiffExtractor}.
47    * <p>
48    * TODO: Use the new diff module instead of the old diff plugin.
49    *
50    * @version $Id: ab1773882e0878dd3a16dfeb429990601fb92989 $
51    */
52    @Component
53    @Singleton
 
54    public class DefaultWatchListEventHTMLDiffExtractor implements WatchListEventHTMLDiffExtractor
55    {
56    /**
57    * Prefix used in inline style we put in HTML diffs.
58    */
59    private static final String HTML_STYLE_PLACEHOLDER_PREFIX = "WATCHLIST_STYLE_DIFF_";
60   
61    /**
62    * Suffix used to insert images later in HTML diffs.
63    */
64    private static final String HTML_IMG_PLACEHOLDER_SUFFIX = "_WATCHLIST_IMG_PLACEHOLDER";
65   
66    /**
67    * Prefix used to insert the metadata icon later in HTML diffs.
68    */
69    private static final String HTML_IMG_METADATA_PREFIX = "metadata";
70   
71    /**
72    * Prefix used to insert the attachment icon later in HTML diffs.
73    */
74    private static final String HTML_IMG_ATTACHMENT_PREFIX = "attach";
75   
76    /**
77    * Value to display in diffs for hidden properties (email, password, etc).
78    */
79    private static final String HIDDEN_PROPERTIES_OBFUSCATED_VALUE = "******************";
80   
81    /**
82    * Name of the password class.
83    */
84    private static final String PASSWORD_CLASS_NAME = "Password";
85   
86    /**
87    * Name of email property.
88    */
89    private static final String EMAIL_PROPERTY_NAME = "email";
90   
91    /**
92    * Default document version on creation.
93    */
94    private static final String INITIAL_DOCUMENT_VERSION = "1.1";
95   
96    @Inject
97    private Logger logger;
98   
99    @Inject
100    private Provider<XWikiContext> contextProvider;
101   
 
102  2 toggle @Override
103    public String getHTMLDiff(WatchListEvent event) throws WatchListException
104    {
105  2 XWikiContext context = contextProvider.get();
106   
107  2 StringBuffer result = new StringBuffer();
108   
109  2 try {
110  2 DiffPluginApi diff = (DiffPluginApi) context.getWiki().getPluginApi("diff", context);
111   
112  2 XWikiDocument d2 = context.getWiki().getDocument(event.getDocumentReference(), context);
113   
114  2 if (event.getType().equals(WatchListEventType.CREATE)) {
115  2 d2 = context.getWiki().getDocument(d2, INITIAL_DOCUMENT_VERSION, context);
116    }
117   
118  2 XWikiDocument d1 = context.getWiki().getDocument(d2, event.getPreviousVersion(), context);
119  2 List<AttachmentDiff> attachDiffs = d2.getAttachmentDiff(d1, d2, context);
120  2 List<List<ObjectDiff>> objectDiffs = d2.getObjectDiff(d1, d2, context);
121  2 List<List<ObjectDiff>> classDiffs = d2.getClassDiff(d1, d2, context);
122  2 List<MetaDataDiff> metaDiffs = d2.getMetaDataDiff(d1, d2, context);
123   
124  2 if (!d1.getContent().equals(d2.getContent())) {
125  2 Div contentDiv = createDiffDiv("contentDiff");
126  2 String contentDiff = diff.getDifferencesAsHTML(d1.getContent(), d2.getContent(), false);
127  2 contentDiv.addElement(contentDiff);
128  2 result.append(contentDiv);
129    }
130   
131  2 for (AttachmentDiff aDiff : attachDiffs) {
132  0 Div attachmentDiv = createDiffDiv("attachmentDiff");
133  0 attachmentDiv.addElement(HTML_IMG_ATTACHMENT_PREFIX + HTML_IMG_PLACEHOLDER_SUFFIX);
134  0 attachmentDiv.addElement(aDiff.toString());
135  0 result.append(attachmentDiv);
136    }
137   
138  2 result.append(getObjectsHTMLDiff(objectDiffs, false, event.getFullName(), diff));
139  2 result.append(getObjectsHTMLDiff(classDiffs, true, event.getFullName(), diff));
140   
141  2 for (MetaDataDiff mDiff : metaDiffs) {
142  4 Div metaDiv = createDiffDiv("metaDiff");
143  4 metaDiv.addElement(HTML_IMG_METADATA_PREFIX + HTML_IMG_PLACEHOLDER_SUFFIX);
144  4 metaDiv.addElement(mDiff.toString());
145  4 result.append(metaDiv);
146    }
147   
148  2 return result.toString();
149    } catch (Exception e) {
150  0 throw new WatchListException(String.format("Failed to compute HTML diff for event type [%s] on [%s]",
151    event.getType(), event.getPrefixedFullName()), e);
152    }
153    }
154   
155    /**
156    * @param classAttr The class of the div to create
157    * @return a HTML div element
158    */
 
159  6 toggle private static Div createDiffDiv(String classAttr)
160    {
161  6 Div div = new Div();
162  6 div.setClass(classAttr);
163  6 div.setStyle(HTML_STYLE_PLACEHOLDER_PREFIX + classAttr);
164   
165  6 return div;
166    }
167   
168    /**
169    * @param classAttr The class of the span to create
170    * @return an opening span markup
171    */
 
172  0 toggle private static Span createDiffSpan(String classAttr)
173    {
174  0 Span span = new Span();
175  0 span.setClass(classAttr);
176  0 span.setStyle(HTML_STYLE_PLACEHOLDER_PREFIX + classAttr);
177   
178  0 return span;
179    }
180   
181    /**
182    * Compute the HTML diff for a given property.
183    *
184    * @param objectDiff object diff object
185    * @param diff the diff plugin API
186    * @return the HTML diff
187    * @throws XWikiException if the diff plugin fails to compute the HTML diff
188    */
 
189  0 toggle private static String getPropertyHTMLDiff(ObjectDiff objectDiff, DiffPluginApi diff) throws XWikiException
190    {
191  0 String propDiff =
192    diff.getDifferencesAsHTML(objectDiff.getPrevValue().toString(), objectDiff.getNewValue().toString(), false);
193   
194    // We hide PasswordClass properties and properties named "email" from notifications for security reasons.
195  0 if ((objectDiff.getPropType().equals(PASSWORD_CLASS_NAME) || objectDiff.getPropName().equals(
196    EMAIL_PROPERTY_NAME))
197    && !StringUtils.isBlank(propDiff)) {
198  0 propDiff = HIDDEN_PROPERTIES_OBFUSCATED_VALUE;
199    }
200   
201  0 return propDiff;
202    }
203   
204    /**
205    * @param objectDiffs the list of object diff
206    * @param isXWikiClass true if the diff to compute is for an XWiki class, false if it's a plain XWiki object
207    * @param documentFullName full name of the document the diff is computed for
208    * @param diff the diff plugin API
209    * @return the HTML string displaying the specified list of diffs
210    */
 
211  4 toggle private String getObjectsHTMLDiff(List<List<ObjectDiff>> objectDiffs, boolean isXWikiClass,
212    String documentFullName, DiffPluginApi diff)
213    {
214  4 StringBuffer result = new StringBuffer();
215  4 String propSeparator = ": ";
216  4 String prefix = (isXWikiClass) ? "class" : "object";
217   
218  4 try {
219  4 for (List<ObjectDiff> oList : objectDiffs) {
220  0 if (oList.isEmpty()) {
221  0 continue;
222    }
223   
224    // The main container
225  0 Div mainDiv = createDiffDiv(prefix + "Diff");
226   
227    // Class name
228  0 Span objectName = createDiffSpan(prefix + "ClassName");
229  0 if (isXWikiClass) {
230  0 objectName.addElement(documentFullName);
231    } else {
232  0 objectName.addElement(oList.get(0).getClassName());
233    }
234  0 mainDiv.addElement(prefix + HTML_IMG_PLACEHOLDER_SUFFIX);
235  0 mainDiv.addElement(objectName);
236   
237    // Diffs for each property
238  0 for (ObjectDiff oDiff : oList) {
239  0 String propDiff = getPropertyHTMLDiff(oDiff, diff);
240  0 if (StringUtils.isBlank(oDiff.getPropName()) || StringUtils.isBlank(propDiff)) {
241    // Skip invalid properties or the ones that have no changed.
242  0 continue;
243    }
244   
245  0 Div propDiv = createDiffDiv("propDiffContainer");
246   
247    // Property name
248  0 Span propNameSpan = createDiffSpan("propName");
249  0 propNameSpan.addElement(oDiff.getPropName() + propSeparator);
250  0 String shortPropType = StringUtils.removeEnd(oDiff.getPropType(), "Class").toLowerCase();
251  0 if (StringUtils.isBlank(shortPropType)) {
252    // When the diff shows a property that has been deleted, its type is not available.
253  0 shortPropType = HTML_IMG_METADATA_PREFIX;
254    }
255  0 propDiv.addElement(shortPropType + HTML_IMG_PLACEHOLDER_SUFFIX);
256  0 propDiv.addElement(propNameSpan);
257   
258    // Property diff
259  0 Div propDiffDiv = createDiffDiv("propDiff");
260  0 propDiffDiv.addElement(propDiff);
261  0 propDiv.addElement(propDiffDiv);
262   
263    // Add it to the main div
264  0 mainDiv.addElement(propDiv);
265    }
266   
267  0 result.append(mainDiv);
268    }
269    } catch (XWikiException e) {
270    // Catch the exception to be sure we won't send emails containing stacktraces to users.
271  0 logger.error("Failed to compute HTML objects or class diff", e);
272    }
273   
274  4 return result.toString();
275    }
276    }