diff --git a/nb-configuration.xml b/nb-configuration.xml
index 55bcdc233..2c0d94580 100644
--- a/nb-configuration.xml
+++ b/nb-configuration.xml
@@ -17,6 +17,7 @@ Without this configuration present, some functionality in the IDE may be limited
markdowns
permalink
servlet
+ Unfollows
whitelist
diff --git a/src/main/java/org/b3log/symphony/event/ArticleNotifier.java b/src/main/java/org/b3log/symphony/event/ArticleNotifier.java
index f14098240..d45331e22 100644
--- a/src/main/java/org/b3log/symphony/event/ArticleNotifier.java
+++ b/src/main/java/org/b3log/symphony/event/ArticleNotifier.java
@@ -15,6 +15,8 @@
*/
package org.b3log.symphony.event;
+import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
@@ -22,15 +24,15 @@
import org.b3log.latke.event.AbstractEventListener;
import org.b3log.latke.event.Event;
import org.b3log.latke.event.EventException;
-import org.b3log.latke.ioc.LatkeBeanManager;
-import org.b3log.latke.ioc.Lifecycle;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.User;
import org.b3log.latke.urlfetch.URLFetchService;
import org.b3log.latke.urlfetch.URLFetchServiceFactory;
import org.b3log.symphony.model.Article;
+import org.b3log.symphony.model.Follow;
import org.b3log.symphony.model.Notification;
+import org.b3log.symphony.service.FollowQueryService;
import org.b3log.symphony.service.NotificationMgmtService;
import org.b3log.symphony.service.UserQueryService;
import org.json.JSONObject;
@@ -39,7 +41,7 @@
* Sends an article notification to the user who be @username in the article content.
*
* @author Liang Ding
- * @version 1.0.0.3, Sep 6, 2013
+ * @version 1.0.0.4, Nov 11, 2013
* @since 0.2.0
*/
@Named
@@ -61,15 +63,23 @@ public class ArticleNotifier extends AbstractEventListener {
@Inject
private NotificationMgmtService notificationMgmtService;
+ /**
+ * Follow query service.
+ */
+ @Inject
+ private FollowQueryService followQueryService;
+
+ /**
+ * User query service.
+ */
+ @Inject
+ private UserQueryService userQueryService;
+
@Override
public void action(final Event event) throws EventException {
final JSONObject data = event.getData();
LOGGER.log(Level.DEBUG, "Processing an event[type={0}, data={1}] in listener[className={2}]",
- new Object[]{event.getType(), data, ArticleNotifier.class.getName()});
-
-
- final LatkeBeanManager beanManager = Lifecycle.getBeanManager();
- final UserQueryService userQueryService = beanManager.getReference(UserQueryService.class);
+ new Object[]{event.getType(), data, ArticleNotifier.class.getName()});
try {
final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE);
@@ -86,6 +96,8 @@ public void action(final Event event) throws EventException {
return;
}
+ final Set atedUserIds = new HashSet();
+
// 'At' Notification
for (final String userName : atUserNames) {
final JSONObject user = userQueryService.getUserByName(userName);
@@ -97,12 +109,30 @@ public void action(final Event event) throws EventException {
}
final JSONObject requestJSONObject = new JSONObject();
- requestJSONObject.put(Notification.NOTIFICATION_USER_ID, user.optString(Keys.OBJECT_ID));
+ final String atedUserId = user.optString(Keys.OBJECT_ID);
+ requestJSONObject.put(Notification.NOTIFICATION_USER_ID, atedUserId);
requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, originalArticle.optString(Keys.OBJECT_ID));
notificationMgmtService.addAtNotification(requestJSONObject);
+
+ atedUserIds.add(atedUserId);
}
+
+ // 'Article' Notification
+ final List followerUsers = followQueryService.getFollowerUsers(articleAuthorId, 1, Integer.MAX_VALUE);
+ for (final JSONObject followerUser : followerUsers) {
+ final JSONObject requestJSONObject = new JSONObject();
+ final String followerUserId = followerUser.optString(Follow.FOLLOWER_ID);
+
+ if (atedUserIds.contains(followerUserId)) {
+ continue;
+ }
+
+ requestJSONObject.put(Notification.NOTIFICATION_USER_ID, followerUserId);
+ requestJSONObject.put(Notification.NOTIFICATION_DATA_ID, originalArticle.optString(Keys.OBJECT_ID));
+ notificationMgmtService.addFollowingUserNotification(requestJSONObject);
+ }
// final Set qqSet = new HashSet();
// for (final String userName : atUserNames) {
@@ -116,7 +146,6 @@ public void action(final Event event) throws EventException {
// if (qqSet.isEmpty()) {
// return;
// }
-
// /*
// * {
// * "key": "",
@@ -153,7 +182,7 @@ public void action(final Event event) throws EventException {
/**
* Gets the event type {@linkplain EventTypes#ADD_ARTICLE}.
- *
+ *
* @return event type
*/
@Override
diff --git a/src/main/java/org/b3log/symphony/model/Common.java b/src/main/java/org/b3log/symphony/model/Common.java
index 56dfaaa5b..bd0fde8c6 100644
--- a/src/main/java/org/b3log/symphony/model/Common.java
+++ b/src/main/java/org/b3log/symphony/model/Common.java
@@ -19,7 +19,7 @@
* This class defines all common model relevant keys.
*
* @author Liang Ding
- * @version 1.0.1.8, Oct 11, 2013
+ * @version 1.0.1.9, Nov 11, 2013
* @since 0.2.0
*/
public final class Common {
@@ -103,6 +103,11 @@ public final class Common {
* Key of latest comment articles.
*/
public static final String LATEST_CMT_ARTICLES = "latestCmtArticles";
+
+ /**
+ * Key of user id.
+ */
+ public static final String USER_ID = "userId";
/**
* Key of user home articles.
@@ -134,6 +139,16 @@ public final class Common {
*/
public static final String UNREAD_AT_NOTIFICATION_CNT = "unreadAtNotificationCnt";
+ /**
+ * Key of 'followingUser' notifications.
+ */
+ public static final String FOLLOWING_USER_NOTIFICATIONS = "followingUserNotifications";
+
+ /**
+ * Key of unread 'followingUser' notifications count.
+ */
+ public static final String UNREAD_FOLLOWING_USER_NOTIFICATION_CNT = "unreadFollowingUserNotificationCnt";
+
/**
* Key of author name.
*/
diff --git a/src/main/java/org/b3log/symphony/model/Notification.java b/src/main/java/org/b3log/symphony/model/Notification.java
index 9cef2abf0..4da5d9688 100644
--- a/src/main/java/org/b3log/symphony/model/Notification.java
+++ b/src/main/java/org/b3log/symphony/model/Notification.java
@@ -19,7 +19,7 @@
* This class defines all notification model relevant keys.
*
* @author Liang Ding
- * @version 1.0.0.1, Sep 2, 2013
+ * @version 1.0.0.2, Nov 11, 2013
* @since 0.2.5
*/
public final class Notification {
@@ -74,7 +74,12 @@ public final class Notification {
* Data type - commented.
*/
public static final int DATA_TYPE_C_COMMENTED = 3;
-
+
+ /**
+ * Data type - followingUser.
+ */
+ public static final int DATA_TYPE_C_FOLLOWING_USER = 4;
+
//// Transient ////
/**
* Key of unread notification count.
diff --git a/src/main/java/org/b3log/symphony/processor/FollowProcessor.java b/src/main/java/org/b3log/symphony/processor/FollowProcessor.java
new file mode 100644
index 000000000..604d88345
--- /dev/null
+++ b/src/main/java/org/b3log/symphony/processor/FollowProcessor.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.b3log.symphony.processor;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.b3log.latke.Keys;
+import org.b3log.latke.logging.Logger;
+import org.b3log.latke.model.User;
+import org.b3log.latke.servlet.HTTPRequestContext;
+import org.b3log.latke.servlet.HTTPRequestMethod;
+import org.b3log.latke.servlet.annotation.Before;
+import org.b3log.latke.servlet.annotation.RequestProcessing;
+import org.b3log.latke.servlet.annotation.RequestProcessor;
+import org.b3log.latke.servlet.renderer.JSONRenderer;
+import org.b3log.latke.util.Requests;
+import org.b3log.symphony.model.Follow;
+import org.b3log.symphony.processor.advice.LoginCheck;
+import org.b3log.symphony.service.FollowMgmtService;
+import org.b3log.symphony.util.QueryResults;
+import org.json.JSONObject;
+
+/**
+ * Follow processor.
+ *
+ *
+ * - Follows a user (/follow/user), POST
+ * - Unfollows a user (/follow/user), DELETE
+ * - Follows a tag (/follow/tag), POST
+ * - Unfollows a tag (/follow/tag), DELETE
+ *
+ *
+ * @author Liang Ding
+ * @version 1.0.0.0, Nov 11, 2013
+ * @since 0.2.5
+ */
+@RequestProcessor
+public class FollowProcessor {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOGGER = Logger.getLogger(FollowProcessor.class.getName());
+
+ /**
+ * Follow management service.
+ */
+ @Inject
+ private FollowMgmtService followMgmtService;
+
+ /**
+ * Follows a user.
+ *
+ *
+ * The request json object:
+ *
+ * {
+ * "followingId": ""
+ * }
+ *
+ *
+ *
+ * @param context the specified context
+ * @param request the specified request
+ * @param response the specified response
+ * @throws Exception exception
+ */
+ @RequestProcessing(value = "/follow/user", method = HTTPRequestMethod.POST)
+ @Before(adviceClass = LoginCheck.class)
+ public void followUser(final HTTPRequestContext context, final HttpServletRequest request,
+ final HttpServletResponse response) throws Exception {
+ final JSONRenderer renderer = new JSONRenderer();
+ context.setRenderer(renderer);
+
+ final JSONObject ret = QueryResults.falseResult();
+ renderer.setJSONObject(ret);
+
+ final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse());
+ final String followingUserId = requestJSONObject.optString(Follow.FOLLOWING_ID);
+
+ final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER);
+ final String followerUserId = currentUser.optString(Keys.OBJECT_ID);
+
+ followMgmtService.followUser(followerUserId, followingUserId);
+ }
+
+ /**
+ * Unfollows a user.
+ *
+ *
+ * The request json object:
+ *
+ * {
+ * "followingId": ""
+ * }
+ *
+ *
+ *
+ * @param context the specified context
+ * @param request the specified request
+ * @param response the specified response
+ * @throws Exception exception
+ */
+ @RequestProcessing(value = "/follow/user", method = HTTPRequestMethod.DELETE)
+ @Before(adviceClass = LoginCheck.class)
+ public void unfollowUser(final HTTPRequestContext context, final HttpServletRequest request,
+ final HttpServletResponse response) throws Exception {
+ final JSONRenderer renderer = new JSONRenderer();
+ context.setRenderer(renderer);
+
+ final JSONObject ret = QueryResults.falseResult();
+ renderer.setJSONObject(ret);
+
+ final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse());
+ final String followingUserId = requestJSONObject.optString(Follow.FOLLOWING_ID);
+
+ final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER);
+ final String followerUserId = currentUser.optString(Keys.OBJECT_ID);
+
+ followMgmtService.removeFollow(followerUserId, followingUserId);
+ }
+
+ /**
+ * Follows a tag.
+ *
+ *
+ * The request json object:
+ *
+ * {
+ * "followingId": ""
+ * }
+ *
+ *
+ *
+ * @param context the specified context
+ * @param request the specified request
+ * @param response the specified response
+ * @throws Exception exception
+ */
+ @RequestProcessing(value = "/follow/tag", method = HTTPRequestMethod.POST)
+ @Before(adviceClass = LoginCheck.class)
+ public void followTag(final HTTPRequestContext context, final HttpServletRequest request,
+ final HttpServletResponse response) throws Exception {
+ final JSONRenderer renderer = new JSONRenderer();
+ context.setRenderer(renderer);
+
+ final JSONObject ret = QueryResults.falseResult();
+ renderer.setJSONObject(ret);
+
+ final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse());
+ final String followingTagId = requestJSONObject.optString(Follow.FOLLOWING_ID);
+
+ final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER);
+ final String followerUserId = currentUser.optString(Keys.OBJECT_ID);
+
+ followMgmtService.followTag(followerUserId, followingTagId);
+ }
+
+ /**
+ * Unfollows a tag.
+ *
+ *
+ * The request json object:
+ *
+ * {
+ * "followingId": ""
+ * }
+ *
+ *
+ *
+ * @param context the specified context
+ * @param request the specified request
+ * @param response the specified response
+ * @throws Exception exception
+ */
+ @RequestProcessing(value = "/follow/tag", method = HTTPRequestMethod.DELETE)
+ @Before(adviceClass = LoginCheck.class)
+ public void unfollowTag(final HTTPRequestContext context, final HttpServletRequest request,
+ final HttpServletResponse response) throws Exception {
+ final JSONRenderer renderer = new JSONRenderer();
+ context.setRenderer(renderer);
+
+ final JSONObject ret = QueryResults.falseResult();
+ renderer.setJSONObject(ret);
+
+ final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, context.getResponse());
+ final String followingTagId = requestJSONObject.optString(Follow.FOLLOWING_ID);
+
+ final JSONObject currentUser = (JSONObject) request.getAttribute(User.USER);
+ final String followerUserId = currentUser.optString(Keys.OBJECT_ID);
+
+ followMgmtService.removeFollow(followerUserId, followingTagId);
+ }
+}
diff --git a/src/main/java/org/b3log/symphony/processor/NotificationProcessor.java b/src/main/java/org/b3log/symphony/processor/NotificationProcessor.java
index 7c28f3449..97ff1890a 100644
--- a/src/main/java/org/b3log/symphony/processor/NotificationProcessor.java
+++ b/src/main/java/org/b3log/symphony/processor/NotificationProcessor.java
@@ -43,13 +43,15 @@
/**
* Notification processor.
- *
- *
- * - Displays comments of an article (/notifications/commented), GET
- *
+ *
+ *
+ * - Displays comments of my articles (/notifications/commented), GET
+ * - Displays at me (/notifications/at), GET
+ * - Displays following user's articles (/notifications/following-user), GET
+ *
*
* @author Liang Ding
- * @version 1.0.0.0, Sep 1, 2013
+ * @version 1.0.0.1, Nov 11, 2013
* @since 0.2.5
*/
@RequestProcessor
@@ -100,7 +102,7 @@ public class NotificationProcessor {
*/
@RequestProcessing(value = "/notifications/commented", method = HTTPRequestMethod.GET)
public void showCommentedNotifications(final HTTPRequestContext context, final HttpServletRequest request,
- final HttpServletResponse response) throws Exception {
+ final HttpServletResponse response) throws Exception {
final JSONObject currentUser = userQueryService.getCurrentUser(request);
if (null == currentUser) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
@@ -128,19 +130,18 @@ public void showCommentedNotifications(final HTTPRequestContext context, final H
final JSONObject result = notificationQueryService.getCommentedNotifications(userId, pageNum, pageSize);
@SuppressWarnings("unchecked")
final List commentedNotifications = (List) result.get(Keys.RESULTS);
-
dataModel.put(Common.COMMENTED_NOTIFICATIONS, commentedNotifications);
-
- final int unreadCommentedNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENTED);
+
+ final int unreadCommentedNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENTED);
dataModel.put(Common.UNREAD_COMMENTED_NOTIFICATION_CNT, unreadCommentedNotificationCnt);
- final int unreadAtNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_AT);
+ final int unreadAtNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_AT);
dataModel.put(Common.UNREAD_AT_NOTIFICATION_CNT, unreadAtNotificationCnt);
- final int unreadCommentNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENT);
- final int unreadArticleNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_ARTICLE);
+
+ final int unreadFollowingUserNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_FOLLOWING_USER);
+ dataModel.put(Common.UNREAD_FOLLOWING_USER_NOTIFICATION_CNT, unreadFollowingUserNotificationCnt);
notificationMgmtService.makeRead(commentedNotifications);
@@ -171,7 +172,7 @@ public void showCommentedNotifications(final HTTPRequestContext context, final H
*/
@RequestProcessing(value = "/notifications/at", method = HTTPRequestMethod.GET)
public void showAtNotifications(final HTTPRequestContext context, final HttpServletRequest request,
- final HttpServletResponse response) throws Exception {
+ final HttpServletResponse response) throws Exception {
final JSONObject currentUser = userQueryService.getCurrentUser(request);
if (null == currentUser) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
@@ -202,16 +203,16 @@ public void showAtNotifications(final HTTPRequestContext context, final HttpServ
dataModel.put(Common.AT_NOTIFICATIONS, atNotifications);
- final int unreadCommentedNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENTED);
+ final int unreadCommentedNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENTED);
dataModel.put(Common.UNREAD_COMMENTED_NOTIFICATION_CNT, unreadCommentedNotificationCnt);
- final int unreadAtNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_AT);
+ final int unreadAtNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_AT);
dataModel.put(Common.UNREAD_AT_NOTIFICATION_CNT, unreadAtNotificationCnt);
- final int unreadCommentNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENT);
- final int unreadArticleNotificationCnt =
- notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_ARTICLE);
+
+ final int unreadFollowingUserNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_FOLLOWING_USER);
+ dataModel.put(Common.UNREAD_FOLLOWING_USER_NOTIFICATION_CNT, unreadFollowingUserNotificationCnt);
notificationMgmtService.makeRead(atNotifications);
@@ -228,6 +229,78 @@ public void showAtNotifications(final HTTPRequestContext context, final HttpServ
dataModel.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
dataModel.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
+ filler.fillHeader(request, response, dataModel);
+ filler.fillFooter(dataModel);
+ }
+
+ /**
+ * Shows [followingUser] notifications.
+ *
+ * @param context the specified context
+ * @param request the specified request
+ * @param response the specified response
+ * @throws Exception exception
+ */
+ @RequestProcessing(value = "/notifications/following-user", method = HTTPRequestMethod.GET)
+ public void showFollowingUserNotifications(final HTTPRequestContext context, final HttpServletRequest request,
+ final HttpServletResponse response) throws Exception {
+ final JSONObject currentUser = userQueryService.getCurrentUser(request);
+ if (null == currentUser) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+
+ return;
+ }
+
+ final AbstractFreeMarkerRenderer renderer = new FreeMarkerRenderer();
+ context.setRenderer(renderer);
+ renderer.setTemplateName("/home/notifications/following-user.ftl");
+ final Map dataModel = renderer.getDataModel();
+
+ final String userId = currentUser.optString(Keys.OBJECT_ID);
+
+ String pageNumStr = request.getParameter("p");
+ if (Strings.isEmptyOrNull(pageNumStr) || !Strings.isNumeric(pageNumStr)) {
+ pageNumStr = "1";
+ }
+
+ final int pageNum = Integer.valueOf(pageNumStr);
+
+ final int pageSize = Symphonys.getInt("followingUserNotificationsCnt");
+ final int windowSize = Symphonys.getInt("followingUserNotificationsWindowSize");
+
+ // TODO: notificationQueryService.getFollowingUserNotifications
+ final JSONObject result = notificationQueryService.getAtNotifications(userId, pageNum, pageSize);
+ @SuppressWarnings("unchecked")
+ final List followingUserNotifications = (List) result.get(Keys.RESULTS);
+
+ dataModel.put(Common.FOLLOWING_USER_NOTIFICATIONS, followingUserNotifications);
+
+ final int unreadCommentedNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_COMMENTED);
+ dataModel.put(Common.UNREAD_COMMENTED_NOTIFICATION_CNT, unreadCommentedNotificationCnt);
+ final int unreadAtNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_AT);
+ dataModel.put(Common.UNREAD_AT_NOTIFICATION_CNT, unreadAtNotificationCnt);
+
+ final int unreadFollowingUserNotificationCnt
+ = notificationQueryService.getUnreadNotificationCountByType(userId, Notification.DATA_TYPE_C_FOLLOWING_USER);
+ dataModel.put(Common.UNREAD_FOLLOWING_USER_NOTIFICATION_CNT, unreadFollowingUserNotificationCnt);
+
+ notificationMgmtService.makeRead(followingUserNotifications);
+
+ final int recordCnt = result.getInt(Pagination.PAGINATION_RECORD_COUNT);
+ final int pageCount = (int) Math.ceil((double) recordCnt / (double) pageSize);
+
+ final List pageNums = Paginator.paginate(pageNum, pageSize, pageCount, windowSize);
+ if (!pageNums.isEmpty()) {
+ dataModel.put(Pagination.PAGINATION_FIRST_PAGE_NUM, pageNums.get(0));
+ dataModel.put(Pagination.PAGINATION_LAST_PAGE_NUM, pageNums.get(pageNums.size() - 1));
+ }
+
+ dataModel.put(Pagination.PAGINATION_CURRENT_PAGE_NUM, pageNum);
+ dataModel.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
+ dataModel.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
+
filler.fillHeader(request, response, dataModel);
filler.fillFooter(dataModel);
}
diff --git a/src/main/java/org/b3log/symphony/processor/advice/LoginCheck.java b/src/main/java/org/b3log/symphony/processor/advice/LoginCheck.java
new file mode 100644
index 000000000..72a85c502
--- /dev/null
+++ b/src/main/java/org/b3log/symphony/processor/advice/LoginCheck.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.b3log.symphony.processor.advice;
+
+import java.util.Map;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.b3log.latke.Keys;
+import org.b3log.latke.logging.Logger;
+import org.b3log.latke.logging.Level;
+import org.b3log.latke.model.User;
+import org.b3log.latke.servlet.HTTPRequestContext;
+import org.b3log.latke.servlet.advice.BeforeRequestProcessAdvice;
+import org.b3log.latke.servlet.advice.RequestProcessAdviceException;
+import org.b3log.symphony.service.UserQueryService;
+import org.json.JSONObject;
+
+/**
+ * Login check, Gets user from request attribute named "user" if logged in.
+ *
+ * @author Liang Ding
+ * @version 1.0.0.0, Nov 11, 2013
+ * @since 0.2.5
+ */
+@Named
+@Singleton
+public class LoginCheck extends BeforeRequestProcessAdvice {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOGGER = Logger.getLogger(LoginCheck.class.getName());
+
+ /**
+ * User query service.
+ */
+ @Inject
+ private UserQueryService userQueryService;
+
+ @Override
+ public void doAdvice(final HTTPRequestContext context, final Map args) throws RequestProcessAdviceException {
+ final HttpServletRequest request = context.getRequest();
+
+ final JSONObject exception = new JSONObject();
+ exception.put(Keys.MSG, HttpServletResponse.SC_FORBIDDEN);
+
+ try {
+ final JSONObject currentUser = userQueryService.getCurrentUser(request);
+ if (null == currentUser) {
+ throw new RequestProcessAdviceException(exception);
+ }
+
+ request.setAttribute(User.USER, currentUser);
+ } catch (final Exception e) {
+ LOGGER.log(Level.ERROR, "Login check failed", e);
+
+ throw new RequestProcessAdviceException(exception);
+ }
+ }
+}
diff --git a/src/main/java/org/b3log/symphony/service/FollowQueryService.java b/src/main/java/org/b3log/symphony/service/FollowQueryService.java
index bc4194160..a077d78a3 100644
--- a/src/main/java/org/b3log/symphony/service/FollowQueryService.java
+++ b/src/main/java/org/b3log/symphony/service/FollowQueryService.java
@@ -41,7 +41,7 @@
* Follow query service.
*
* @author Liang Ding
- * @version 1.0.0.0, Aug 28, 2013
+ * @version 1.0.0.1, Nov 11, 2013
* @since 0.2.5
*/
@Service
@@ -60,7 +60,7 @@ public class FollowQueryService {
/**
* Gets following tags of the specified follower.
- *
+ *
* @param followerId the specified follower id
* @param currentPageNum the specified page number
* @param pageSize the specified page size
@@ -80,7 +80,7 @@ public List getFollowingTags(final String followerId, final int curr
/**
* Gets following users of the specified follower.
- *
+ *
* @param followerId the specified follower id
* @param currentPageNum the specified page number
* @param pageSize the specified page size
@@ -99,14 +99,34 @@ public List getFollowingUsers(final String followerId, final int cur
}
/**
- * Gets the followings of a follower specified by the given follower id and follow type.
- *
+ * Gets follower users of the specified following user.
+ *
+ * @param followingUserId the specified following user id
+ * @param currentPageNum the specified page number
+ * @param pageSize the specified page size
+ * @return follower users, returns an empty list if not found
+ * @throws ServiceException service exception
+ */
+ public List getFollowerUsers(final String followingUserId, final int currentPageNum, final int pageSize)
+ throws ServiceException {
+ try {
+ return getFollowers(followingUserId, pageSize, currentPageNum, Follow.FOLLOWING_TYPE_C_USER);
+ } catch (final RepositoryException e) {
+ LOGGER.log(Level.ERROR, "Gets follower users of following user[id=" + followingUserId + "] failed", e);
+
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * Gets the followings of a follower specified by the given follower id and following type.
+ *
* @param followerId the given follower id
* @param followingType the specified following type
* @param currentPageNum the specified current page number
* @param pageSize the specified page size
* @return followings, returns an empty list if not found
- * @throws RepositoryException
+ * @throws RepositoryException repository exception
*/
private List getFollowings(final String followerId, final int followingType, final int currentPageNum, final int pageSize)
throws RepositoryException {
@@ -122,4 +142,29 @@ private List getFollowings(final String followerId, final int follow
return CollectionUtils.jsonArrayToList(result.optJSONArray(Keys.RESULTS));
}
+
+ /**
+ * Gets the followers of a following specified by the given following id and follow type.
+ *
+ * @param followingId the given following id
+ * @param followingType the specified following type
+ * @param currentPageNum the specified current page number
+ * @param pageSize the specified page size
+ * @return followers, returns an empty list if not found
+ * @throws RepositoryException repository exception
+ */
+ private List getFollowers(final String followingId, final int followingType, final int currentPageNum, final int pageSize)
+ throws RepositoryException {
+ final List filters = new ArrayList();
+ filters.add(new PropertyFilter(Follow.FOLLOWING_ID, FilterOperator.EQUAL, followingId));
+ filters.add(new PropertyFilter(Follow.FOLLOWING_TYPE, FilterOperator.EQUAL, followingType));
+
+ final Query query = new Query().addSort(Keys.OBJECT_ID, SortDirection.DESCENDING).
+ setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters))
+ .setPageSize(pageSize).setCurrentPageNum(currentPageNum);
+
+ final JSONObject result = followRepository.get(query);
+
+ return CollectionUtils.jsonArrayToList(result.optJSONArray(Keys.RESULTS));
+ }
}
diff --git a/src/main/java/org/b3log/symphony/service/NotificationMgmtService.java b/src/main/java/org/b3log/symphony/service/NotificationMgmtService.java
index 50e865732..e0d0f2b79 100644
--- a/src/main/java/org/b3log/symphony/service/NotificationMgmtService.java
+++ b/src/main/java/org/b3log/symphony/service/NotificationMgmtService.java
@@ -168,6 +168,32 @@ public void addArticleNotification(final JSONObject requestJSONObject) throws Se
throw new ServiceException(msg);
}
}
+
+ /**
+ * Adds a 'followingUser' type notification with the specified request json object.
+ *
+ * @param requestJSONObject the specified request json object, for example,
+ *
+ * {
+ * "userId"; "",
+ * "dataId": ""
+ * }
+ *
+ * @throws ServiceException
+ */
+ @Transactional
+ public void addFollowingUserNotification(final JSONObject requestJSONObject) throws ServiceException {
+ try {
+ requestJSONObject.put(Notification.NOTIFICATION_DATA_TYPE, Notification.DATA_TYPE_C_FOLLOWING_USER);
+
+ addNotification(requestJSONObject);
+ } catch (final RepositoryException e) {
+ final String msg = "Adds notification [type=followingUser] failed";
+ LOGGER.log(Level.ERROR, msg, e);
+
+ throw new ServiceException(msg);
+ }
+ }
/**
* Adds a 'commented' type notification with the specified request json object.
diff --git a/src/main/resources/repository.json b/src/main/resources/repository.json
index 48c7f593a..66e57b48c 100644
--- a/src/main/resources/repository.json
+++ b/src/main/resources/repository.json
@@ -1,6 +1,6 @@
{
"description": "Description of repository structures, for generation (DDL: http://en.wikipedia.org/wiki/Data_Definition_Language) of the relational database table and persistence validation.",
- "version": "1.0.1.9, Aug 28, 2013",
+ "version": "1.0.2.0, Nov 11, 2013",
"authors": ["Liang Ding"],
"since": "0.2.0",
"repositories": [
@@ -25,7 +25,7 @@
{
"name": "dataType",
"type": "int",
- "description": "0: article, 1: comment, 2: at, 3: commented"
+ "description": "0: article, 1: comment, 2: at, 3: commented, 4: followingUseer"
},
{
"name": "hasRead",
diff --git a/src/main/resources/symphony.properties b/src/main/resources/symphony.properties
index dd75e53db..a565933df 100644
--- a/src/main/resources/symphony.properties
+++ b/src/main/resources/symphony.properties
@@ -16,7 +16,7 @@
#
# Description: B3log Symphony configurations.
-# Version: 1.0.0.12, Oct 11, 2013
+# Version: 1.0.1.0, Nov 11, 2013
# Author: Liang Ding
#
@@ -47,6 +47,8 @@ atNotificationsCnt=10
atNotificationsWindowSize=10
commentedNotificationsCnt=10
commentedNotificationsWindowSize=10
+followingUserNotificationsCnt=10
+followingUserNotificationsWindowSize=10
### Article Comment ###
articleCommentsPageSize=30
articleCommentsWindowSize=5