aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--juick-common/src/main/java/com/juick/service/SubscriptionService.java2
-rw-r--r--juick-common/src/main/java/com/juick/util/MessageUtils.java13
-rw-r--r--juick-common/src/test/java/com/juick/MessageTest.java10
-rw-r--r--juick-server/src/main/java/com/juick/server/CommandsManager.java2
-rw-r--r--juick-server/src/main/java/com/juick/server/EmailManager.java6
-rw-r--r--juick-server/src/main/java/com/juick/server/XMPPConnection.java2
-rw-r--r--juick-server/src/main/java/com/juick/server/api/Notifications.java2
-rw-r--r--juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java26
-rw-r--r--juick-server/src/test/java/com/juick/server/tests/ServerTests.java41
9 files changed, 80 insertions, 24 deletions
diff --git a/juick-common/src/main/java/com/juick/service/SubscriptionService.java b/juick-common/src/main/java/com/juick/service/SubscriptionService.java
index 8132ec10..98ea59e0 100644
--- a/juick-common/src/main/java/com/juick/service/SubscriptionService.java
+++ b/juick-common/src/main/java/com/juick/service/SubscriptionService.java
@@ -30,7 +30,7 @@ import java.util.List;
public interface SubscriptionService {
List<String> getJIDSubscribedToUser(int uid, boolean friendsonly);
- List<User> getSubscribedUsers(int uid, int mid);
+ List<User> getSubscribedUsers(int uid, Message msg);
List<User> getUsersSubscribedToComments(Message msg, Message reply);
diff --git a/juick-common/src/main/java/com/juick/util/MessageUtils.java b/juick-common/src/main/java/com/juick/util/MessageUtils.java
index bac24507..4de68cb9 100644
--- a/juick-common/src/main/java/com/juick/util/MessageUtils.java
+++ b/juick-common/src/main/java/com/juick/util/MessageUtils.java
@@ -68,6 +68,9 @@ public class MessageUtils {
private final static String replyNumberRegex = "((?<=\\s)|(?<=\\A))\\/(\\d+)((?=\\s)|(?=\\Z)|(?=\\p{Punct}))";
+ private final static String usernameRegex = "((?<=\\s)|(?<=\\A))@([\\w\\-]{2,16})((?=\\s)|(?=\\Z)|(?=\\p{Punct}))";
+ private final static Pattern usernamePattern = Pattern.compile(usernameRegex);
+
public static String formatMessageCode(String msg) {
msg = msg.replaceAll("&", "&amp;");
msg = msg.replaceAll("<", "&lt;");
@@ -139,7 +142,7 @@ public class MessageUtils {
// @username
// <a href="http://juick.com/username/">@username</a>
- msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-]{2,16})((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<a href=\"https://juick.com/$2/\">@$2</a>$3");
+ msg = msg.replaceAll(usernameRegex, "$1<a href=\"https://juick.com/$2/\">@$2</a>$3");
// (http://juick.com/last?page=2)
// (<a href="http://juick.com/last?page=2" rel="nofollow">juick.com</a>)
@@ -301,4 +304,12 @@ public class MessageUtils {
}
return input;
}
+ public static List<String> getMentions(Message msg) {
+ Matcher usernameMatcher = usernamePattern.matcher(msg.getText());
+ List<String> result = new ArrayList<>();
+ while (usernameMatcher.find()) {
+ result.add(usernameMatcher.group());
+ }
+ return result;
+ }
}
diff --git a/juick-common/src/test/java/com/juick/MessageTest.java b/juick-common/src/test/java/com/juick/MessageTest.java
index aaa66af2..d9c83b84 100644
--- a/juick-common/src/test/java/com/juick/MessageTest.java
+++ b/juick-common/src/test/java/com/juick/MessageTest.java
@@ -22,6 +22,8 @@ import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
+import java.util.List;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
@@ -168,4 +170,12 @@ public class MessageTest {
String msg = "[te](http://juick.com/)[st](http://juick.com/)";
assertThat(MessageUtils.stripNonSafeUrls(msg), is(msg));
}
+ @Test
+ public void mentionsCount() {
+ Message msg = new Message();
+ msg.setText("@ugnich go home");
+ List<String> mentions = MessageUtils.getMentions(msg);
+ assertThat(mentions.size(), is(1));
+ assertThat(mentions.get(0), is("@ugnich"));
+ }
}
diff --git a/juick-server/src/main/java/com/juick/server/CommandsManager.java b/juick-server/src/main/java/com/juick/server/CommandsManager.java
index 53b93d4c..e9cf11de 100644
--- a/juick-server/src/main/java/com/juick/server/CommandsManager.java
+++ b/juick-server/src/main/java/com/juick/server/CommandsManager.java
@@ -123,7 +123,7 @@ public class CommandsManager {
subscriptionService.subscribeMessage(msg, user);
applicationEventPublisher.publishEvent(new MessageReadEvent(this, Collections.singletonList(user), msg));
- applicationEventPublisher.publishEvent(new MessageEvent(this, msg, subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg.getMid())));
+ applicationEventPublisher.publishEvent(new MessageEvent(this, msg, subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg)));
return CommandResult.build(msg, "New message posted.\n#" + msg.getMid() + " https://juick.com/m/" + msg.getMid(), String.format("[New message](%s) posted", PlainTextFormatter.formatUrl(msg)));
}
diff --git a/juick-server/src/main/java/com/juick/server/EmailManager.java b/juick-server/src/main/java/com/juick/server/EmailManager.java
index 0acabeff..2be21127 100644
--- a/juick-server/src/main/java/com/juick/server/EmailManager.java
+++ b/juick-server/src/main/java/com/juick/server/EmailManager.java
@@ -83,12 +83,12 @@ public class EmailManager implements ApplicationListener<MessageEvent> {
headers.put("In-Reply-To", String.format("<%d.%d@juick.com>", original.getMid(), original.getRid()));
}
}
- String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user " +
- ", discussion or tag. Reply to this email directly or view it on Juick: %s.",
+ String plainText = String.format("%s\n\n--\nYou are receiving this because you are subscribed to this user," +
+ " discussion, tag or mentioned. Reply to this email directly or view it on Juick: %s.",
formatPost(msg), formatUrl(msg));
String hash = userService.getHashByUID(userService.getUserByEmail(email).getUid());
String htmlText = String.format("%s<br /><br />--<br />You are receiving this because you are subscribed to this user" +
- ", discussion or tag. Reply to this email directly or <a href=\"%s\"><img src=\"https://api.juick.com/thread/mark_read/%d-%d.gif?hash=%s\" />view it</a> on Juick." +
+ ", discussion, tag or mentioned. Reply to this email directly or <a href=\"%s\"><img src=\"https://api.juick.com/thread/mark_read/%d-%d.gif?hash=%s\" />view it</a> on Juick." +
"<br /><a href=\"https://juick.com/settings?hash=%s\">Configure or disable notifications</a>",
MessageUtils.formatHtml(msg), formatUrl(msg),
msg.getMid(), msg.getRid(), hash, hash);
diff --git a/juick-server/src/main/java/com/juick/server/XMPPConnection.java b/juick-server/src/main/java/com/juick/server/XMPPConnection.java
index ba155fe7..fdbb5fe6 100644
--- a/juick-server/src/main/java/com/juick/server/XMPPConnection.java
+++ b/juick-server/src/main/java/com/juick/server/XMPPConnection.java
@@ -586,7 +586,7 @@ public class XMPPConnection implements StanzaListener, NotificationListener {
subscriptionService.getUsersSubscribedToComments(original, reply)));
} else if (!MessageUtils.isPM(jmsg)) {
applicationEventPublisher.publishEvent(new MessageEvent(this,
- messagesService.getMessage(jmsg.getMid()), subscriptionService.getSubscribedUsers(jmsg.getUser().getUid(), jmsg.getMid())));
+ messagesService.getMessage(jmsg.getMid()), subscriptionService.getSubscribedUsers(jmsg.getUser().getUid(), jmsg)));
}
} else {
URI attachment = URI.create(StringUtils.EMPTY);
diff --git a/juick-server/src/main/java/com/juick/server/api/Notifications.java b/juick-server/src/main/java/com/juick/server/api/Notifications.java
index b0d64292..67e52851 100644
--- a/juick-server/src/main/java/com/juick/server/api/Notifications.java
+++ b/juick-server/src/main/java/com/juick/server/api/Notifications.java
@@ -89,7 +89,7 @@ public class Notifications {
Message reply = messagesService.getReply(mid, rid);
users = subscriptionService.getUsersSubscribedToComments(op, reply);
} else {
- users = subscriptionService.getSubscribedUsers(msg.getUser().getUid(), mid);
+ users = subscriptionService.getSubscribedUsers(msg.getUser().getUid(), msg);
}
return ResponseEntity.ok(users.stream().map(User::getUid)
diff --git a/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java b/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
index 492fef1c..2032576c 100644
--- a/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
+++ b/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
@@ -21,6 +21,10 @@ import com.juick.Message;
import com.juick.Tag;
import com.juick.User;
import com.juick.model.NotifyOpts;
+import com.juick.util.MessageUtils;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -61,16 +65,20 @@ public class SubscriptionServiceImpl extends BaseJdbcService implements Subscrip
@Transactional(readOnly = true)
@Override
- public List<User> getSubscribedUsers(final int uid, final int mid) {
+ public List<User> getSubscribedUsers(final int uid, final Message msg) {
+ int mid = msg.getMid();
User author = messagesService.getMessageAuthor(mid);
- List<User> userids = userService.getUserReaders(uid);
+ List<User> subscribers = userService.getUserReaders(uid);
+ List<User> mentionedUsers = userService.getUsersByName(MessageUtils.getMentions(msg).stream()
+ .map(u -> u.substring(1)).collect(Collectors.toList()));
+ List<User> users = ListUtils.union(subscribers, mentionedUsers);
List<Integer> tags = tagService.getMessageTagsIDs(mid);
List<String> tagsStr = tagService.getMessageTags(mid).stream().map(t -> t.getTag().getName()).collect(Collectors.toList());
Set<Integer> set = new HashSet<>();
set.addAll(
- userids.stream()
+ users.stream()
.map(User::getUid).filter(u -> Collections.disjoint(tagService.getUserBLTags(u), tagsStr))
.collect(Collectors.toList()));
@@ -99,13 +107,15 @@ public class SubscriptionServiceImpl extends BaseJdbcService implements Subscrip
@Override
public List<User> getUsersSubscribedToComments(@Nonnull final Message msg, @Nonnull final Message reply,
boolean blacklisted) {
- List<Integer> userids = getJdbcTemplate().queryForList(
+ List<User> subscribers = userService.getUsersByID(getJdbcTemplate().queryForList(
"SELECT suser_id FROM subscr_messages WHERE message_id=? AND suser_id!=?",
Integer.class,
- msg.getMid(), reply.getUser().getUid());
-
- if (!userids.isEmpty()) {
- return userService.getUsersByID(userids).stream()
+ msg.getMid(), reply.getUser().getUid()));
+ List<User> mentionedUsers = userService.getUsersByName(MessageUtils.getMentions(reply).stream()
+ .map(u -> u.substring(1)).collect(Collectors.toList()));
+ List<User> users = IteratorUtils.toList(CollectionUtils.union(subscribers, mentionedUsers).iterator());
+ if (!users.isEmpty()) {
+ return users.stream()
.filter(u -> blacklisted || !userService.isReplyToBL(u, reply))
.collect(Collectors.toList());
}
diff --git a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java
index 7e5acf1a..0f483acc 100644
--- a/juick-server/src/test/java/com/juick/server/tests/ServerTests.java
+++ b/juick-server/src/test/java/com/juick/server/tests/ServerTests.java
@@ -251,7 +251,8 @@ public class ServerTests {
Tag yoTag = tagService.getTag("yoyo", true);
assertThat(tagService.getTag("YOYO", false), equalTo(yoTag));
int mid = messagesService.createMessage(ugnich.getUid(), "yo", null, Collections.singletonList(yoTag));
- List<User> subscribers = subscriptionService.getSubscribedUsers(ugnich.getUid(), mid);
+ Message msg = messagesService.getMessage(mid);
+ List<User> subscribers = subscriptionService.getSubscribedUsers(ugnich.getUid(), msg);
telegramService.createTelegramUser(12345, "freefd");
String loginhash = jdbcTemplate.queryForObject("SELECT loginhash FROM telegram where tg_id=?",
@@ -263,13 +264,18 @@ public class ServerTests {
assertThat(subscribers.size(), equalTo(telegramSubscribers.size()));
assertThat(subscribers.get(0).getUid(), equalTo(freefd.getUid()));
tagService.blacklistTag(freefd, yoTag);
- List<User> subscribers2 = subscriptionService.getSubscribedUsers(ugnich.getUid(), mid);
+ List<User> subscribers2 = subscriptionService.getSubscribedUsers(ugnich.getUid(), msg);
assertThat(subscribers2.size(), equalTo(0));
assertThat(telegramService.getTelegramIdentifiers(subscribers2).size(), equalTo(0));
tagService.blacklistTag(freefd, yoTag);
- assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mid).size(), equalTo(1));
+ assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), msg).size(), equalTo(1));
subscriptionService.unSubscribeUser(freefd, ugnich);
- assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mid).size(), equalTo(0));
+ assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), msg).size(), equalTo(0));
+ Message mentionMessage = new Message();
+ mentionMessage.setText("@freefd - dick");
+ assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mentionMessage).size(), equalTo(1));
+ subscriptionService.subscribeUser(freefd, ugnich);
+ assertThat(subscriptionService.getSubscribedUsers(ugnich.getUid(), mentionMessage).size(), equalTo(1));
}
@Test
public void pmTests() {
@@ -725,7 +731,8 @@ public class ServerTests {
CommandResult yoyoMsg = commandsManager.processCommand(user, "*yo", URI.create("http://static.juick.com/settings/facebook.png"));
assertTrue(yoyoMsg.getNewMessage().isPresent());
assertThat(yoyoMsg.getNewMessage().get().getTags().get(0), is(yo));
- int mid = yoyoMsg.getNewMessage().get().getMid();
+ Message msg2 = yoyoMsg.getNewMessage().get();
+ int mid = msg2.getMid();
Timestamp last = jdbcTemplate.queryForObject("SELECT lastmessage FROM users WHERE id=?", Timestamp.class, user.getUid());
assertThat(last.toInstant(), equalTo(yoyoMsg.getNewMessage().get().getTimestamp()));
assertEquals("should be message", true,
@@ -785,7 +792,7 @@ public class ServerTests {
assertEquals("should be blacklisted", "Tag added to your blacklist",
commandsManager.processCommand(readerUser, "BL *there", emptyUri).getText());
assertEquals("number of subscribed users should match", 0,
- subscriptionService.getSubscribedUsers(uid, mid).size());
+ subscriptionService.getSubscribedUsers(uid, msg2).size());
assertEquals("tags should be updated", "Tags are updated",
commandsManager.processCommand(user, "#" + mid + " *there", emptyUri).getText());
assertEquals("number of tags should match", 1,
@@ -795,11 +802,11 @@ public class ServerTests {
assertEquals("should be subscribed", "Subscribed",
commandsManager.processCommand(taggerUser, "S *yo", emptyUri).getText());
assertEquals("number of subscribed users should match", 2,
- subscriptionService.getSubscribedUsers(uid, mid).size());
+ subscriptionService.getSubscribedUsers(uid, msg2).size());
assertEquals("should be unsubscribed", "Unsubscribed from yo",
commandsManager.processCommand(taggerUser, "U *yo", emptyUri).getText());
assertEquals("number of subscribed users should match", 1,
- subscriptionService.getSubscribedUsers(uid, mid).size());
+ subscriptionService.getSubscribedUsers(uid, msg2).size());
assertEquals("number of readers should match", 1,
userService.getUserReaders(uid).size());
String readerFeed = commandsManager.processCommand(readerUser, "#", emptyUri).getText();
@@ -1266,6 +1273,24 @@ public class ServerTests {
assertThat(subscribers.apply(recommenderId, messagesService.getMessage(readerMid)).size(), is(0));
}
@Test
+ public void mentionsInComments() {
+ int posterId = userService.createUser("p", "secret");
+ int commenterId = userService.createUser("cc", "secret");
+ User commenter = userService.getUserByUID(commenterId).get();
+ int mentionerId = userService.createUser("mmm", "secret");
+ User mentioner = userService.getUserByUID(mentionerId).get();
+ int mid = messagesService.createMessage(posterId, "who is dick?", null, null);
+ Message msg = messagesService.getMessage(mid);
+ int rid = messagesService.createReply(mid, 0, commenter,
+ "@mmm is dick", null);
+ Message reply = messagesService.getReply(mid, rid);
+ assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(1));
+ subscriptionService.subscribeUser(mentioner, commenter);
+ assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(1));
+ privacyQueriesService.blacklistUser(mentioner, commenter);
+ assertThat(subscriptionService.getUsersSubscribedToComments(msg, reply).size(), is(0));
+ }
+ @Test
public void xmppStatusApi() throws Exception {
Supplier<XMPPStatus> getStatus = () -> {
try {