001    /**
002     * Copyright (c) 2000-2010 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 =
187                                    messageDisplay.getMessage().getMessageId();
188                    }
189                    else {
190                            commentParentId = messageIdMap.get(commentParentId);
191                    }
192    
193                    ServiceContext serviceContext = new ServiceContext();
194    
195                    serviceContext.setAddCommunityPermissions(true);
196                    serviceContext.setAddGuestPermissions(true);
197    
198                    MBMessage message = MBMessageLocalServiceUtil.addDiscussionMessage(
199                            defaultUser.getUserId(), commentAuthor, context.getGroupId(),
200                            BlogsEntry.class.getName(), entry.getEntryId(),
201                            thread.getThreadId(), commentParentId, null, commentContent,
202                            serviceContext);
203    
204                    messageIdMap.put(commentId, message.getMessageId());
205            }
206    
207            protected static void importEntry(
208                            PortletDataContext context, User defaultUser,
209                            Map<String, Long> userMap, DateFormat dateFormat, Element entryEl)
210                    throws PortalException, SystemException {
211    
212                    long userId = context.getUserId(null);
213    
214                    String creator = entryEl.elementText(
215                            SAXReaderUtil.createQName("creator", _NS_DC));
216    
217                    if (userMap.containsKey(creator)) {
218                            userId = userMap.get(creator);
219                    }
220    
221                    String title = entryEl.elementTextTrim("title");
222    
223                    if (Validator.isNull(title)) {
224                            title = entryEl.elementTextTrim(
225                                    SAXReaderUtil.createQName("post_name", _NS_WP));
226                    }
227    
228                    String content = entryEl.elementText(
229                            SAXReaderUtil.createQName("encoded", _NS_CONTENT));
230    
231                    content = content.replaceAll("\\n", "\n<br />");
232    
233                    // LPS-1425
234    
235                    if (Validator.isNull(content)) {
236                            content = "<br />";
237                    }
238    
239                    String dateText = entryEl.elementTextTrim(
240                            SAXReaderUtil.createQName("post_date_gmt", _NS_WP));
241    
242                    Date postDate = new Date();
243    
244                    try {
245                            postDate = dateFormat.parse(dateText);
246                    }
247                    catch (ParseException pe) {
248                            _log.warn("Parse " + dateText, pe);
249                    }
250    
251                    Calendar cal = Calendar.getInstance();
252    
253                    cal.setTime(postDate);
254    
255                    int displayDateMonth = cal.get(Calendar.MONTH);
256                    int displayDateDay = cal.get(Calendar.DAY_OF_MONTH);
257                    int displayDateYear = cal.get(Calendar.YEAR);
258                    int displayDateHour = cal.get(Calendar.HOUR_OF_DAY);
259                    int displayDateMinute = cal.get(Calendar.MINUTE);
260    
261                    String pingStatusText = entryEl.elementTextTrim(
262                            SAXReaderUtil.createQName("ping_status", _NS_WP));
263    
264                    boolean allowPingbacks = pingStatusText.equalsIgnoreCase("open");
265                    boolean allowTrackbacks = allowPingbacks;
266    
267                    String statusText = entryEl.elementTextTrim(
268                            SAXReaderUtil.createQName("status", _NS_WP));
269    
270                    int workflowAction = WorkflowConstants.ACTION_PUBLISH;
271    
272                    if (statusText.equalsIgnoreCase("draft")) {
273                            workflowAction = WorkflowConstants.ACTION_SAVE_DRAFT;
274                    }
275    
276                    String[] assetTagNames = null;
277    
278                    String categoryText = entryEl.elementTextTrim("category");
279    
280                    if (Validator.isNotNull(categoryText)) {
281                            assetTagNames = new String[] {categoryText};
282                    }
283    
284                    ServiceContext serviceContext = new ServiceContext();
285    
286                    serviceContext.setAddCommunityPermissions(true);
287                    serviceContext.setAddGuestPermissions(true);
288                    serviceContext.setAssetTagNames(assetTagNames);
289                    serviceContext.setScopeGroupId(context.getGroupId());
290                    serviceContext.setWorkflowAction(workflowAction);
291    
292                    BlogsEntry entry = null;
293    
294                    try {
295                            entry = BlogsEntryLocalServiceUtil.addEntry(
296                                    userId, title, content, displayDateMonth, displayDateDay,
297                                    displayDateYear, displayDateHour, displayDateMinute,
298                                    allowPingbacks, allowTrackbacks, 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    }