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