package com.idega.block.article.business; import java.sql.Timestamp; import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.directwebremoting.ScriptBuffer; import org.directwebremoting.WebContextFactory; import org.springframework.beans.factory.annotation.Autowired; import com.idega.block.article.ArticleCacher; import com.idega.block.article.bean.ArticleComment; import com.idega.block.article.bean.CommentAttachmentNotifyBean; import com.idega.block.article.bean.CommentEntry; import com.idega.block.article.bean.CommentsViewerProperties; import com.idega.block.article.component.CommentCreator; import com.idega.block.article.data.Comment; import com.idega.block.rss.business.RSSBusiness; import com.idega.builder.bean.AdvancedProperty; import com.idega.builder.business.BuilderLogicWrapper; import com.idega.business.IBOLookup; import com.idega.business.IBOLookupException; import com.idega.business.IBOSessionBean; import com.idega.business.file.FileDownloadNotifier; import com.idega.content.bean.ContentItemFeedBean; import com.idega.content.business.ContentConstants; import com.idega.content.business.ContentUtil; import com.idega.content.themes.helpers.business.ThemesHelper; import com.idega.core.builder.business.BuilderService; import com.idega.core.cache.IWCacheManager2; import com.idega.core.component.bean.RenderedComponent; import com.idega.core.contact.data.Email; import com.idega.dwr.reverse.ScriptCaller; import com.idega.idegaweb.IWMainApplication; import com.idega.idegaweb.IWMainApplicationSettings; import com.idega.idegaweb.IWResourceBundle; import com.idega.presentation.IWContext; import com.idega.slide.business.IWSlideService; import com.idega.user.business.NoEmailFoundException; import com.idega.user.business.UserBusiness; import com.idega.user.data.User; import com.idega.util.CoreConstants; import com.idega.util.CoreUtil; import com.idega.util.IWTimestamp; import com.idega.util.ListUtil; import com.idega.util.StringHandler; import com.idega.util.StringUtil; import com.idega.util.expression.ELUtil; import com.sun.syndication.feed.atom.Content; import com.sun.syndication.feed.atom.Entry; import com.sun.syndication.feed.atom.Feed; import com.sun.syndication.feed.atom.Link; import com.sun.syndication.feed.atom.Person; import com.sun.syndication.feed.module.DCModule; import com.sun.syndication.feed.module.DCModuleImpl; import com.sun.syndication.feed.synd.SyndFeed; public class CommentsEngineBean extends IBOSessionBean implements CommentsEngine { private static final long serialVersionUID = 7299800648381936213L; private static final Logger LOGGER = Logger.getLogger(CommentsEngineBean.class.getName()); private static final String COMMENTS_CACHE_NAME = "article_comments_feeds_cache"; @Autowired private ThemesHelper themesHelper; private FileDownloadNotifier downloadNotifier; @Autowired private BuilderLogicWrapper builderLogicWrapper; public boolean addComment(CommentsViewerProperties properties) { if (properties == null) { LOGGER.log(Level.INFO, "Comment properties are undefined!"); return false; } String uri = properties.getUri(); String subject = properties.getSubject(); String user = properties.getUser(); String instanceId = properties.getInstanceId(); String body = properties.getBody(); String commentAuthorEmail = properties.getEmail(); String errorMessage = "Unable to add comment: '" + subject + "' by: " + user; boolean notify = properties.isNotify(); if (uri == null) { closeLoadingMessage(); LOGGER.log(Level.SEVERE, errorMessage); return false; } if (ContentConstants.EMPTY.equals(uri)) { closeLoadingMessage(); LOGGER.log(Level.SEVERE, errorMessage); return false; } IWContext iwc = CoreUtil.getIWContext(); if (iwc == null) { LOGGER.log(Level.SEVERE, errorMessage); return false; } CommentsPersistenceManager commentsManager = getCommentsManager(properties.getSpringBeanIdentifier()); if (commentsManager == null) { uri = getFixedCommentsUri(uri, instanceId, properties.getCurrentPageUri()); properties.setUri(uri); } String language = getThemesHelper().getCurrentLanguage(iwc); Timestamp date = IWTimestamp.getTimestampRightNow(); Feed comments = getCommentsFeed(properties); if (comments == null) { String feedTitle = commentsManager == null ? properties.getTitle() : commentsManager.getFeedTitle(iwc, properties.getIdentifier()); String feedSubtitle = commentsManager == null ? properties.getSubtitle() : commentsManager.getFeedSubtitle(iwc, properties.getIdentifier()); comments = createFeed(uri, user, date, language, iwc, feedTitle, feedSubtitle, commentsManager); } if (comments == null) { LOGGER.log(Level.SEVERE, errorMessage); return false; } String entryId = addNewEntry(comments, subject, getUriForCommentLink(properties), date, body, user, language, commentAuthorEmail, notify); if (entryId == null) { LOGGER.log(Level.SEVERE, errorMessage); return false; } properties.setEntryId(entryId); // Caching XML if (commentsManager == null) { putFeedToCache(comments, uri); } // Clearing cache for articles (ALWAYS) if (commentsManager == null) { clearArticleCache(); } // Uploading changed XML for comments boolean finishedSuccessfully = commentsManager == null ? uploadFeed(uri, comments, iwc, true) : commentsManager.storeFeed(properties.getIdentifier(), comments); if (!finishedSuccessfully) { LOGGER.log(Level.SEVERE, errorMessage); return false; } // Adding entry to DB about new comment Object commentId = null; if (commentsManager != null) { commentId = commentsManager.addComment(properties); if (commentId == null) { LOGGER.warning("Unable to add entry to " + Comment.class + " by properties: " + properties); finishedSuccessfully = false; } } if (!finishedSuccessfully) { LOGGER.log(Level.SEVERE, errorMessage); return false; } // Updating clients with the newest comments ScriptCaller scriptCaller = new ScriptCaller(WebContextFactory.get(), new ScriptBuffer("getUpdatedCommentsFromServer(").appendData(properties.getId()) .appendScript(");"), true); executeScriptForAllPages(scriptCaller, false); // Sending notifications (if needed) about new comment if (commentsManager == null) { sendNotification(comments, commentAuthorEmail, iwc, properties); } else { sendNotification(commentsManager.getPersonsToNotifyAboutComment(properties, commentId, false), commentAuthorEmail, iwc, properties); } return finishedSuccessfully; } private String getUriForCommentLink(CommentsViewerProperties properties) { CommentsPersistenceManager commentsManager = getCommentsManager(properties.getSpringBeanIdentifier()); if (commentsManager == null) { commentsManager = getDefaultCommentsManager(); } return commentsManager.getUriForCommentLink(properties); } private void clearArticleCache() { Map<String, String> articlesCache = getArticlesCache(); if (articlesCache == null) { Logger.getLogger(CommentsEngineBean.class.getName()).log(Level.WARNING, "Aticle cache is null, can not clear it!"); } else { articlesCache.clear(); } } @SuppressWarnings("unchecked") private boolean sendNotification(Feed comments, String commentAuthorEmail, IWContext iwc, CommentsViewerProperties properties) { if (comments == null) { return false; } List<String> recipients = getDefaultCommentsManager().getEmails(comments.getEntries(), commentAuthorEmail); return sendNotification(recipients, commentAuthorEmail, iwc, properties); } private boolean sendNotification(List<String> recipients, String commentAuthorEmail, IWContext iwc, CommentsViewerProperties properties) { return sendNotification(recipients, commentAuthorEmail, iwc, properties, false); } private boolean sendNotification(List<String> recipients, String commentAuthorEmail, IWContext iwc, CommentsViewerProperties properties, boolean useAuthorEmailAsFrom) { if (ListUtil.isEmpty(recipients)) { return false; } recipients = new ArrayList<String>(recipients); if (!StringUtil.isEmpty(commentAuthorEmail) && recipients.contains(commentAuthorEmail)) { recipients.remove(commentAuthorEmail); } String newCommentMessage = getLocalizedString(iwc, "comments_viewer.new_comment_message", "New comment was entered. You can read all comments at"); String newComment = getLocalizedString(iwc, "comments_viewer.new_comment", "New comment"); if (!StringUtil.isEmpty(properties.getSubject())) { newComment = new StringBuilder(newComment).append(": ").append(properties.getSubject()).toString(); } StringBuilder body = new StringBuilder(newCommentMessage).append(CoreConstants.COLON).append(CoreConstants.SPACE); CommentsPersistenceManager manager = getCommentsManager(properties.getSpringBeanIdentifier()); if (manager == null) { manager = getDefaultCommentsManager(); } List<AdvancedProperty> recipientsWithLinks = manager.getLinksForRecipients(recipients, properties); return sendNotification(recipientsWithLinks, newComment, body.toString(), useAuthorEmailAsFrom ? commentAuthorEmail : null); } private boolean sendNotification(List<AdvancedProperty> recipients, String subject, String message, String from) { if (ListUtil.isEmpty(recipients) || StringUtil.isEmpty(subject) || StringUtil.isEmpty(message)) { return false; } try { IWMainApplicationSettings settings = IWMainApplication.getDefaultIWMainApplication().getSettings(); String host = settings.getProperty(CoreConstants.PROP_SYSTEM_SMTP_MAILSERVER); from = StringUtil.isEmpty(from) ? settings.getProperty(CoreConstants.PROP_SYSTEM_MAIL_FROM_ADDRESS) : from; if (StringUtil.isEmpty(from)) { LOGGER.warning("Address 'from' is not defined, unable to send message: " + subject + " to: " + recipients); return false; } Thread sender = new Thread(new CommentsNotificationSender(recipients, from, subject, message, host)); sender.start(); return true; } catch(Exception e) { LOGGER.log(Level.WARNING, "Error sending message: " + subject + " to: " + recipients, e); } return false; } private String addNewEntry(Feed feed, String subject, String uri, Timestamp date, String body, String user, String language, String email, boolean notify) { if (feed == null) { return null; } List<Entry> entries = initEntries(feed.getEntries()); Entry entry = new Entry(); // Title entry.setTitle(subject); // Summary Content summary = new Content(); summary.setType("html"); summary.setValue(getShortBody(body)); entry.setSummary(summary); // Body of comment Content comment = new Content(); comment.setType("html"); comment.setValue(body); List<Content> comments = new ArrayList<Content>(); comments.add(comment); entry.setContents(comments); // Dates entry.setUpdated(date); entry.setCreated(date); entry.setPublished(date); entry.setModified(date); // Author & Email Person author = new Person(); author.setName(user); if (notify) { author.setEmail(encodeMail(email)); } List<Person> authors = new ArrayList<Person>(); authors.add(author); entry.setAuthors(authors); // ID String id = getThemesHelper().getUniqueIdByNumberAndDate(ContentConstants.COMMENT_SCOPE); entry.setId(id); if (!StringUtil.isEmpty(uri)) { // URI Link link = new Link(); link.setHref(uri); List<Link> links = new ArrayList<Link>(); links.add(link); entry.setAlternateLinks(links); } // DC module DCModule dcModule = new DCModuleImpl(); dcModule.setCreator(user); dcModule.setDate(date); entry.setModules(Arrays.asList(dcModule)); entries.add(entry); feed.setEntries(entries); return id; } private List<Entry> initEntries(@SuppressWarnings("rawtypes") List oldEntries) { if (ListUtil.isEmpty(oldEntries)) { return new ArrayList<Entry>(); } List<Entry> entries = new ArrayList<Entry>(); Object o = null; for (int i = 0; i < oldEntries.size(); i++) { o = oldEntries.get(i); if (o instanceof Entry) { entries.add((Entry) o); } } return entries; } private Feed createFeed(String uri, String user, Timestamp date, String language, IWContext iwc, String feedTitle, String feedSubtitle, CommentsPersistenceManager commentsManager) { String serverName = getThemesHelper().getFullServerName(iwc); String articeComments = StringUtil.isEmpty(feedTitle) ? getLocalizedString(iwc, "comments_viewer.article_comments", "Comments of Article") : feedTitle; String allArticleComments = StringUtil.isEmpty(feedSubtitle) ? getLocalizedString(iwc, "comments_viewer.all_article_comments", "All comments") : feedSubtitle; Feed comments = new Feed(); comments.setFeedType(ContentItemFeedBean.FEED_TYPE_ATOM_1); // Title comments.setTitle(articeComments); // Subtitle Content subtitle = new Content(); subtitle.setValue(allArticleComments); comments.setSubtitle(subtitle); // Language comments.setLanguage(language); // Dates comments.setModified(date); comments.setUpdated(date); // ID comments.setId(serverName + CoreConstants.WEBDAV_SERVLET_URI + uri); // Author Person author = new Person(); author.setName(user); List<Person> authors = new ArrayList<Person>(); authors.add(author); comments.setAuthors(authors); // Link Link link = new Link(); link.setHref(serverName); List<Link> links = new ArrayList<Link>(); links.add(link); comments.setAlternateLinks(links); if (commentsManager == null) { putFeedToCache(comments, uri); } return comments; } private String getShortBody(String body) { if (body == null) { return ContentConstants.EMPTY; } if (body.length() >= 200) { StringBuffer shortBody = new StringBuffer(body.substring(0, 200)).append(ContentConstants.DOT); shortBody.append(ContentConstants.DOT).append(ContentConstants.DOT); return shortBody.toString(); } return body; } private RSSBusiness getRSSBusiness() { try { return IBOLookup.getServiceInstance(getIWApplicationContext(), RSSBusiness.class); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error getting: " + RSSBusiness.class, e); } return null; } /** * Updates particular comments block in client's browser(s) * @param uri - link to comments * @param id - comments group id * @return */ public boolean getCommentsForAllPages(CommentsViewerProperties properties) { return executeScriptForAllPages(getScriptForCommentsList(properties)); } private ScriptBuffer getScriptForCommentsList(CommentsViewerProperties properties) { if (properties == null) { LOGGER.log(Level.WARNING, "Can not create ScriptBuffer: properties unknown"); return null; } ScriptBuffer script = new ScriptBuffer(); script = new ScriptBuffer("getCommentsCallback(").appendData(getCommentsList(properties)).appendScript(");"); return script; } public List<List<ArticleComment>> getCommentsFromUris(List<CommentsViewerProperties> commentsProperties) { if (ListUtil.isEmpty(commentsProperties)) { return null; } List<List<ArticleComment>> allComments = new ArrayList<List<ArticleComment>>(); for (CommentsViewerProperties commentProperty: commentsProperties) { commentProperty.setAddNulls(false); commentProperty.setFetchFully(true); allComments.add(getCommentsEntries(commentProperty)); } return allComments; } public List<ArticleComment> getComments(CommentsViewerProperties properties) { return getCommentsList(properties); } private List<ArticleComment> getCommentsList(CommentsViewerProperties properties) { if (properties == null) { return null; } properties.setAddNulls(true); properties.setFetchFully(true); return getCommentsEntries(properties); } private List<ArticleComment> getCommentsEntries(CommentsViewerProperties properties) { List<ArticleComment> fake = new ArrayList<ArticleComment>(); if (properties.getUri() == null) { if (properties.isAddNulls()) { return null; } return fake; } List<? extends Entry> entriesToFormat = getEntriesToFormat(properties); if (entriesToFormat == null) { if (properties.isAddNulls()) { return null; } return fake; } List<ArticleComment> articleComments = getFormattedEntries(entriesToFormat, properties); return articleComments == null ? properties.isAddNulls() ? null : fake : articleComments; } @SuppressWarnings("unchecked") private List<? extends Entry> getEntriesToFormat(CommentsViewerProperties properties) { Feed comments = getCommentsFeed(properties); if (comments == null) { return null; } if (StringUtil.isEmpty(properties.getSpringBeanIdentifier())) { return comments.getEntries(); } else { CommentsPersistenceManager manager = getCommentsManager(properties.getSpringBeanIdentifier()); if (manager != null) { return manager.getEntriesToFormat(comments, properties); } } return null; } private List<ArticleComment> getFormattedEntries(List<? extends Entry> entriesToFormat, CommentsViewerProperties properties) { if (ListUtil.isEmpty(entriesToFormat)) { return null; } Locale locale = null; IWContext iwc = CoreUtil.getIWContext(); if (iwc != null) { locale = iwc.getCurrentLocale(); } if (locale == null) { locale = Locale.ENGLISH; } List<ArticleComment> items = new ArrayList<ArticleComment>(); ArticleComment comment = null; Content content = null; Person author = null; IWTimestamp posted = null; int number = 0; for (Entry entry: entriesToFormat) { comment = new ArticleComment(); // Number comment.setListNumber(number + 1); // ID comment.setId(entry.getId()); // Author try { if (entry.getAuthors() != null) { author = (Person) entry.getAuthors().get(0); comment.setUser(author.getName()); } else { comment.setUser(ContentConstants.EMPTY); } } catch(ClassCastException e) { comment.setUser(ContentConstants.EMPTY); } catch (IndexOutOfBoundsException e) { comment.setUser(ContentConstants.EMPTY); } // Subject comment.setSubject(StringUtil.isEmpty(entry.getTitle()) ? CoreConstants.EMPTY : entry.getTitle()); // Content try { if (entry.getContents() != null) { content = (Content) entry.getContents().get(0); comment.setComment(content.getValue()); } else { comment.setComment(ContentConstants.EMPTY); } } catch (ClassCastException e) { comment.setComment(ContentConstants.EMPTY); } catch (IndexOutOfBoundsException e) { comment.setComment(ContentConstants.EMPTY); } // Date of creation posted = new IWTimestamp(entry.getPublished()); comment.setPosted(posted.getLocaleDateAndTime(locale, DateFormat.FULL, DateFormat.MEDIUM)); if (entry instanceof CommentEntry) { CommentEntry commentEntry = (CommentEntry) entry; comment.setPublished(commentEntry.isPublished()); comment.setCanBePublished(commentEntry.isPublishable()); comment.setCanBeRead(commentEntry.isReadable()); comment.setCanBeReplied(commentEntry.isReplyable()); comment.setReaders(commentEntry.getReaders()); comment.setAttachments(commentEntry.getAttachments()); comment.setPrimaryKey(commentEntry.getPrimaryKey()); } items.add(comment); number++; } Collections.sort(items, new ArticleCommentComparator(locale, DateFormat.FULL, DateFormat.MEDIUM, properties.isNewestEntriesOnTop())); return items; } public CommentsPersistenceManager getCommentsManager(String springBeanIdentifier) { if (StringUtil.isEmpty(springBeanIdentifier)) { return null; } try { return ELUtil.getInstance().getBean(springBeanIdentifier); } catch(Exception e) { LOGGER.log(Level.SEVERE, "Error getting specified Spring bean: " + springBeanIdentifier, e); } return null; } private CommentsPersistenceManager getDefaultCommentsManager() { return getCommentsManager(DefaultCommentsPersistenceManager.BEAN_IDENTIFIER); } public int getCommentsCount(String uri, String springBeanIdentifier, String identifier, IWContext iwc, boolean addLoginbyUUIDOnRSSFeedLink) { CommentsViewerProperties properties = new CommentsViewerProperties(); properties.setUri(uri); properties.setSpringBeanIdentifier(springBeanIdentifier); properties.setIdentifier(identifier); properties.setAddLoginbyUUIDOnRSSFeedLink(addLoginbyUUIDOnRSSFeedLink); properties.setFetchFully(false); List<? extends Entry> entries = getEntriesToFormat(properties); return entries == null ? 0 : entries.size(); } private synchronized Feed getCommentsFeed(CommentsViewerProperties properties) { CommentsPersistenceManager commentsManager = getCommentsManager(properties.getSpringBeanIdentifier()); if (commentsManager != null) { return commentsManager.getCommentsFeed(properties.getIdentifier()); } if (StringUtil.isEmpty(properties.getUri())) { return null; } Feed cachedFeed = getFeedFromCache(properties.getUri()); if (cachedFeed != null) { return cachedFeed; } IWSlideService slide = getSlideService(); if (slide == null) { return null; } try { if (!slide.getExistence(properties.getUri())) { return null; } } catch (Exception e) { LOGGER.log(Level.WARNING, "Error while checking if file exists: " + properties.getUri(), e); return null; } RSSBusiness rss = getRSSBusiness(); if (rss == null) { return null; } User currentUser = getCurrentUser(); if (properties.isAddLoginbyUUIDOnRSSFeedLink() && currentUser == null) { LOGGER.log(Level.WARNING, "User must be looged to get comments feed!"); return null; } String pathToComments = new StringBuilder(getThemesHelper().getFullWebRoot()).append(properties.getUri()).toString(); SyndFeed comments = properties.isAddLoginbyUUIDOnRSSFeedLink() ? rss.getFeedAuthenticatedByUser(pathToComments, currentUser) : rss.getFeed(pathToComments); if (comments == null) { return null; } Object abstractFeed = comments.createWireFeed(); if (abstractFeed instanceof Feed) { Feed realFeed = (Feed) abstractFeed; putFeedToCache(realFeed, properties.getUri()); return realFeed; } return null; } private void putFeedToCache(Feed comments, String uri) { if (comments == null || uri == null) { return; } IWCacheManager2 cache = IWCacheManager2.getInstance(getIWMainApplication()); if (cache == null) { return; } Map<String, Feed> commentsMap = cache.getCache(COMMENTS_CACHE_NAME); if (commentsMap == null) { commentsMap = new HashMap<String, Feed>(); } commentsMap.put(uri, comments); return; } @Override protected IWMainApplication getIWMainApplication() { IWMainApplication iwma = null; try { iwma = super.getIWMainApplication(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Error getting IWMainApplication from IBOSessionBean, will use default application", e); } return iwma == null ? IWMainApplication.getDefaultIWMainApplication() : iwma; } private Feed getFeedFromCache(String uri) { if (uri == null) { return null; } IWCacheManager2 cache = IWCacheManager2.getInstance(getIWMainApplication()); if (cache == null) { return null; } Map<String, Feed> comments = null; try { comments = cache.getCache(COMMENTS_CACHE_NAME); } catch(Exception e) { e.printStackTrace(); } if (comments == null) { return null; } return comments.get(uri); } private String encodeMail(String email) { return CoreUtil.getEncodedValue(email); } public boolean setModuleProperty(String pageKey, String moduleId, String propName, String propValue, String cacheKey) { BuilderService builder = getBuilderService(); if (builder == null) { closeLoadingMessage(); return false; } IWContext iwc = CoreUtil.getIWContext(); if (iwc == null) { closeLoadingMessage(); return false; } String[] property = new String[1]; property[0] = propValue; builder.setProperty(pageKey, moduleId, propName, property, iwc.getIWMainApplication()); decacheComponent(cacheKey); ScriptBuffer script = new ScriptBuffer("hideOrShowComments('").appendData(moduleId).appendScript("');"); return executeScriptForAllPages(script); } private Map<String, String> getArticlesCache() { ArticleCacher cache = ArticleCacher.getInstance(getIWMainApplication()); if (cache == null) { return null; } try { return cache.getCacheMap(); } catch(Exception e) { e.printStackTrace(); } return null; } private void decacheComponent(String cacheKey) { if (cacheKey == null) { return; } Map<String, String> articles = getArticlesCache(); if (articles == null) { return; } try { articles.clear(); } catch (UnsupportedOperationException e) { e.printStackTrace(); clearAllCaches(); } } private void clearAllCaches() { IWCacheManager2 cacheManager = null; try { cacheManager = IWCacheManager2.getInstance(getIWMainApplication()); } catch(Exception e) { e.printStackTrace(); } if (cacheManager == null) { return; } cacheManager.reset(); } public boolean hideOrShowComments() { IWContext iwc = CoreUtil.getIWContext(); if (ContentUtil.hasContentEditorRoles(iwc)) { return false; // Do not need reload page } return true; // Need to reload page (disable component) } private boolean executeScriptForAllPages(ScriptBuffer script) { return executeScriptForAllPages(script, Boolean.FALSE); } private boolean executeScriptForAllPages(ScriptBuffer script, boolean useThreading) { return executeScriptForAllPages(new ScriptCaller(WebContextFactory.get(), script), useThreading); } private boolean executeScriptForAllPages(ScriptCaller scriptCaller, boolean useThreading) { if (useThreading) { Thread thread = new Thread(scriptCaller); thread.start(); } else { scriptCaller.run(); } return true; } /** * Closes loading layer in client's browser */ private void closeLoadingMessage() { ScriptBuffer script = new ScriptBuffer("closeAllLoadingMessages();"); executeScriptForAllPages(script, true); } public CommentsViewerProperties deleteComments(CommentsViewerProperties properties) { if (properties == null) { return null; } IWContext iwc = CoreUtil.getIWContext(); if (iwc == null) { return null; } CommentsPersistenceManager commentsManager = getCommentsManager(properties.getSpringBeanIdentifier()); if (commentsManager == null) { if (!ContentUtil.hasContentEditorRoles(iwc)) { LOGGER.log(Level.WARNING, "Current user doesn't have enough rights to delete comment(s)!"); return null; } } else if (!commentsManager.hasFullRightsForComments(properties.getIdentifier())) { LOGGER.log(Level.WARNING, "Current user doesn't have enough rights to delete comment(s)!"); return null; } String linkToComments = properties.getUri(); String commentId = properties.getId(); Feed comments = getCommentsFeed(properties); if (comments == null) { return null; } if (commentId == null) { // Delete all comments comments.setEntries(new ArrayList<Entry>()); } else { // Delete one comment comments.setEntries(getUpdatedEntries(initEntries(comments.getEntries()), commentId)); } if (commentsManager == null) { clearArticleCache(); putFeedToCache(comments, linkToComments); } String identifier = properties.getIdentifier(); boolean deleted = commentsManager == null ? uploadFeed(linkToComments, comments, iwc, true) : commentsManager.storeFeed(identifier, comments); properties.setActionSuccess(deleted); if (deleted) { invokeToReceiveComments(); } return properties; } private List<Entry> getUpdatedEntries(List<Entry> entries, String commentId) { if (entries == null) { return null; } if (commentId == null) { return entries; } Entry e = null; boolean found = false; for (int i = 0; (i < entries.size() && !found); i++) { e = entries.get(i); if (commentId.equals(e.getId())) { entries.remove(e); found = true; } } return entries; } public boolean initCommentsFeed(IWContext iwc, String uri, String user, Timestamp date, String language, String feedTitle, String feedSubtitle, CommentsPersistenceManager commentsManager) { Feed initialFeed = createFeed(uri, user, date, language, iwc, feedTitle, feedSubtitle, commentsManager); if (initialFeed == null) { return false; } return uploadFeed(uri, initialFeed, iwc, false); } private boolean uploadFeed(String uri, Feed comments, IWContext iwc, boolean useThread) { if (uri == null || comments == null || iwc == null) { return false; } IWSlideService service = getSlideService(); if (service == null) { return false; } String commentsContent = getDefaultCommentsManager().getFeedContent(comments); if (commentsContent == null) { return false; } String fileBase = uri; String fileName = uri; int index = uri.lastIndexOf(ContentConstants.SLASH); if (index != -1) { fileBase = uri.substring(0, index + 1); fileName = uri.substring(index + 1); } Thread uploader = new Thread(new CommentsFeedUploader(service, fileBase, fileName, commentsContent)); if (useThread) { uploader.start(); } else { uploader.run(); } return true; } private IWSlideService getSlideService() { try { return IBOLookup.getServiceInstance(IWMainApplication.getDefaultIWApplicationContext(), IWSlideService.class); } catch (IBOLookupException e) { e.printStackTrace(); } return null; } private String getLocalizedString(IWContext iwc, String key, String defaultValue) { if (iwc == null) { return defaultValue; } try { IWResourceBundle iwrb = ArticleUtil.getBundle().getResourceBundle(iwc); return iwrb.getLocalizedString(key, defaultValue); } catch (Exception e) { e.printStackTrace(); } return defaultValue; } public String getFixedCommentsUri(String uri, String instanceId, String currentPageUri) { if (uri == null) { uri = String.valueOf(new Date().getTime()); } BuilderService service = getBuilderService(); // Checking uri start: must be /files/... if (!uri.startsWith(new StringBuilder(CoreConstants.PATH_FILES_ROOT).append(CoreConstants.SLASH).toString())) { if (!uri.startsWith(CoreConstants.SLASH)) { uri = new StringBuffer(CoreConstants.SLASH).append(uri).toString(); } uri = new StringBuffer(CoreConstants.CONTENT_PATH).append(CoreConstants.SLASH).append(ContentConstants.COMMENT_SCOPE).append(uri).toString(); } // Checking end if (!uri.endsWith(".xml")) { String fileName = new StringBuffer(instanceId).append(CoreConstants.DOT).append("xml").toString(); if (!uri.endsWith(fileName)) { if (!uri.endsWith(CoreConstants.SLASH)) { uri = new StringBuffer(uri).append(CoreConstants.SLASH).toString(); } uri = new StringBuffer(uri).append(fileName).toString(); } } char[] leaveAsIs = {'-', '_', '/', '.', '0','1','2','3','4','5','6','7','8','9'}; uri = StringHandler.stripNonRomanCharacters(uri, leaveAsIs); if (service != null && !StringUtil.isEmpty(currentPageUri)) { try { String pageKey = service.getPageKeyByURI(currentPageUri); String method = ":method:1:implied:void:setLinkToComments:java.lang.String:"; if (!StringUtil.isEmpty(pageKey) && !service.isPropertySet(pageKey, instanceId, method, getIWMainApplication())) { service.setModuleProperty(pageKey, instanceId, method, new String[] {uri}); } } catch(Exception e) { LOGGER.log(Level.INFO, "Unable to set URI property for CommentsViewer: " + uri, e); } } return uri; } public BuilderLogicWrapper getBuilderLogicWrapper() { if (builderLogicWrapper == null) { ELUtil.getInstance().autowire(this); } return builderLogicWrapper; } private BuilderService getBuilderService() { return getBuilderLogicWrapper().getBuilderService(IWMainApplication.getDefaultIWApplicationContext()); } public void setBuilderLogicWrapper(BuilderLogicWrapper builderLogicWrapper) { this.builderLogicWrapper = builderLogicWrapper; } public boolean markAsRead(Object primaryKey, String beanIdentifier) { if (StringUtil.isEmpty(beanIdentifier)) { return false; } CommentsPersistenceManager manager = getCommentsManager(beanIdentifier); if (manager == null) { return false; } return manager.markCommentAsRead(primaryKey); } public boolean setCommentPublished(CommentsViewerProperties properties) { if (properties == null) { return false; } CommentsPersistenceManager manager = getCommentsManager(properties.getSpringBeanIdentifier()); if (manager == null) { return false; } if (manager.hasFullRightsForComments(properties.getIdentifier())) { if (manager.setCommentPublished(properties.getPrimaryKey(), properties.isMakePublic())) { if (properties.isMakePublic()) { IWContext iwc = CoreUtil.getIWContext(); if (iwc == null) { LOGGER.warning("Unable to send notification about published comment: " + properties.getPrimaryKey()); } else { String handlerEmail = getCurrentUserEmailAddress(iwc); sendNotification(manager.getPersonsToNotifyAboutComment(properties, properties.getPrimaryKey(), true), handlerEmail, iwc, properties, true); } } invokeToReceiveComments(); return true; } } return false; } private String getCurrentUserEmailAddress(IWContext iwc) { User currentUser = iwc.isLoggedOn() ? iwc.getCurrentUser() : null; if (currentUser == null) { return null; } try { UserBusiness userBusiness = getServiceInstance(UserBusiness.class); Email email = userBusiness.getUsersMainEmail(currentUser); return email == null ? null : email.getEmailAddress(); } catch(NoEmailFoundException e) { LOGGER.warning(currentUser + " doesn't have email!"); } catch(Exception e) { LOGGER.log(Level.WARNING, "Error getting user's main email", e); } return null; } public boolean setReadComment(CommentsViewerProperties properties) { if (properties == null) { return false; } CommentsPersistenceManager manager = getCommentsManager(properties.getSpringBeanIdentifier()); if (manager == null) { return false; } if (manager.setCommentRead(properties.getPrimaryKey())) { invokeToReceiveComments(); return true; } return false; } public RenderedComponent getCommentCreator(CommentsViewerProperties properties) { if (properties == null) { return null; } IWContext iwc = CoreUtil.getIWContext(); if (iwc == null) { return null; } CommentCreator commentCreator = new CommentCreator(); commentCreator.setProperties(properties); CommentsPersistenceManager manager = getCommentsManager(properties.getSpringBeanIdentifier()); if (manager != null && manager.canWriteComments(properties)) { commentCreator.setAutoEnableNotifications(manager.isNotificationsAutoEnabled(properties)); if (manager.isCommentsCreationEnabled(properties)) { commentCreator.setAddUploader(true); commentCreator.setUploadPath(manager.getCommentFilesPath(properties)); } } return getBuilderService().getRenderedComponent(commentCreator, null); } private ThemesHelper getThemesHelper() { if (themesHelper == null) { ELUtil.getInstance().autowire(this); } return themesHelper; } private FileDownloadNotifier getFileDownloadNotifier() { if (downloadNotifier == null) { downloadNotifier = ELUtil.getInstance().getBean(CommentAttachmentDownloadNotifier.BEAN_IDENTIFIER); } return downloadNotifier; } public AdvancedProperty sendNotificationsToDownloadDocument(CommentAttachmentNotifyBean properties) { FileDownloadNotifier downloadNotifier = getFileDownloadNotifier(); if (downloadNotifier == null) { return null; } return downloadNotifier.sendNotifications(properties); } private void invokeToReceiveComments() { executeScriptForAllPages(new ScriptBuffer("getAllComments();"), true); } }