001    /**
002     * Copyright (c) 2000-2013 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.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
020    import com.liferay.portal.kernel.lar.PortletDataContext;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.TimeZoneUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.kernel.xml.Document;
030    import com.liferay.portal.kernel.xml.DocumentException;
031    import com.liferay.portal.kernel.xml.Element;
032    import com.liferay.portal.kernel.xml.Namespace;
033    import com.liferay.portal.kernel.xml.Node;
034    import com.liferay.portal.kernel.xml.SAXReaderUtil;
035    import com.liferay.portal.model.User;
036    import com.liferay.portal.service.ServiceContext;
037    import com.liferay.portal.service.UserLocalServiceUtil;
038    import com.liferay.portal.service.persistence.UserUtil;
039    import com.liferay.portal.util.PortletKeys;
040    import com.liferay.portlet.blogs.model.BlogsEntry;
041    import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
042    import com.liferay.portlet.messageboards.model.MBMessage;
043    import com.liferay.portlet.messageboards.model.MBMessageDisplay;
044    import com.liferay.portlet.messageboards.model.MBThread;
045    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
046    
047    import java.text.DateFormat;
048    import java.text.ParseException;
049    
050    import java.util.Calendar;
051    import java.util.Date;
052    import java.util.HashMap;
053    import java.util.List;
054    import java.util.Map;
055    
056    /**
057     * @author Raymond Augé
058     */
059    public class WordPressImporter {
060    
061            public static void importData(PortletDataContext context)
062                    throws PortalException, SystemException {
063    
064                    Map<String, Long> userMap = getWordPressUserMap(context);
065    
066                    String path = getWordPressPath(context, _EXPORT_FILE);
067    
068                    String fileData = context.getZipEntryAsString(path);
069    
070                    if (Validator.isNull(fileData)) {
071                            return;
072                    }
073    
074                    Document wordPressDoc = null;
075    
076                    try {
077                            wordPressDoc = SAXReaderUtil.read(fileData);
078                    }
079                    catch (DocumentException de) {
080                            _log.error("Reading " + path, de);
081    
082                            return;
083                    }
084    
085                    User defaultUser = UserLocalServiceUtil.getDefaultUser(
086                            context.getCompanyId());
087    
088                    Element root = wordPressDoc.getRootElement();
089    
090                    List<Element> entryEls = root.element("channel").elements("item");
091    
092                    DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
093                            _DATE_FORMAT);
094    
095                    dateFormat.setTimeZone(TimeZoneUtil.getTimeZone(StringPool.UTC));
096    
097                    for (Element entryEl : entryEls) {
098                            importEntry(context, defaultUser, userMap, dateFormat, entryEl);
099                    }
100            }
101    
102            protected static String getWordPressPath(
103                    PortletDataContext context, String fileName) {
104    
105                    String path = ExportImportPathUtil.getSourcePortletPath(
106                            context, PortletKeys.BLOGS);
107    
108                    return path.concat(StringPool.SLASH).concat(fileName);
109            }
110    
111            protected static Map<String, Long> getWordPressUserMap(
112                    PortletDataContext context) {
113    
114                    Map<String, Long> userMap = new HashMap<String, Long>();
115    
116                    String path = getWordPressPath(context, _USER_MAP_FILE);
117    
118                    String fileData = context.getZipEntryAsString(path);
119    
120                    if (Validator.isNull(fileData)) {
121                            return userMap;
122                    }
123    
124                    Document doc = null;
125    
126                    try {
127                            doc = SAXReaderUtil.read(fileData);
128                    }
129                    catch (DocumentException de) {
130                            _log.error(de.getMessage(), de);
131    
132                            return userMap;
133                    }
134    
135                    Element root = doc.getRootElement();
136    
137                    List<Element> userEls = root.elements("wordpress-user");
138    
139                    for (Element userEl : userEls) {
140                            try {
141                                    User user = UserUtil.findByC_EA(
142                                            context.getCompanyId(),
143                                            userEl.attributeValue("email-address"));
144    
145                                    userMap.put(userEl.getTextTrim(), user.getUserId());
146                            }
147                            catch (Exception e) {
148                                    if (_log.isDebugEnabled()) {
149                                            _log.debug(
150                                                    "User for {" + context.getCompanyId() + ", " +
151                                                            userEl.attributeValue("email-address") + "}", e);
152                                    }
153                            }
154                    }
155    
156                    return userMap;
157            }
158    
159            protected static void importComment(
160                            PortletDataContext context, User defaultUser,
161                            MBMessageDisplay messageDisplay, Map<Long, Long> messageIdMap,
162                            BlogsEntry entry, Element commentEl)
163                    throws PortalException, SystemException {
164    
165                    MBThread thread = messageDisplay.getThread();
166    
167                    long commentId = GetterUtil.getLong(
168                            commentEl.elementTextTrim(
169                                    SAXReaderUtil.createQName("comment_id", _NS_WP)));
170    
171                    String commentContent = commentEl.elementTextTrim(
172                            SAXReaderUtil.createQName("comment_content", _NS_WP));
173    
174                    if (Validator.isNull(commentContent)) {
175                            return;
176                    }
177    
178                    String commentAuthor = commentEl.elementTextTrim(
179                            SAXReaderUtil.createQName("comment_author", _NS_WP));
180    
181                    commentAuthor = commentAuthor.substring(
182                            0, Math.min(75, commentAuthor.length()));
183    
184                    long commentParentId = GetterUtil.getLong(
185                            commentEl.elementTextTrim(
186                                    SAXReaderUtil.createQName("comment_parent", _NS_WP)));
187    
188                    if (commentParentId == 0) {
189                            commentParentId = messageDisplay.getMessage().getMessageId();
190                    }
191                    else {
192                            commentParentId = messageIdMap.get(commentParentId);
193                    }
194    
195                    ServiceContext serviceContext = new ServiceContext();
196    
197                    serviceContext.setAddGroupPermissions(true);
198                    serviceContext.setAddGuestPermissions(true);
199    
200                    MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
201                            defaultUser.getUserId(), commentAuthor, context.getGroupId(),
202                            BlogsEntry.class.getName(), entry.getEntryId(),
203                            thread.getThreadId(), commentParentId, null, commentContent,
204                            serviceContext);
205    
206                    messageIdMap.put(commentId, message.getMessageId());
207            }
208    
209            protected static void importEntry(
210                            PortletDataContext context, User defaultUser,
211                            Map<String, Long> userMap, DateFormat dateFormat, Element entryEl)
212                    throws PortalException, SystemException {
213    
214                    String creator = entryEl.elementText(
215                            SAXReaderUtil.createQName("creator", _NS_DC));
216    
217                    Long userId = userMap.get(creator);
218    
219                    if (userId == null) {
220                            userId = context.getUserId(null);
221                    }
222    
223                    String title = entryEl.elementTextTrim("title");
224    
225                    if (Validator.isNull(title)) {
226                            title = entryEl.elementTextTrim(
227                                    SAXReaderUtil.createQName("post_name", _NS_WP));
228                    }
229    
230                    String content = entryEl.elementText(
231                            SAXReaderUtil.createQName("encoded", _NS_CONTENT));
232    
233                    content = content.replaceAll("\\n", "\n<br />");
234    
235                    // LPS-1425
236    
237                    if (Validator.isNull(content)) {
238                            content = "<br />";
239                    }
240    
241                    String dateText = entryEl.elementTextTrim(
242                            SAXReaderUtil.createQName("post_date_gmt", _NS_WP));
243    
244                    Date postDate = new Date();
245    
246                    try {
247                            postDate = dateFormat.parse(dateText);
248                    }
249                    catch (ParseException pe) {
250                            _log.warn("Parse " + dateText, pe);
251                    }
252    
253                    Calendar cal = Calendar.getInstance();
254    
255                    cal.setTime(postDate);
256    
257                    int displayDateMonth = cal.get(Calendar.MONTH);
258                    int displayDateDay = cal.get(Calendar.DAY_OF_MONTH);
259                    int displayDateYear = cal.get(Calendar.YEAR);
260                    int displayDateHour = cal.get(Calendar.HOUR_OF_DAY);
261                    int displayDateMinute = cal.get(Calendar.MINUTE);
262    
263                    String pingStatusText = entryEl.elementTextTrim(
264                            SAXReaderUtil.createQName("ping_status", _NS_WP));
265    
266                    boolean allowPingbacks = pingStatusText.equalsIgnoreCase("open");
267                    boolean allowTrackbacks = allowPingbacks;
268    
269                    String statusText = entryEl.elementTextTrim(
270                            SAXReaderUtil.createQName("status", _NS_WP));
271    
272                    int workflowAction = WorkflowConstants.ACTION_PUBLISH;
273    
274                    if (statusText.equalsIgnoreCase("draft")) {
275                            workflowAction = WorkflowConstants.ACTION_SAVE_DRAFT;
276                    }
277    
278                    String[] assetTagNames = null;
279    
280                    String categoryText = entryEl.elementTextTrim("category");
281    
282                    if (Validator.isNotNull(categoryText)) {
283                            assetTagNames = new String[] {categoryText};
284                    }
285    
286                    ServiceContext serviceContext = new ServiceContext();
287    
288                    serviceContext.setAddGroupPermissions(true);
289                    serviceContext.setAddGuestPermissions(true);
290                    serviceContext.setAssetTagNames(assetTagNames);
291                    serviceContext.setScopeGroupId(context.getGroupId());
292                    serviceContext.setWorkflowAction(workflowAction);
293    
294                    BlogsEntry entry = null;
295    
296                    try {
297                            entry = BlogsEntryLocalServiceUtil.addEntry(
298                                    userId, title, StringPool.BLANK, content, displayDateMonth,
299                                    displayDateDay, displayDateYear, displayDateHour,
300                                    displayDateMinute, allowPingbacks, allowTrackbacks, null, false,
301                                    null, null, null, serviceContext);
302                    }
303                    catch (Exception e) {
304                            _log.error("Add entry " + title, e);
305    
306                            return;
307                    }
308    
309                    MBMessageDisplay messageDisplay =
310                            MBMessageLocalServiceUtil.getDiscussionMessageDisplay(
311                                    userId, context.getGroupId(), BlogsEntry.class.getName(),
312                                    entry.getEntryId(), WorkflowConstants.STATUS_APPROVED);
313    
314                    Map<Long, Long> messageIdMap = new HashMap<Long, Long>();
315    
316                    List<Node> commentNodes = entryEl.selectNodes(
317                            "wp:comment", "wp:comment_parent/text()");
318    
319                    for (Node commentNode : commentNodes) {
320                            Element commentEl = (Element)commentNode;
321    
322                            importComment(
323                                    context, defaultUser, messageDisplay, messageIdMap, entry,
324                                    commentEl);
325                    }
326            }
327    
328            private static final String _DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
329    
330            private static final String _EXPORT_FILE = "wordpress.xml";
331    
332            private static final Namespace _NS_CONTENT = SAXReaderUtil.createNamespace(
333                    "content", "http://purl.org/rss/1.0/modules/content/");
334    
335            private static final Namespace _NS_DC = SAXReaderUtil.createNamespace(
336                    "dc", "http://purl.org/dc/elements/1.1/");
337    
338            private static final Namespace _NS_WP = SAXReaderUtil.createNamespace(
339                    "wp", "http://wordpress.org/export/1.0/");
340    
341            private static final String _USER_MAP_FILE = "wordpress-user-map.xml";
342    
343            private static Log _log = LogFactoryUtil.getLog(WordPressImporter.class);
344    
345    }