001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.blogs.lar;
016    
017    import com.liferay.portal.kernel.lar.BasePortletDataHandler;
018    import com.liferay.portal.kernel.lar.PortletDataContext;
019    import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
020    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
021    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
022    import com.liferay.portal.kernel.util.StreamUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.kernel.workflow.WorkflowConstants;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.SAXReaderUtil;
031    import com.liferay.portal.model.Image;
032    import com.liferay.portal.service.ServiceContext;
033    import com.liferay.portal.service.persistence.ImageUtil;
034    import com.liferay.portal.util.PortletKeys;
035    import com.liferay.portal.util.PropsValues;
036    import com.liferay.portlet.blogs.model.BlogsEntry;
037    import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
038    import com.liferay.portlet.blogs.service.BlogsStatsUserLocalServiceUtil;
039    import com.liferay.portlet.blogs.service.persistence.BlogsEntryUtil;
040    import com.liferay.portlet.dynamicdatamapping.lar.DDMPortletDataHandler;
041    import com.liferay.portlet.journal.lar.JournalPortletDataHandler;
042    
043    import java.io.InputStream;
044    
045    import java.util.Calendar;
046    import java.util.List;
047    
048    import javax.portlet.PortletPreferences;
049    
050    /**
051     * @author Bruno Farache
052     * @author Raymond Augé
053     * @author Juan Fernández
054     */
055    public class BlogsPortletDataHandler extends BasePortletDataHandler {
056    
057            public static final String NAMESPACE = "blogs";
058    
059            public BlogsPortletDataHandler() {
060                    setAlwaysExportable(true);
061                    setExportControls(
062                            new PortletDataHandlerBoolean(NAMESPACE, "entries", true, true));
063                    setExportMetadataControls(
064                            new PortletDataHandlerBoolean(
065                                    NAMESPACE, "blog-entries", true,
066                                    new PortletDataHandlerControl[] {
067                                            new PortletDataHandlerBoolean(NAMESPACE, "categories"),
068                                            new PortletDataHandlerBoolean(NAMESPACE, "comments"),
069                                            new PortletDataHandlerBoolean(NAMESPACE, "ratings"),
070                                            new PortletDataHandlerBoolean(NAMESPACE, "tags")
071                                    }));
072                    setImportMetadataControls(
073                            getExportMetadataControls()[0],
074                            new PortletDataHandlerBoolean(NAMESPACE, "wordpress"));
075                    setPublishToLiveByDefault(PropsValues.BLOGS_PUBLISH_TO_LIVE_BY_DEFAULT);
076            }
077    
078            @Override
079            protected PortletPreferences doDeleteData(
080                            PortletDataContext portletDataContext, String portletId,
081                            PortletPreferences portletPreferences)
082                    throws Exception {
083    
084                    if (portletDataContext.addPrimaryKey(
085                                    BlogsPortletDataHandler.class, "deleteData")) {
086    
087                            return portletPreferences;
088                    }
089    
090                    BlogsEntryLocalServiceUtil.deleteEntries(
091                            portletDataContext.getScopeGroupId());
092    
093                    BlogsStatsUserLocalServiceUtil.deleteStatsUserByGroupId(
094                            portletDataContext.getScopeGroupId());
095    
096                    return portletPreferences;
097            }
098    
099            @Override
100            protected String doExportData(
101                            PortletDataContext portletDataContext, String portletId,
102                            PortletPreferences portletPreferences)
103                    throws Exception {
104    
105                    portletDataContext.addPermissions(
106                            "com.liferay.portlet.blogs", portletDataContext.getScopeGroupId());
107    
108                    Element rootElement = addExportRootElement();
109    
110                    rootElement.addAttribute(
111                            "group-id", String.valueOf(portletDataContext.getScopeGroupId()));
112    
113                    Element entriesElement = rootElement.addElement("entries");
114    
115                    Element dlFileEntryTypesElement = entriesElement.addElement(
116                            "dl-file-entry-types");
117                    Element dlFoldersElement = entriesElement.addElement("dl-folders");
118                    Element dlFileEntriesElement = entriesElement.addElement(
119                            "dl-file-entries");
120                    Element dlFileRanksElement = entriesElement.addElement("dl-file-ranks");
121                    Element dlRepositoriesElement = entriesElement.addElement(
122                            "dl-repositories");
123                    Element dlRepositoryEntriesElement = entriesElement.addElement(
124                            "dl-repository-entries");
125    
126                    List<BlogsEntry> entries = BlogsEntryUtil.findByGroupId(
127                            portletDataContext.getScopeGroupId());
128    
129                    for (BlogsEntry entry : entries) {
130                            exportEntry(
131                                    portletDataContext, entriesElement, dlFileEntryTypesElement,
132                                    dlFoldersElement, dlFileEntriesElement, dlFileRanksElement,
133                                    dlRepositoriesElement, dlRepositoryEntriesElement, entry);
134                    }
135    
136                    return rootElement.formattedString();
137            }
138    
139            @Override
140            protected PortletPreferences doImportData(
141                            PortletDataContext portletDataContext, String portletId,
142                            PortletPreferences portletPreferences, String data)
143                    throws Exception {
144    
145                    portletDataContext.importPermissions(
146                            "com.liferay.portlet.blogs", portletDataContext.getSourceGroupId(),
147                            portletDataContext.getScopeGroupId());
148    
149                    Document document = SAXReaderUtil.read(data);
150    
151                    Element rootElement = document.getRootElement();
152    
153                    Element entriesElement = rootElement.element("entries");
154    
155                    if (entriesElement != null) {
156                            JournalPortletDataHandler.importReferencedData(
157                                    portletDataContext, entriesElement);
158                    }
159                    else {
160                            entriesElement = rootElement;
161                    }
162    
163                    for (Element entryElement : entriesElement.elements("entry")) {
164                            String path = entryElement.attributeValue("path");
165    
166                            if (!portletDataContext.isPathNotProcessed(path)) {
167                                    continue;
168                            }
169    
170                            BlogsEntry entry =
171                                    (BlogsEntry)portletDataContext.getZipEntryAsObject(path);
172    
173                            importEntry(portletDataContext, entryElement, entry);
174                    }
175    
176                    if (portletDataContext.getBooleanParameter(NAMESPACE, "wordpress")) {
177                            WordPressImporter.importData(portletDataContext);
178                    }
179    
180                    return null;
181            }
182    
183            protected void exportEntry(
184                            PortletDataContext portletDataContext, Element entriesElement,
185                            Element dlFileEntryTypesElement, Element dlFoldersElement,
186                            Element dlFileEntriesElement, Element dlFileRanksElement,
187                            Element dlRepositoriesElement, Element dlRepositoryEntriesElement,
188                            BlogsEntry entry)
189                    throws Exception {
190    
191                    if (!portletDataContext.isWithinDateRange(entry.getModifiedDate())) {
192                            return;
193                    }
194    
195                    if (!entry.isApproved() && !entry.isInTrash()) {
196                            return;
197                    }
198    
199                    String path = getEntryPath(portletDataContext, entry);
200    
201                    if (!portletDataContext.isPathNotProcessed(path)) {
202                            return;
203                    }
204    
205                    // Clone this entry to make sure changes to its content are never
206                    // persisted
207    
208                    entry = (BlogsEntry)entry.clone();
209    
210                    Element entryElement = (Element)entriesElement.selectSingleNode(
211                            "//page[@path='".concat(path).concat("']"));
212    
213                    if (entryElement == null) {
214                            entryElement = entriesElement.addElement("entry");
215                    }
216    
217                    String content = DDMPortletDataHandler.exportReferencedContent(
218                            portletDataContext, dlFileEntryTypesElement, dlFoldersElement,
219                            dlFileEntriesElement, dlFileRanksElement, dlRepositoriesElement,
220                            dlRepositoryEntriesElement, entryElement, entry.getContent());
221    
222                    entry.setContent(content);
223    
224                    String imagePath = getEntryImagePath(portletDataContext, entry);
225    
226                    entryElement.addAttribute("image-path", imagePath);
227    
228                    if (entry.isSmallImage()) {
229                            Image smallImage = ImageUtil.fetchByPrimaryKey(
230                                    entry.getSmallImageId());
231    
232                            if (Validator.isNotNull(entry.getSmallImageURL())) {
233                                    String smallImageURL =
234                                            DDMPortletDataHandler.exportReferencedContent(
235                                                    portletDataContext, dlFileEntryTypesElement,
236                                                    dlFoldersElement, dlFileEntriesElement,
237                                                    dlFileRanksElement, dlRepositoriesElement,
238                                                    dlRepositoryEntriesElement, entryElement,
239                                                    entry.getSmallImageURL().concat(StringPool.SPACE));
240    
241                                    entry.setSmallImageURL(smallImageURL);
242                            }
243                            else if (smallImage != null) {
244                                    String smallImagePath = getEntrySmallImagePath(
245                                            portletDataContext, entry);
246    
247                                    entryElement.addAttribute("small-image-path", smallImagePath);
248    
249                                    entry.setSmallImageType(smallImage.getType());
250    
251                                    portletDataContext.addZipEntry(
252                                            smallImagePath, smallImage.getTextObj());
253                            }
254                    }
255    
256                    portletDataContext.addClassedModel(
257                            entryElement, path, entry, NAMESPACE);
258            }
259    
260            protected String getEntryImagePath(
261                            PortletDataContext portletDataContext, BlogsEntry entry)
262                    throws Exception {
263    
264                    StringBundler sb = new StringBundler(4);
265    
266                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
267                    sb.append("/entry/");
268                    sb.append(entry.getUuid());
269                    sb.append(StringPool.SLASH);
270    
271                    return sb.toString();
272            }
273    
274            protected String getEntryPath(
275                    PortletDataContext portletDataContext, BlogsEntry entry) {
276    
277                    StringBundler sb = new StringBundler(4);
278    
279                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
280                    sb.append("/entries/");
281                    sb.append(entry.getEntryId());
282                    sb.append(".xml");
283    
284                    return sb.toString();
285            }
286    
287            protected String getEntrySmallImagePath(
288                            PortletDataContext portletDataContext, BlogsEntry entry)
289                    throws Exception {
290    
291                    StringBundler sb = new StringBundler(6);
292    
293                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
294                    sb.append("/entries/");
295                    sb.append(entry.getUuid());
296                    sb.append("/thumbnail");
297                    sb.append(StringPool.PERIOD);
298                    sb.append(entry.getSmallImageType());
299    
300                    return sb.toString();
301            }
302    
303            protected void importEntry(
304                            PortletDataContext portletDataContext, Element entryElement,
305                            BlogsEntry entry)
306                    throws Exception {
307    
308                    long userId = portletDataContext.getUserId(entry.getUserUuid());
309    
310                    String content = JournalPortletDataHandler.importReferencedContent(
311                            portletDataContext, entryElement, entry.getContent());
312    
313                    entry.setContent(content);
314    
315                    Calendar displayDateCal = CalendarFactoryUtil.getCalendar();
316    
317                    displayDateCal.setTime(entry.getDisplayDate());
318    
319                    int displayDateMonth = displayDateCal.get(Calendar.MONTH);
320                    int displayDateDay = displayDateCal.get(Calendar.DATE);
321                    int displayDateYear = displayDateCal.get(Calendar.YEAR);
322                    int displayDateHour = displayDateCal.get(Calendar.HOUR);
323                    int displayDateMinute = displayDateCal.get(Calendar.MINUTE);
324    
325                    if (displayDateCal.get(Calendar.AM_PM) == Calendar.PM) {
326                            displayDateHour += 12;
327                    }
328    
329                    boolean allowPingbacks = entry.isAllowPingbacks();
330                    boolean allowTrackbacks = entry.isAllowTrackbacks();
331                    String[] trackbacks = StringUtil.split(entry.getTrackbacks());
332                    int status = entry.getStatus();
333    
334                    String smallImageFileName = null;
335                    InputStream smallImageInputStream = null;
336    
337                    try {
338                            if (entry.isSmallImage()) {
339                                    String smallImagePath = entryElement.attributeValue(
340                                            "small-image-path");
341    
342                                    if (Validator.isNotNull(entry.getSmallImageURL())) {
343                                            String smallImageURL =
344                                                    JournalPortletDataHandler.importReferencedContent(
345                                                            portletDataContext, entryElement,
346                                                            entry.getSmallImageURL());
347    
348                                            entry.setSmallImageURL(smallImageURL);
349                                    }
350                                    else if (Validator.isNotNull(smallImagePath)) {
351                                            smallImageFileName = String.valueOf(
352                                                    entry.getSmallImageId()).concat(
353                                                            StringPool.PERIOD).concat(
354                                                                    entry.getSmallImageType());
355                                            smallImageInputStream =
356                                                    portletDataContext.getZipEntryAsInputStream(
357                                                            smallImagePath);
358                                    }
359                            }
360    
361                            ServiceContext serviceContext =
362                                    portletDataContext.createServiceContext(
363                                            entryElement, entry, NAMESPACE);
364    
365                            if ((status != WorkflowConstants.STATUS_APPROVED) &&
366                                    (status != WorkflowConstants.STATUS_IN_TRASH)) {
367    
368                                    serviceContext.setWorkflowAction(
369                                            WorkflowConstants.ACTION_SAVE_DRAFT);
370                            }
371    
372                            BlogsEntry importedEntry = null;
373    
374                            if (portletDataContext.isDataStrategyMirror()) {
375                                    serviceContext.setAttribute("urlTitle", entry.getUrlTitle());
376    
377                                    BlogsEntry existingEntry = BlogsEntryUtil.fetchByUUID_G(
378                                            entry.getUuid(), portletDataContext.getScopeGroupId());
379    
380                                    if (existingEntry == null) {
381                                            serviceContext.setUuid(entry.getUuid());
382    
383                                            importedEntry = BlogsEntryLocalServiceUtil.addEntry(
384                                                    userId, entry.getTitle(), entry.getDescription(),
385                                                    entry.getContent(), displayDateMonth, displayDateDay,
386                                                    displayDateYear, displayDateHour, displayDateMinute,
387                                                    allowPingbacks, allowTrackbacks, trackbacks,
388                                                    entry.isSmallImage(), entry.getSmallImageURL(),
389                                                    smallImageFileName, smallImageInputStream,
390                                                    serviceContext);
391    
392                                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
393                                                    importedEntry =
394                                                            BlogsEntryLocalServiceUtil.moveEntryToTrash(
395                                                                    userId, importedEntry);
396                                            }
397                                    }
398                                    else {
399                                            importedEntry = BlogsEntryLocalServiceUtil.updateEntry(
400                                                    userId, existingEntry.getEntryId(), entry.getTitle(),
401                                                    entry.getDescription(), entry.getContent(),
402                                                    displayDateMonth, displayDateDay, displayDateYear,
403                                                    displayDateHour, displayDateMinute, allowPingbacks,
404                                                    allowTrackbacks, trackbacks, entry.getSmallImage(),
405                                                    entry.getSmallImageURL(), smallImageFileName,
406                                                    smallImageInputStream, serviceContext);
407                                    }
408                            }
409                            else {
410                                    importedEntry = BlogsEntryLocalServiceUtil.addEntry(
411                                            userId, entry.getTitle(), entry.getDescription(),
412                                            entry.getContent(), displayDateMonth, displayDateDay,
413                                            displayDateYear, displayDateHour, displayDateMinute,
414                                            allowPingbacks, allowTrackbacks, trackbacks,
415                                            entry.getSmallImage(), entry.getSmallImageURL(),
416                                            smallImageFileName, smallImageInputStream, serviceContext);
417                            }
418    
419                            portletDataContext.importClassedModel(
420                                    entry, importedEntry, NAMESPACE);
421                    }
422                    finally {
423                            StreamUtil.cleanUp(smallImageInputStream);
424                    }
425    
426            }
427    
428    }