/* * Symphony - A modern community (forum/SNS/blog) platform written in Java. * Copyright (C) 2012-2017, b3log.org & hacpai.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.b3log.symphony.service; import org.b3log.latke.Keys; import org.b3log.latke.ioc.inject.Inject; import org.b3log.latke.logging.Level; import org.b3log.latke.logging.Logger; import org.b3log.latke.model.Pagination; import org.b3log.latke.model.User; import org.b3log.latke.repository.*; import org.b3log.latke.service.LangPropsService; import org.b3log.latke.service.ServiceException; import org.b3log.latke.service.annotation.Service; import org.b3log.latke.util.Stopwatchs; import org.b3log.symphony.model.*; import org.b3log.symphony.repository.*; import org.b3log.symphony.util.Emotions; import org.b3log.symphony.util.Symphonys; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * Notification query service. * * @author <a href="http://88250.b3log.org">Liang Ding</a> * @version 1.13.4.12, Apr 27, 2017 * @since 0.2.5 */ @Service public class NotificationQueryService { /** * Logger. */ private static final Logger LOGGER = Logger.getLogger(NotificationQueryService.class.getName()); /** * Notification repository. */ @Inject private NotificationRepository notificationRepository; /** * Article repository. */ @Inject private ArticleRepository articleRepository; /** * Comment query service. */ @Inject private CommentQueryService commentQueryService; /** * User repository. */ @Inject private UserRepository userRepository; /** * Comment repository. */ @Inject private CommentRepository commentRepository; /** * Reward repository. */ @Inject private RewardRepository rewardRepository; /** * Tag repository. */ @Inject private TagRepository tagRepository; /** * Pointtransfer repository. */ @Inject private PointtransferRepository pointtransferRepository; /** * Avatar query service. */ @Inject private AvatarQueryService avatarQueryService; /** * Language service. */ @Inject private LangPropsService langPropsService; /** * Role query service. */ @Inject private RoleQueryService roleQueryService; /** * Gets the count of unread 'following' notifications of a user specified with the given user id. * * @param userId the given user id * @return count of unread notifications, returns {@code 0} if occurs exception */ public int getUnreadFollowingNotificationCount(final String userId) { final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_HAS_READ, FilterOperator.EQUAL, false)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_ARTICLE_UPDATE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_ARTICLE_COMMENT)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_USER)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)); try { final JSONObject result = notificationRepository.get(query); return result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [following] notification count failed [userId=" + userId + "]", e); return 0; } } /** * Gets the count of unread 'sys announce' notifications of a user specified with the given user id. * * @param userId the given user id * @return count of unread notifications, returns {@code 0} if occurs exception */ public int getUnreadSysAnnounceNotificationCount(final String userId) { final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_HAS_READ, FilterOperator.EQUAL, false)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_ARTICLE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_NEW_USER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_ROLE_CHANGED)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)); try { final JSONObject result = notificationRepository.get(query); return result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [sys_announce] notification count failed [userId=" + userId + "]", e); return 0; } } /** * Gets 'sys announce' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "description": int, * "hasRead": boolean * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getSysAnnounceNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_ARTICLE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_NEW_USER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_SYS_ANNOUNCE_ROLE_CHANGED)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String notificationUserId = notification.optString(Notification.NOTIFICATION_USER_ID); final String dataId = notification.optString(Notification.NOTIFICATION_DATA_ID); final int dataType = notification.optInt(Notification.NOTIFICATION_DATA_TYPE); String desTemplate = ""; switch (dataType) { case Notification.DATA_TYPE_C_SYS_ANNOUNCE_NEW_USER: desTemplate = langPropsService.get("notificationSysNewUser1Label"); break; case Notification.DATA_TYPE_C_SYS_ANNOUNCE_ARTICLE: desTemplate = langPropsService.get("notificationSysArticleLabel"); final JSONObject article15 = articleRepository.get(dataId); if (null == article15) { desTemplate = langPropsService.get("removedLabel"); break; } final String articleLink15 = "<a href=\"" + article15.optString(Article.ARTICLE_PERMALINK) + "\">" + article15.optString(Article.ARTICLE_TITLE) + "</a>"; desTemplate = desTemplate.replace("{article}", articleLink15); break; case Notification.DATA_TYPE_C_SYS_ANNOUNCE_ROLE_CHANGED: desTemplate = langPropsService.get("notificationSysRoleChangedLabel"); final String oldRoleId = dataId.split("-")[0]; final String newRoleId = dataId.split("-")[1]; final JSONObject oldRole = roleQueryService.getRole(oldRoleId); final JSONObject newRole = roleQueryService.getRole(newRoleId); desTemplate = desTemplate.replace("{oldRole}", oldRole.optString(Role.ROLE_NAME)); desTemplate = desTemplate.replace("{newRole}", newRole.optString(Role.ROLE_NAME)); break; default: throw new AssertionError(); } notification.put(Common.DESCRIPTION, desTemplate); rslts.add(notification); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [sys_announce] notifications failed", e); throw new ServiceException(e); } } /** * Gets the count of unread notifications of a user specified with the given user id. * * @param userId the given user id * @return count of unread notifications, returns {@code 0} if occurs exception */ public int getUnreadNotificationCount(final String userId) { Stopwatchs.start("Gets unread notification count"); try { final Query query = new Query(); query.setFilter(CompositeFilterOperator.and( new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId), new PropertyFilter(Notification.NOTIFICATION_HAS_READ, FilterOperator.EQUAL, false) )); try { return (int) notificationRepository.count(query); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets unread notification count failed [userId=" + userId + "]", e); return 0; } } finally { Stopwatchs.end(); } } /** * Gets the count of unread notifications of a user specified with the given user id and data type. * * @param userId the given user id * @param notificationDataType the specified notification data type * @return count of unread notifications, returns {@code 0} if occurs exception */ public int getUnreadNotificationCountByType(final String userId, final int notificationDataType) { final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_HAS_READ, FilterOperator.EQUAL, false)); filters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, notificationDataType)); final Query query = new Query(); query.setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)).addProjection(Keys.OBJECT_ID, String.class); try { final JSONObject result = notificationRepository.get(query); return result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [" + notificationDataType + "] notification count failed [userId=" + userId + "]", e); return 0; } } /** * Gets the count of unread 'point' notifications of a user specified with the given user id. * * @param userId the given user id * @return count of unread notifications, returns {@code 0} if occurs exception */ public int getUnreadPointNotificationCount(final String userId) { final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_HAS_READ, FilterOperator.EQUAL, false)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_ARTICLE_REWARD)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_ARTICLE_THANK)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_CHARGE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_EXCHANGE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ABUSE_POINT_DEDUCT)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_COMMENT_THANK)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_TRANSFER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_INVITECODE_USED)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_INVITATION_LINK_USED)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_PERFECT_ARTICLE)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)); try { final JSONObject result = notificationRepository.get(query); return result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT); } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [point] notification count failed [userId=" + userId + "]", e); return 0; } } /** * Gets 'point' type notifications with the specified user id, current page number and page size. * * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "description": int, * "hasRead": boolean * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getPointNotifications(final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_ARTICLE_REWARD)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_ARTICLE_THANK)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_CHARGE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_EXCHANGE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ABUSE_POINT_DEDUCT)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_COMMENT_THANK)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_TRANSFER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_INVITECODE_USED)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_INVITATION_LINK_USED)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_POINT_PERFECT_ARTICLE)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String dataId = notification.optString(Notification.NOTIFICATION_DATA_ID); final int dataType = notification.optInt(Notification.NOTIFICATION_DATA_TYPE); String desTemplate = ""; switch (dataType) { case Notification.DATA_TYPE_C_POINT_ARTICLE_THANK: desTemplate = langPropsService.get("notificationArticleThankLabel"); final JSONObject reward12 = rewardRepository.get(dataId); final String senderId12 = reward12.optString(Reward.SENDER_ID); final JSONObject user12 = userRepository.get(senderId12); final String articleId12 = reward12.optString(Reward.DATA_ID); final JSONObject article12 = articleRepository.get(articleId12); if (null == article12) { desTemplate = langPropsService.get("removedLabel"); break; } final String userLink12 = "<a href=\"/member/" + user12.optString(User.USER_NAME) + "\">" + user12.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", userLink12); final String articleLink12 = "<a href=\"" + article12.optString(Article.ARTICLE_PERMALINK) + "\">" + article12.optString(Article.ARTICLE_TITLE) + "</a>"; desTemplate = desTemplate.replace("{article}", articleLink12); break; case Notification.DATA_TYPE_C_POINT_ARTICLE_REWARD: desTemplate = langPropsService.get("notificationArticleRewardLabel"); final JSONObject reward7 = rewardRepository.get(dataId); final String senderId7 = reward7.optString(Reward.SENDER_ID); final JSONObject user7 = userRepository.get(senderId7); final String articleId7 = reward7.optString(Reward.DATA_ID); final JSONObject article7 = articleRepository.get(articleId7); if (null == article7) { desTemplate = langPropsService.get("removedLabel"); break; } final String userLink7 = "<a href=\"/member/" + user7.optString(User.USER_NAME) + "\">" + user7.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", userLink7); final String articleLink7 = "<a href=\"" + article7.optString(Article.ARTICLE_PERMALINK) + "\">" + article7.optString(Article.ARTICLE_TITLE) + "</a>"; desTemplate = desTemplate.replace("{article}", articleLink7); break; case Notification.DATA_TYPE_C_POINT_CHARGE: desTemplate = langPropsService.get("notificationPointChargeLabel"); final JSONObject transfer5 = pointtransferRepository.get(dataId); final int sum5 = transfer5.optInt(Pointtransfer.SUM); final String memo5 = transfer5.optString(Pointtransfer.DATA_ID); final String yuan = memo5.split("-")[0]; desTemplate = desTemplate.replace("{yuan}", yuan); desTemplate = desTemplate.replace("{point}", String.valueOf(sum5)); break; case Notification.DATA_TYPE_C_POINT_EXCHANGE: desTemplate = langPropsService.get("notificationPointExchangeLabel"); final JSONObject transfer6 = pointtransferRepository.get(dataId); final int sum6 = transfer6.optInt(Pointtransfer.SUM); final String yuan6 = transfer6.optString(Pointtransfer.DATA_ID); desTemplate = desTemplate.replace("{yuan}", yuan6); desTemplate = desTemplate.replace("{point}", String.valueOf(sum6)); break; case Notification.DATA_TYPE_C_ABUSE_POINT_DEDUCT: desTemplate = langPropsService.get("notificationAbusePointDeductLabel"); final JSONObject transfer7 = pointtransferRepository.get(dataId); final int sum7 = transfer7.optInt(Pointtransfer.SUM); final String memo7 = transfer7.optString(Pointtransfer.DATA_ID); desTemplate = desTemplate.replace("{action}", memo7); desTemplate = desTemplate.replace("{point}", String.valueOf(sum7)); break; case Notification.DATA_TYPE_C_POINT_COMMENT_THANK: desTemplate = langPropsService.get("notificationCmtThankLabel"); final JSONObject reward8 = rewardRepository.get(dataId); final String senderId8 = reward8.optString(Reward.SENDER_ID); final JSONObject user8 = userRepository.get(senderId8); final JSONObject comment8 = commentRepository.get(reward8.optString(Reward.DATA_ID)); final String articleId8 = comment8.optString(Comment.COMMENT_ON_ARTICLE_ID); final JSONObject article8 = articleRepository.get(articleId8); if (null == article8) { desTemplate = langPropsService.get("removedLabel"); break; } final String userLink8 = "<a href=\"/member/" + user8.optString(User.USER_NAME) + "\">" + user8.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", userLink8); final String articleLink8 = "<a href=\"" + article8.optString(Article.ARTICLE_PERMALINK) + "\">" + article8.optString(Article.ARTICLE_TITLE) + "</a>"; desTemplate = desTemplate.replace("{article}", articleLink8); break; case Notification.DATA_TYPE_C_POINT_TRANSFER: desTemplate = langPropsService.get("notificationPointTransferLabel"); final JSONObject transfer101 = pointtransferRepository.get(dataId); final String fromId101 = transfer101.optString(Pointtransfer.FROM_ID); final JSONObject user101 = userRepository.get(fromId101); final int sum101 = transfer101.optInt(Pointtransfer.SUM); final String userLink101 = "<a href=\"/member/" + user101.optString(User.USER_NAME) + "\">" + user101.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", userLink101); desTemplate = desTemplate.replace("{amount}", String.valueOf(sum101)); break; case Notification.DATA_TYPE_C_INVITECODE_USED: desTemplate = langPropsService.get("notificationInvitecodeUsedLabel"); final JSONObject invitedUser = userRepository.get(dataId); final String invitedUserLink = "<a href=\"/member/" + invitedUser.optString(User.USER_NAME) + "\">" + invitedUser.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", invitedUserLink); break; case Notification.DATA_TYPE_C_INVITATION_LINK_USED: desTemplate = langPropsService.get("notificationInvitationLinkUsedLabel"); final JSONObject invitedUser18 = userRepository.get(dataId); final String invitedUserLink18 = "<a href=\"/member/" + invitedUser18.optString(User.USER_NAME) + "\">" + invitedUser18.optString(User.USER_NAME) + "</a>"; desTemplate = desTemplate.replace("{user}", invitedUserLink18); break; case Notification.DATA_TYPE_C_POINT_PERFECT_ARTICLE: desTemplate = langPropsService.get("notificationPointPerfectArticleLabel"); final JSONObject article22 = articleRepository.get(dataId); if (null == article22) { desTemplate = langPropsService.get("removedLabel"); break; } final String articleLink22 = "<a href=\"" + article22.optString(Article.ARTICLE_PERMALINK) + "\">" + article22.optString(Article.ARTICLE_TITLE) + "</a>"; desTemplate = desTemplate.replace("{article}", articleLink22); break; default: throw new AssertionError(); } notification.put(Common.DESCRIPTION, desTemplate); rslts.add(notification); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [point] notifications failed", e); throw new ServiceException(e); } } /** * Gets 'commented' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "commentAuthorName": "", * "commentContent": "", * "commentAuthorThumbnailURL": "", * "commentArticleTitle": "", * "commentArticleType": int, * "commentSharpURL": "", * "commentCreateTime": java.util.Date, * "hasRead": boolean * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getCommentedNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_COMMENTED)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject user = userRepository.get(userId); final int cmtViewMode = user.optInt(UserExt.USER_COMMENT_VIEW_MODE); final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String commentId = notification.optString(Notification.NOTIFICATION_DATA_ID); final JSONObject comment = commentQueryService.getCommentById(avatarViewMode, commentId); final Query q = new Query().setPageCount(1). addProjection(Article.ARTICLE_TITLE, String.class). addProjection(Article.ARTICLE_TYPE, Integer.class). setFilter(new PropertyFilter(Keys.OBJECT_ID, FilterOperator.EQUAL, comment.optString(Comment.COMMENT_ON_ARTICLE_ID))); final JSONArray rlts = articleRepository.get(q).optJSONArray(Keys.RESULTS); final JSONObject article = rlts.optJSONObject(0); final String articleTitle = article.optString(Article.ARTICLE_TITLE); final int articleType = article.optInt(Article.ARTICLE_TYPE); final int articlePerfect = article.optInt(Article.ARTICLE_PERFECT); final JSONObject commentedNotification = new JSONObject(); commentedNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); commentedNotification.put(Comment.COMMENT_T_AUTHOR_NAME, comment.optString(Comment.COMMENT_T_AUTHOR_NAME)); commentedNotification.put(Comment.COMMENT_CONTENT, comment.optString(Comment.COMMENT_CONTENT)); commentedNotification.put(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL, comment.optString(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL)); commentedNotification.put(Common.THUMBNAIL_UPDATE_TIME, comment.optJSONObject(Comment.COMMENT_T_COMMENTER). optLong(UserExt.USER_UPDATE_TIME)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_TITLE, Emotions.convert(articleTitle)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_TYPE, articleType); commentedNotification.put(Comment.COMMENT_CREATE_TIME, comment.opt(Comment.COMMENT_CREATE_TIME)); commentedNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_PERFECT, articlePerfect); final String articleId = comment.optString(Comment.COMMENT_ON_ARTICLE_ID); final int cmtPage = commentQueryService.getCommentPage(articleId, commentId, cmtViewMode, Symphonys.getInt("articleCommentsPageSize")); commentedNotification.put(Comment.COMMENT_SHARP_URL, "/article/" + articleId + "?p=" + cmtPage + "&m=" + cmtViewMode + "#" + commentId); rslts.add(commentedNotification); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [commented] notifications", e); throw new ServiceException(e); } } /** * Gets 'reply' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "commentAuthorName": "", * "commentContent": "", * "commentAuthorThumbnailURL": "", * "commentArticleTitle": "", * "commentArticleType": int, * "commentSharpURL": "", * "commentCreateTime": java.util.Date, * "hasRead": boolean * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getReplyNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_REPLY)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String commentId = notification.optString(Notification.NOTIFICATION_DATA_ID); final JSONObject comment = commentQueryService.getCommentById(avatarViewMode, commentId); final Query q = new Query().setPageCount(1). addProjection(Article.ARTICLE_TITLE, String.class). addProjection(Article.ARTICLE_TYPE, Integer.class). setFilter(new PropertyFilter(Keys.OBJECT_ID, FilterOperator.EQUAL, comment.optString(Comment.COMMENT_ON_ARTICLE_ID))); final JSONArray rlts = articleRepository.get(q).optJSONArray(Keys.RESULTS); final JSONObject article = rlts.optJSONObject(0); final String articleTitle = article.optString(Article.ARTICLE_TITLE); final int articleType = article.optInt(Article.ARTICLE_TYPE); final int articlePerfect = article.optInt(Article.ARTICLE_PERFECT); final JSONObject commentedNotification = new JSONObject(); commentedNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); commentedNotification.put(Comment.COMMENT_T_AUTHOR_NAME, comment.optString(Comment.COMMENT_T_AUTHOR_NAME)); commentedNotification.put(Comment.COMMENT_CONTENT, comment.optString(Comment.COMMENT_CONTENT)); commentedNotification.put(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL, comment.optString(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL)); commentedNotification.put(Common.THUMBNAIL_UPDATE_TIME, comment.optJSONObject(Comment.COMMENT_T_COMMENTER). optLong(UserExt.USER_UPDATE_TIME)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_TITLE, Emotions.convert(articleTitle)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_TYPE, articleType); commentedNotification.put(Comment.COMMENT_SHARP_URL, comment.optString(Comment.COMMENT_SHARP_URL)); commentedNotification.put(Comment.COMMENT_CREATE_TIME, comment.opt(Comment.COMMENT_CREATE_TIME)); commentedNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); commentedNotification.put(Comment.COMMENT_T_ARTICLE_PERFECT, articlePerfect); rslts.add(commentedNotification); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [reply] notifications", e); throw new ServiceException(e); } } /** * Gets 'at' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "authorName": "", * "content": "", * "thumbnailURL": "", * "articleTitle": "", * "articleType": int, * "url": "", * "createTime": java.util.Date, * "hasRead": boolean, * "atInArticle": boolean, * "isAt": boolean, * "articleTags": "", // if atInArticle is true * "articleTagObjs": [{}, ....], // if atInArticle is true * "articleCommentCnt": int // if atInArticle is true * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getAtNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_AT)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ARTICLE_NEW_FOLLOWER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ARTICLE_NEW_WATCHER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_COMMENT_VOTE_UP)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_COMMENT_VOTE_DOWN)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ARTICLE_VOTE_UP)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_ARTICLE_VOTE_DOWN)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final int dataType = notification.optInt(Notification.NOTIFICATION_DATA_TYPE); final String dataId = notification.optString(Notification.NOTIFICATION_DATA_ID); final JSONObject atNotification = new JSONObject(); atNotification.put(Notification.NOTIFICATION_DATA_TYPE, dataType); String description = ""; switch (dataType) { case Notification.DATA_TYPE_C_AT: final JSONObject comment = commentQueryService.getCommentById(avatarViewMode, dataId); if (null != comment) { final Query q = new Query().setPageCount(1). addProjection(Article.ARTICLE_TITLE, String.class). addProjection(Article.ARTICLE_TYPE, Integer.class). setFilter(new PropertyFilter(Keys.OBJECT_ID, FilterOperator.EQUAL, comment.optString(Comment.COMMENT_ON_ARTICLE_ID))); final JSONArray rlts = articleRepository.get(q).optJSONArray(Keys.RESULTS); final JSONObject article = rlts.optJSONObject(0); final String articleTitle = article.optString(Article.ARTICLE_TITLE); final int articleType = article.optInt(Article.ARTICLE_TYPE); final int articlePerfect = article.optInt(Article.ARTICLE_PERFECT); atNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); atNotification.put(Common.AUTHOR_NAME, comment.optString(Comment.COMMENT_T_AUTHOR_NAME)); atNotification.put(Common.CONTENT, comment.optString(Comment.COMMENT_CONTENT)); atNotification.put(Common.THUMBNAIL_URL, comment.optString(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL)); atNotification.put(Common.THUMBNAIL_UPDATE_TIME, comment.optJSONObject(Comment.COMMENT_T_COMMENTER). optLong(UserExt.USER_UPDATE_TIME)); atNotification.put(Article.ARTICLE_TITLE, Emotions.convert(articleTitle)); atNotification.put(Article.ARTICLE_TYPE, articleType); atNotification.put(Common.URL, comment.optString(Comment.COMMENT_SHARP_URL)); atNotification.put(Common.CREATE_TIME, comment.opt(Comment.COMMENT_CREATE_TIME)); atNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); atNotification.put(Notification.NOTIFICATION_T_AT_IN_ARTICLE, false); atNotification.put(Article.ARTICLE_PERFECT, articlePerfect); rslts.add(atNotification); } else { // The 'at' in article content final JSONObject article = articleRepository.get(dataId); final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject articleAuthor = userRepository.get(articleAuthorId); atNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); atNotification.put(Common.AUTHOR_NAME, articleAuthor.optString(User.USER_NAME)); atNotification.put(Common.CONTENT, ""); final String thumbnailURL = avatarQueryService.getAvatarURLByUser(avatarViewMode, articleAuthor, "48"); atNotification.put(Common.THUMBNAIL_URL, thumbnailURL); atNotification.put(Common.THUMBNAIL_UPDATE_TIME, articleAuthor.optLong(UserExt.USER_UPDATE_TIME)); atNotification.put(Article.ARTICLE_TITLE, Emotions.convert(article.optString(Article.ARTICLE_TITLE))); atNotification.put(Article.ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE)); atNotification.put(Common.URL, article.optString(Article.ARTICLE_PERMALINK)); atNotification.put(Common.CREATE_TIME, new Date(article.optLong(Article.ARTICLE_CREATE_TIME))); atNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); atNotification.put(Notification.NOTIFICATION_T_AT_IN_ARTICLE, true); final String tagsStr = article.optString(Article.ARTICLE_TAGS); atNotification.put(Article.ARTICLE_TAGS, tagsStr); final List<JSONObject> tags = buildTagObjs(tagsStr); atNotification.put(Article.ARTICLE_T_TAG_OBJS, (Object) tags); atNotification.put(Article.ARTICLE_COMMENT_CNT, article.optInt(Article.ARTICLE_COMMENT_CNT)); atNotification.put(Article.ARTICLE_PERFECT, article.optInt(Article.ARTICLE_PERFECT)); rslts.add(atNotification); } break; case Notification.DATA_TYPE_C_ARTICLE_NEW_FOLLOWER: case Notification.DATA_TYPE_C_ARTICLE_NEW_WATCHER: final String articleId = dataId.split("-")[0]; final String followerUserId = dataId.split("-")[1]; atNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); atNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); atNotification.put(Common.CREATE_TIME, new Date(notification.optLong(Keys.OBJECT_ID))); final JSONObject article = articleRepository.get(articleId); if (null == article) { description = langPropsService.get("removedLabel"); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); continue; } if (Notification.DATA_TYPE_C_ARTICLE_NEW_FOLLOWER == dataType) { description = langPropsService.get("notificationArticleNewFollowerLabel"); } else if (Notification.DATA_TYPE_C_ARTICLE_NEW_WATCHER == dataType) { description = langPropsService.get("notificationArticleNewWatcherLabel"); } final JSONObject followerUser = userRepository.get(followerUserId); final String followerUserName = followerUser.optString(User.USER_NAME); atNotification.put(User.USER_NAME, followerUserName); final String thumbnailURL = avatarQueryService.getAvatarURLByUser(avatarViewMode, followerUser, "48"); atNotification.put(Common.THUMBNAIL_URL, thumbnailURL); atNotification.put(Common.THUMBNAIL_UPDATE_TIME, followerUser.optLong(UserExt.USER_UPDATE_TIME)); final String userLink = "<a href=\"/member/" + followerUserName + "\">" + followerUserName + "</a> "; description = description.replace("{user}", userLink); final String articleLink = " <a href=\"" + article.optString(Article.ARTICLE_PERMALINK) + "\">" + Emotions.convert(article.optString(Article.ARTICLE_TITLE)) + "</a>"; description = description.replace("{article}", articleLink); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); break; case Notification.DATA_TYPE_C_COMMENT_VOTE_UP: case Notification.DATA_TYPE_C_COMMENT_VOTE_DOWN: case Notification.DATA_TYPE_C_ARTICLE_VOTE_UP: case Notification.DATA_TYPE_C_ARTICLE_VOTE_DOWN: final String commentOrArticleId = dataId.split("-")[0]; final String voterId = dataId.split("-")[1]; JSONObject articleVote = null; if (Notification.DATA_TYPE_C_COMMENT_VOTE_UP == dataType) { description = langPropsService.get("notificationCommentVoteUpLabel"); articleVote = commentRepository.get(commentOrArticleId); if (null == articleVote) { description = langPropsService.get("removedLabel"); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); continue; } articleVote = articleRepository.get(articleVote.optString(Comment.COMMENT_ON_ARTICLE_ID)); } else if (Notification.DATA_TYPE_C_COMMENT_VOTE_DOWN == dataType) { description = langPropsService.get("notificationCommentVoteDownLabel"); articleVote = commentRepository.get(commentOrArticleId); if (null == articleVote) { description = langPropsService.get("removedLabel"); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); continue; } articleVote = articleRepository.get(articleVote.optString(Comment.COMMENT_ON_ARTICLE_ID)); } else if (Notification.DATA_TYPE_C_ARTICLE_VOTE_UP == dataType) { description = langPropsService.get("notificationArticleVoteUpLabel"); articleVote = articleRepository.get(commentOrArticleId); } else if (Notification.DATA_TYPE_C_ARTICLE_VOTE_DOWN == dataType) { description = langPropsService.get("notificationArticleVoteDownLabel"); articleVote = articleRepository.get(commentOrArticleId); } if (null == articleVote) { description = langPropsService.get("removedLabel"); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); continue; } atNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); atNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); atNotification.put(Common.CREATE_TIME, new Date(notification.optLong(Keys.OBJECT_ID))); final JSONObject voter = userRepository.get(voterId); final String voterUserName = voter.optString(User.USER_NAME); atNotification.put(User.USER_NAME, voterUserName); final String thumbnailURLVote = avatarQueryService.getAvatarURLByUser(avatarViewMode, voter, "48"); atNotification.put(Common.THUMBNAIL_URL, thumbnailURLVote); atNotification.put(Common.THUMBNAIL_UPDATE_TIME, voter.optLong(UserExt.USER_UPDATE_TIME)); final String userLinkVote = "<a href=\"/member/" + voterUserName + "\">" + voterUserName + "</a> "; description = description.replace("{user}", userLinkVote); final String articleLinkVote = " <a href=\"" + articleVote.optString(Article.ARTICLE_PERMALINK) + "\">" + Emotions.convert(articleVote.optString(Article.ARTICLE_TITLE)) + "</a>"; description = description.replace("{article}", articleLinkVote); atNotification.put(Common.DESCRIPTION, description); rslts.add(atNotification); break; } } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [at] notifications", e); throw new ServiceException(e); } } /** * Gets 'following' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "authorName": "", * "content": "", * "thumbnailURL": "", * "articleTitle": "", * "articleType": int, * "url": "", * "createTime": java.util.Date, * "hasRead": boolean, * "type": "", // article/comment * "articleTags": "", // if atInArticle is true * "articleTagObjs": [{}, ....], // if atInArticle is true * "articleCommentCnt": int // if atInArticle is true * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getFollowingNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); final List<Filter> subFilters = new ArrayList<>(); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_USER)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_ARTICLE_UPDATE)); subFilters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_FOLLOWING_ARTICLE_COMMENT)); filters.add(new CompositeFilter(CompositeFilterOperator.OR, subFilters)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String commentId = notification.optString(Notification.NOTIFICATION_DATA_ID); final JSONObject comment = commentQueryService.getCommentById(avatarViewMode, commentId); if (null != comment) { final Query q = new Query().setPageCount(1). addProjection(Article.ARTICLE_TITLE, String.class). addProjection(Article.ARTICLE_TYPE, Integer.class). setFilter(new PropertyFilter(Keys.OBJECT_ID, FilterOperator.EQUAL, comment.optString(Comment.COMMENT_ON_ARTICLE_ID))); final JSONArray rlts = articleRepository.get(q).optJSONArray(Keys.RESULTS); final JSONObject article = rlts.optJSONObject(0); final String articleTitle = article.optString(Article.ARTICLE_TITLE); final int articleType = article.optInt(Article.ARTICLE_TYPE); final int articlePerfect = article.optInt(Article.ARTICLE_PERFECT); final JSONObject followingNotification = new JSONObject(); followingNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); followingNotification.put(Common.AUTHOR_NAME, comment.optString(Comment.COMMENT_T_AUTHOR_NAME)); followingNotification.put(Common.CONTENT, comment.optString(Comment.COMMENT_CONTENT)); followingNotification.put(Common.THUMBNAIL_URL, comment.optString(Comment.COMMENT_T_AUTHOR_THUMBNAIL_URL)); followingNotification.put(Common.THUMBNAIL_UPDATE_TIME, comment.optJSONObject(Comment.COMMENT_T_COMMENTER). optLong(UserExt.USER_UPDATE_TIME)); followingNotification.put(Article.ARTICLE_TITLE, Emotions.convert(articleTitle)); followingNotification.put(Article.ARTICLE_TYPE, articleType); followingNotification.put(Common.URL, comment.optString(Comment.COMMENT_SHARP_URL)); followingNotification.put(Common.CREATE_TIME, comment.opt(Comment.COMMENT_CREATE_TIME)); followingNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); followingNotification.put(Notification.NOTIFICATION_T_IS_COMMENT, true); followingNotification.put(Article.ARTICLE_PERFECT, articlePerfect); rslts.add(followingNotification); } else { // The 'at' in article content final JSONObject article = articleRepository.get(commentId); final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject articleAuthor = userRepository.get(articleAuthorId); final JSONObject followingNotification = new JSONObject(); followingNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); followingNotification.put(Common.AUTHOR_NAME, articleAuthor.optString(User.USER_NAME)); followingNotification.put(Common.CONTENT, ""); final String thumbnailURL = avatarQueryService.getAvatarURLByUser(avatarViewMode, articleAuthor, "48"); followingNotification.put(Common.THUMBNAIL_URL, thumbnailURL); followingNotification.put(Common.THUMBNAIL_UPDATE_TIME, articleAuthor.optLong(UserExt.USER_UPDATE_TIME)); followingNotification.put(Article.ARTICLE_TITLE, Emotions.convert(article.optString(Article.ARTICLE_TITLE))); followingNotification.put(Article.ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE)); followingNotification.put(Common.URL, article.optString(Article.ARTICLE_PERMALINK)); followingNotification.put(Common.CREATE_TIME, new Date(article.optLong(Article.ARTICLE_CREATE_TIME))); followingNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); followingNotification.put(Notification.NOTIFICATION_T_IS_COMMENT, false); final String tagsStr = article.optString(Article.ARTICLE_TAGS); followingNotification.put(Article.ARTICLE_TAGS, tagsStr); final List<JSONObject> tags = buildTagObjs(tagsStr); followingNotification.put(Article.ARTICLE_T_TAG_OBJS, (Object) tags); followingNotification.put(Article.ARTICLE_COMMENT_CNT, article.optInt(Article.ARTICLE_COMMENT_CNT)); followingNotification.put(Article.ARTICLE_PERFECT, article.optInt(Article.ARTICLE_PERFECT)); rslts.add(followingNotification); } } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [following] notifications", e); throw new ServiceException(e); } } /** * Gets 'broadcast' type notifications with the specified user id, current page number and page size. * * @param avatarViewMode the specified avatar view mode * @param userId the specified user id * @param currentPageNum the specified page number * @param pageSize the specified page size * @return result json object, for example, <pre> * { * "paginationRecordCount": int, * "rslts": java.util.List[{ * "oId": "", // notification record id * "authorName": "", * "content": "", * "thumbnailURL": "", * "articleTitle": "", * "articleType": int, * "articleTags": "", * "articleTagObjs": [{}, ....], * "articleCommentCnt": int, * "url": "", * "createTime": java.util.Date, * "hasRead": boolean, * "type": "", // article/comment * }, ....] * } * </pre> * @throws ServiceException service exception */ public JSONObject getBroadcastNotifications(final int avatarViewMode, final String userId, final int currentPageNum, final int pageSize) throws ServiceException { final JSONObject ret = new JSONObject(); final List<JSONObject> rslts = new ArrayList<>(); ret.put(Keys.RESULTS, (Object) rslts); final List<Filter> filters = new ArrayList<>(); filters.add(new PropertyFilter(Notification.NOTIFICATION_USER_ID, FilterOperator.EQUAL, userId)); filters.add(new PropertyFilter(Notification.NOTIFICATION_DATA_TYPE, FilterOperator.EQUAL, Notification.DATA_TYPE_C_BROADCAST)); final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize). setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)). addSort(Notification.NOTIFICATION_HAS_READ, SortDirection.ASCENDING). addSort(Keys.OBJECT_ID, SortDirection.DESCENDING); try { final JSONObject queryResult = notificationRepository.get(query); final JSONArray results = queryResult.optJSONArray(Keys.RESULTS); ret.put(Pagination.PAGINATION_RECORD_COUNT, queryResult.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_RECORD_COUNT)); for (int i = 0; i < results.length(); i++) { final JSONObject notification = results.optJSONObject(i); final String articleId = notification.optString(Notification.NOTIFICATION_DATA_ID); final Query q = new Query().setPageCount(1). addProjection(Article.ARTICLE_TITLE, String.class). addProjection(Article.ARTICLE_TYPE, Integer.class). addProjection(Article.ARTICLE_AUTHOR_ID, String.class). addProjection(Article.ARTICLE_PERMALINK, String.class). addProjection(Article.ARTICLE_CREATE_TIME, Long.class). addProjection(Article.ARTICLE_TAGS, String.class). addProjection(Article.ARTICLE_COMMENT_CNT, Integer.class). addProjection(Article.ARTICLE_PERFECT, Integer.class). setFilter(new PropertyFilter(Keys.OBJECT_ID, FilterOperator.EQUAL, articleId)); final JSONArray rlts = articleRepository.get(q).optJSONArray(Keys.RESULTS); final JSONObject article = rlts.optJSONObject(0); if (null == article) { LOGGER.warn("Not found article[id=" + articleId + ']'); continue; } final String articleTitle = article.optString(Article.ARTICLE_TITLE); final String articleAuthorId = article.optString(Article.ARTICLE_AUTHOR_ID); final JSONObject author = userRepository.get(articleAuthorId); if (null == author) { LOGGER.warn("Not found user[id=" + articleAuthorId + ']'); continue; } final JSONObject broadcastNotification = new JSONObject(); broadcastNotification.put(Keys.OBJECT_ID, notification.optString(Keys.OBJECT_ID)); broadcastNotification.put(Common.AUTHOR_NAME, author.optString(User.USER_NAME)); broadcastNotification.put(Common.CONTENT, ""); broadcastNotification.put(Common.THUMBNAIL_URL, avatarQueryService.getAvatarURLByUser(avatarViewMode, author, "48")); broadcastNotification.put(Common.THUMBNAIL_UPDATE_TIME, author.optLong(UserExt.USER_UPDATE_TIME)); broadcastNotification.put(Article.ARTICLE_TITLE, Emotions.convert(articleTitle)); broadcastNotification.put(Common.URL, article.optString(Article.ARTICLE_PERMALINK)); broadcastNotification.put(Common.CREATE_TIME, new Date(article.optLong(Article.ARTICLE_CREATE_TIME))); broadcastNotification.put(Notification.NOTIFICATION_HAS_READ, notification.optBoolean(Notification.NOTIFICATION_HAS_READ)); broadcastNotification.put(Common.TYPE, Article.ARTICLE); broadcastNotification.put(Article.ARTICLE_TYPE, article.optInt(Article.ARTICLE_TYPE)); final String tagsStr = article.optString(Article.ARTICLE_TAGS); broadcastNotification.put(Article.ARTICLE_TAGS, tagsStr); final List<JSONObject> tags = buildTagObjs(tagsStr); broadcastNotification.put(Article.ARTICLE_T_TAG_OBJS, (Object) tags); broadcastNotification.put(Article.ARTICLE_COMMENT_CNT, article.optInt(Article.ARTICLE_COMMENT_CNT)); broadcastNotification.put(Article.ARTICLE_PERFECT, article.optInt(Article.ARTICLE_PERFECT)); rslts.add(broadcastNotification); } return ret; } catch (final RepositoryException e) { LOGGER.log(Level.ERROR, "Gets [broadcast] notifications", e); throw new ServiceException(e); } } /** * Builds tag objects with the specified tags string. * * @param tagsStr the specified tags string * @return tag objects */ private List<JSONObject> buildTagObjs(final String tagsStr) { final List<JSONObject> ret = new ArrayList<>(); final String[] tagTitles = tagsStr.split(","); for (final String tagTitle : tagTitles) { final JSONObject tag = new JSONObject(); tag.put(Tag.TAG_TITLE, tagTitle); final String uri = tagRepository.getURIByTitle(tagTitle); if (null != uri) { tag.put(Tag.TAG_URI, uri); } else { tag.put(Tag.TAG_URI, tagTitle); tagRepository.getURIByTitle(tagTitle); } ret.add(tag); } return ret; } }