From 1f7c9e6c479da315381ba3469b271f9889836b33 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 8 Oct 2021 12:33:20 +0300 Subject: Add message editing and updating interval * 3 days for message deletion * 15 minutes for editing --- .../com/juick/service/MessagesServiceImpl.java | 1045 +++++++++----------- .../java/com/juick/server/tests/ServerTests.java | 12 +- 2 files changed, 485 insertions(+), 572 deletions(-) (limited to 'src') diff --git a/src/main/java/com/juick/service/MessagesServiceImpl.java b/src/main/java/com/juick/service/MessagesServiceImpl.java index eee40512..c2e5d15d 100644 --- a/src/main/java/com/juick/service/MessagesServiceImpl.java +++ b/src/main/java/com/juick/service/MessagesServiceImpl.java @@ -48,6 +48,7 @@ import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; @@ -121,17 +122,16 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ } } - - /** - * @see Java, JDBC and MySQL Types + * @see Java, + * JDBC and MySQL Types */ @Transactional @Override public int createMessage(final int uid, final String txt, final String attachment, final List tags) { SimpleJdbcInsert simpleJdbcInsert = new SimpleJdbcInsert(getJdbcTemplate()).withTableName("messages") - .usingColumns("user_id", "attach", "ts") - .usingGeneratedKeyColumns("message_id"); + .usingColumns("user_id", "attach", "ts").usingGeneratedKeyColumns("message_id"); Map insertMap = new HashMap<>(); insertMap.put("user_id", uid); Instant now = Instant.now(); @@ -142,25 +142,25 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ int mid = simpleJdbcInsert.executeAndReturnKey(insertMap).intValue(); if (mid > 0) { if (CollectionUtils.isNotEmpty(tags)) { - getJdbcTemplate().batchUpdate( - "INSERT INTO messages_tags(message_id, tag_id) VALUES (?, ?)", + getJdbcTemplate().batchUpdate("INSERT INTO messages_tags(message_id, tag_id) VALUES (?, ?)", new BatchPreparedStatementSetter() { - @Override - public void setValues(@Nonnull PreparedStatement ps, int i) throws SQLException { - ps.setInt(1, mid); - ps.setInt(2, tags.get(i).TID); - } - @Override - public int getBatchSize() { - return tags.size(); - } - }); + @Override + public void setValues(@Nonnull PreparedStatement ps, int i) throws SQLException { + ps.setInt(1, mid); + ps.setInt(2, tags.get(i).TID); + } + + @Override + public int getBatchSize() { + return tags.size(); + } + }); } - getJdbcTemplate().update( - "INSERT INTO messages_txt(message_id, txt, updated_at) VALUES (?, ?, ?)", - new Object[]{mid, txt, Timestamp.from(now)}, - new int[]{Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP}); - getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", Timestamp.from(now), Timestamp.from(now), uid); + getJdbcTemplate().update("INSERT INTO messages_txt(message_id, txt, updated_at) VALUES (?, ?, ?)", + new Object[] { mid, txt, Timestamp.from(now) }, + new int[] { Types.INTEGER, Types.VARCHAR, Types.TIMESTAMP }); + getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", Timestamp.from(now), + Timestamp.from(now), uid); } return mid; @@ -173,7 +173,9 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ * @param txt * @param attachment * @return - * @see Java, JDBC and MySQL Types + * @see Java, + * JDBC and MySQL Types */ @Transactional @Override @@ -181,13 +183,13 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ int ridnew = getReplyIDIncrement(mid, user.getUid()); if (ridnew > 0) { Timestamp ts = Timestamp.from(Instant.now()); - getJdbcTemplate().update("INSERT INTO replies(message_id, reply_id, user_id, replyto, attach, txt, ts, updated_at, user_uri) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + getJdbcTemplate().update( + "INSERT INTO replies(message_id, reply_id, user_id, replyto, attach, txt, ts, updated_at, user_uri) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", mid, ridnew, user.getUid(), rid, attachment, txt, ts, ts, user.getUri().toASCIIString()); - getJdbcTemplate().update( - "UPDATE messages SET replies = replies + 1, updated=? WHERE message_id = ?", - ts, mid); + getJdbcTemplate().update("UPDATE messages SET replies = replies + 1, updated=? WHERE message_id = ?", ts, + mid); setLastReadComment(user, mid, ridnew); getJdbcTemplate().update("UPDATE users SET lastmessage=?, last_seen=? where id=?", ts, ts, user.getUid()); } @@ -200,7 +202,8 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ int replyNo; final int readOnly; final int userId; - try (PreparedStatement ps = conn.prepareStatement("SELECT maxreplyid+1, readonly, user_id FROM messages WHERE message_id=? FOR UPDATE")) { + try (PreparedStatement ps = conn.prepareStatement( + "SELECT maxreplyid+1, readonly, user_id FROM messages WHERE message_id=? FOR UPDATE")) { ps.setInt(1, mid); try (ResultSet resultSet = ps.executeQuery()) { if (resultSet.next()) { @@ -208,17 +211,20 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ readOnly = resultSet.getInt(2); userId = resultSet.getInt(3); } else { - throw new IncorrectResultSizeDataAccessException("while getting getReplyIDIncrement, mid=" + mid, 1, 0); + throw new IncorrectResultSizeDataAccessException( + "while getting getReplyIDIncrement, mid=" + mid, 1, 0); } } } // author can reply to his readonly post if (readOnly == 0 || uid == userId) { - try (PreparedStatement ps = conn.prepareStatement("UPDATE messages SET maxreplyid=? WHERE message_id=?")) { + try (PreparedStatement ps = conn + .prepareStatement("UPDATE messages SET maxreplyid=? WHERE message_id=?")) { ps.setInt(1, replyNo); ps.setInt(2, mid); if (ps.executeUpdate() != 1) { - throw new IncorrectResultSizeDataAccessException("Cannot find a message to update: " + mid, 1, 0); + throw new IncorrectResultSizeDataAccessException("Cannot find a message to update: " + mid, 1, + 0); } } } else { @@ -232,9 +238,9 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional void updateRepliesBy(int mid) { - List users = getJdbcTemplate().queryForList("SELECT users.nick FROM replies " + - "INNER JOIN users ON replies.user_id=users.id WHERE replies.message_id=? " + - "GROUP BY replies.user_id ORDER BY COUNT(replies.reply_id) DESC LIMIT 5", String.class, mid); + List users = getJdbcTemplate().queryForList("SELECT users.nick FROM replies " + + "INNER JOIN users ON replies.user_id=users.id WHERE replies.message_id=? " + + "GROUP BY replies.user_id ORDER BY COUNT(replies.reply_id) DESC LIMIT 5", String.class, mid); String result = users.stream().map(u -> "@" + u).collect(Collectors.joining(",")); getJdbcTemplate().update("UPDATE messages_txt SET repliesby=? WHERE message_id=?", result, mid); } @@ -242,18 +248,17 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional @Override public RecommendStatus recommendMessage(final int mid, final int vuid, final String userUri) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", vuid) - .addValue("uri", userUri) - .addValue("like_id", Reaction.LIKE) - .addValue("mid", mid); - int wasDeleted = getNamedParameterJdbcTemplate() - .update("DELETE FROM favorites WHERE user_id=:uid AND message_id=:mid AND like_id=:like_id AND user_uri=:uri", sqlParameterSource); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", vuid) + .addValue("uri", userUri).addValue("like_id", Reaction.LIKE).addValue("mid", mid); + int wasDeleted = getNamedParameterJdbcTemplate().update( + "DELETE FROM favorites WHERE user_id=:uid AND message_id=:mid AND like_id=:like_id AND user_uri=:uri", + sqlParameterSource); if (wasDeleted > 0) { return RecommendStatus.Deleted; } else { - boolean wasAdded = getJdbcTemplate() - .update("INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", vuid, mid,Reaction.LIKE, userUri) == 1; + boolean wasAdded = getJdbcTemplate().update( + "INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", + vuid, mid, Reaction.LIKE, userUri) == 1; if (wasAdded) { return RecommendStatus.Added; } @@ -282,22 +287,23 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional @Override - public RecommendStatus likeMessage(int mid, int vuid, Integer reaction, String userUri) throws IllegalArgumentException { + public RecommendStatus likeMessage(int mid, int vuid, Integer reaction, String userUri) + throws IllegalArgumentException { if (reaction == null) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", vuid) - .addValue("uri", userUri) - .addValue("mid", mid); - boolean wasDeleted = getNamedParameterJdbcTemplate() - .update("DELETE FROM favorites WHERE user_id=:uid AND message_id=:mid AND user_uri=:uri", sqlParameterSource) > 0; + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", vuid) + .addValue("uri", userUri).addValue("mid", mid); + boolean wasDeleted = getNamedParameterJdbcTemplate().update( + "DELETE FROM favorites WHERE user_id=:uid AND message_id=:mid AND user_uri=:uri", + sqlParameterSource) > 0; if (wasDeleted) { return RecommendStatus.Deleted; } else { return RecommendStatus.Error; } } - boolean wasAdded = getJdbcTemplate() - .update("INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", vuid, mid, reaction, userUri) == 1; + boolean wasAdded = getJdbcTemplate().update( + "INSERT INTO favorites(user_id, message_id, ts, like_id, user_uri) VALUES (?, ?, NOW(), ?, ?)", vuid, + mid, reaction, userUri) == 1; if (wasAdded) { return RecommendStatus.Added; } @@ -308,8 +314,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public boolean canViewThread(final int mid, final int uid) { - List list = getJdbcTemplate().query( - "SELECT user_id, privacy FROM messages WHERE message_id = ?", + List list = getJdbcTemplate().query("SELECT user_id, privacy FROM messages WHERE message_id = ?", (rs, rowNum) -> { PrivacyOpts res = new PrivacyOpts(); @@ -317,25 +322,20 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ res.setPrivacy(rs.getInt(2)); return res; - }, - mid); + }, mid); PrivacyOpts privacyOpts = list.isEmpty() ? null : list.get(0); - return privacyOpts == null || - privacyOpts.getPrivacy() >= 0 || - uid == privacyOpts.getUid() || - ((privacyOpts.getPrivacy() == -1 || privacyOpts.getPrivacy() == -2) && - uid > 0 && userService.isInWL(privacyOpts.getUid(), uid)); + return privacyOpts == null || privacyOpts.getPrivacy() >= 0 || uid == privacyOpts.getUid() + || ((privacyOpts.getPrivacy() == -1 || privacyOpts.getPrivacy() == -2) && uid > 0 + && userService.isInWL(privacyOpts.getUid(), uid)); } @Transactional(readOnly = true) @Override public boolean isReadOnly(final int mid) { - List list = getJdbcTemplate().queryForList( - "SELECT readonly FROM messages WHERE message_id = ?", - Integer.class, - mid); + List list = getJdbcTemplate().queryForList("SELECT readonly FROM messages WHERE message_id = ?", + Integer.class, mid); return !list.isEmpty() && list.get(0) == 1; } @@ -344,9 +344,7 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Override public boolean isSubscribed(final int uid, final int mid) { List list = getJdbcTemplate().queryForList( - "SELECT 1 FROM subscr_messages WHERE suser_id = ? AND message_id = ?", - Integer.class, - uid, mid); + "SELECT 1 FROM subscr_messages WHERE suser_id = ? AND message_id = ?", Integer.class, uid, mid); return !list.isEmpty() && list.get(0) == 1; } @@ -354,10 +352,8 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public int getMessagePrivacy(final int mid) { - List list = getJdbcTemplate().queryForList( - "SELECT privacy FROM messages WHERE message_id = ?", - Integer.class, - mid); + List list = getJdbcTemplate().queryForList("SELECT privacy FROM messages WHERE message_id = ?", + Integer.class, mid); return list.isEmpty() ? -4 : list.get(0); } @@ -366,27 +362,21 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Override public Optional getMessage(final int mid) { - List list = getJdbcTemplate().query( - "SELECT messages.message_id as mid, 0 as rid, 0 as replyto, " - + "messages.user_id as uid, users.nick, users.banned as banned, " - + "" - + "messages.ts," - + "messages.readonly, messages.privacy, messages.replies," - + "messages.attach, COUNT(DISTINCT favorites.user_id) as likes, messages.hidden," - + "GROUP_CONCAT(tags.name SEPARATOR ' '), txt.repliesby, txt.txt, '' as q, messages.updated as updated, 0 as to_uid, " - + "NULL as to_name, txt.updated_at, '' as reply_user_uri, '' as to_uri, '' as reply_uri, 0 as html, 0 as unread FROM messages " - + "INNER JOIN users ON messages.user_id = users.id " - + "INNER JOIN messages_txt AS txt " - + "ON messages.message_id = txt.message_id " - + "LEFT JOIN favorites " - + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 " - + "LEFT JOIN messages_tags ON messages_tags.message_id=txt.message_id " - + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id " - + "WHERE messages.message_id = ? AND users.banned = 0 " - + "GROUP BY mid, rid, replyto, uid, nick, banned, messages.ts, readonly, " - + "privacy, replies, attach, repliesby, q, updated_at, reply_user_uri, to_uri, reply_uri, html, unread", - new MessageMapper(), - mid); + List list = getJdbcTemplate().query("SELECT messages.message_id as mid, 0 as rid, 0 as replyto, " + + "messages.user_id as uid, users.nick, users.banned as banned, " + "" + "messages.ts," + + "messages.readonly, messages.privacy, messages.replies," + + "messages.attach, COUNT(DISTINCT favorites.user_id) as likes, messages.hidden," + + "GROUP_CONCAT(tags.name SEPARATOR ' '), txt.repliesby, txt.txt, '' as q, messages.updated as updated, 0 as to_uid, " + + "NULL as to_name, txt.updated_at, '' as reply_user_uri, '' as to_uri, '' as reply_uri, 0 as html, 0 as unread FROM messages " + + "INNER JOIN users ON messages.user_id = users.id " + "INNER JOIN messages_txt AS txt " + + "ON messages.message_id = txt.message_id " + "LEFT JOIN favorites " + + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 " + + "LEFT JOIN messages_tags ON messages_tags.message_id=txt.message_id " + + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id " + + "WHERE messages.message_id = ? AND users.banned = 0 " + + "GROUP BY mid, rid, replyto, uid, nick, banned, messages.ts, readonly, " + + "privacy, replies, attach, repliesby, q, updated_at, reply_user_uri, to_uri, reply_uri, html, unread", + new MessageMapper(), mid); if (!list.isEmpty()) { final Message message = list.get(0); Map> reactionStats = updateReactionsFor(Collections.singletonList(mid)); @@ -400,21 +390,17 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public Message getReply(final int mid, final int rid) { - List list = getJdbcTemplate().query( - "SELECT replies.user_id, users.nick," - + "replies.replyto, replies.ts," - + "replies.attach, replies.txt, IFNULL(q.txt,t.txt) as quote, " - + "COALESCE(q.user_id, m.user_id) AS to_uid, COALESCE(qu.nick, mu.nick) AS to_name, " - + "replies.updated_at, replies.user_uri as uri, " - + "q.user_uri AS to_uri, replies.reply_uri AS reply_uri, replies.html, q.reply_uri " - + "FROM replies LEFT JOIN users ON replies.user_id = users.id " - + "LEFT JOIN replies q ON replies.message_id = q.message_id and replies.replyto = q.reply_id " - + "LEFT JOIN messages_txt t ON replies.message_id = t.message_id " - + "LEFT JOIN messages m ON replies.message_id = m.message_id " - + "LEFT JOIN users qu ON q.user_id=qu.id " - + "LEFT JOIN users mu ON m.user_id=mu.id " - + "WHERE replies.message_id = ? AND replies.reply_id = ?", - (rs, num) -> { + List list = getJdbcTemplate().query("SELECT replies.user_id, users.nick," + + "replies.replyto, replies.ts," + "replies.attach, replies.txt, IFNULL(q.txt,t.txt) as quote, " + + "COALESCE(q.user_id, m.user_id) AS to_uid, COALESCE(qu.nick, mu.nick) AS to_name, " + + "replies.updated_at, replies.user_uri as uri, " + + "q.user_uri AS to_uri, replies.reply_uri AS reply_uri, replies.html, q.reply_uri " + + "FROM replies LEFT JOIN users ON replies.user_id = users.id " + + "LEFT JOIN replies q ON replies.message_id = q.message_id and replies.replyto = q.reply_id " + + "LEFT JOIN messages_txt t ON replies.message_id = t.message_id " + + "LEFT JOIN messages m ON replies.message_id = m.message_id " + + "LEFT JOIN users qu ON q.user_id=qu.id " + "LEFT JOIN users mu ON m.user_id=mu.id " + + "WHERE replies.message_id = ? AND replies.reply_id = ?", (rs, num) -> { Message msg = new Message(); msg.setMid(mid); @@ -424,8 +410,8 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ msg.getUser().setName(rs.getString(2)); if (msg.getUser().getUid() == 0) { msg.getUser().setName(AnonymousUser.INSTANCE.getName()); - msg.getUser().setUri( - URI.create(Optional.ofNullable(rs.getString(11)).orElse(StringUtils.EMPTY))); + msg.getUser() + .setUri(URI.create(Optional.ofNullable(rs.getString(11)).orElse(StringUtils.EMPTY))); } msg.setReplyto(rs.getInt(3)); msg.setCreated(rs.getTimestamp(4).toInstant()); @@ -455,15 +441,15 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ } msg.setEntities(MessageUtils.getEntities(msg)); return msg; - }, - mid, rid); + }, mid, rid); return list.isEmpty() ? null : list.get(0); } @Override public Message getReplyByUri(String replyUri) { - List replies = getJdbcTemplate().query("SELECT message_id, reply_id from replies WHERE reply_uri=?", (rs, rowNum) -> getReply(rs.getInt(1), rs.getInt(2)), replyUri); + List replies = getJdbcTemplate().query("SELECT message_id, reply_id from replies WHERE reply_uri=?", + (rs, rowNum) -> getReply(rs.getInt(1), rs.getInt(2)), replyUri); return replies.isEmpty() ? null : replies.get(0); } @@ -478,26 +464,23 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ res.setUid(rs.getInt(1)); res.setName(rs.getString(2)); return res; - }, - mid); + }, mid); - return list.isEmpty() ? - null : list.get(0); + return list.isEmpty() ? null : list.get(0); } @Transactional(readOnly = true) @Override public List> getMessagesRecommendations(final Collection mids) { return getNamedParameterJdbcTemplate().query( - "SELECT DISTINCT favorites.message_id, users.id, users.nick, favorites.user_uri FROM favorites " + - "INNER JOIN users ON (favorites.user_id = users.id) " + - "INNER JOIN messages m ON favorites.message_id=m.message_id WHERE favorites.like_id=1 " + - "AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " + - "(user_id = favorites.user_id AND bl_user_id = m.user_id) " + - "OR (user_id = m.user_id AND bl_user_id = favorites.user_id)) " + - "AND favorites.message_id IN (:mids)", - new MapSqlParameterSource("mids", mids), - (rs, rowNum) -> { + "SELECT DISTINCT favorites.message_id, users.id, users.nick, favorites.user_uri FROM favorites " + + "INNER JOIN users ON (favorites.user_id = users.id) " + + "INNER JOIN messages m ON favorites.message_id=m.message_id WHERE favorites.like_id=1 " + + "AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " + + "(user_id = favorites.user_id AND bl_user_id = m.user_id) " + + "OR (user_id = m.user_id AND bl_user_id = favorites.user_id)) " + + "AND favorites.message_id IN (:mids)", + new MapSqlParameterSource("mids", mids), (rs, rowNum) -> { User user = new User(); user.setUid(rs.getInt(2)); user.setName(rs.getString(3)); @@ -509,217 +492,163 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public List getAll(final int visitorUid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("before", before) + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("before", before) .addValue("visitorUid", visitorUid); - return getNamedParameterJdbcTemplate().queryForList( - "SELECT m.message_id FROM messages m WHERE " + - (before > 0 ? - " m.message_id < :before AND " : StringUtils.EMPTY) + - " m.hidden = 0 AND (m.privacy > 0" + - (visitorUid > 1 ? - " OR m.user_id = :visitorUid) AND NOT EXISTS (" + - " SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid AND b.bl_user_id = m.user_id)" : - ")") + - " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + - "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :visitorUid = bt.user_id)" + - " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :visitorUid) ORDER BY m.message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate().queryForList("SELECT m.message_id FROM messages m WHERE " + + (before > 0 ? " m.message_id < :before AND " : StringUtils.EMPTY) + " m.hidden = 0 AND (m.privacy > 0" + + (visitorUid > 1 ? " OR m.user_id = :visitorUid) AND NOT EXISTS (" + + " SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid AND b.bl_user_id = m.user_id)" : ")") + + " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + + "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :visitorUid = bt.user_id)" + + " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :visitorUid) ORDER BY m.message_id DESC LIMIT 20", + sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getTag(final int tid, final int visitorUid, final int before, final int cnt) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("tid", tid) - .addValue("cnt", cnt) - .addValue("before", before) - .addValue("visitorUid", visitorUid); - - return getNamedParameterJdbcTemplate().queryForList( - "SELECT messages.message_id FROM (tags INNER JOIN messages_tags " + - "ON ((tags.synonym_id = :tid OR tags.tag_id = :tid) AND tags.tag_id = messages_tags.tag_id)) " + - "INNER JOIN messages ON messages.message_id = messages_tags.message_id WHERE " + - (before > 0 ? - " messages.message_id < :before AND " : StringUtils.EMPTY) + - "(messages.privacy > 0 OR messages.user_id = :visitorUid) " + - "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid and b.bl_user_id = messages.user_id) " + - "ORDER BY messages.message_id DESC LIMIT :cnt", - sqlParameterSource, - Integer.class); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("tid", tid).addValue("cnt", cnt) + .addValue("before", before).addValue("visitorUid", visitorUid); + + return getNamedParameterJdbcTemplate() + .queryForList("SELECT messages.message_id FROM (tags INNER JOIN messages_tags " + + "ON ((tags.synonym_id = :tid OR tags.tag_id = :tid) AND tags.tag_id = messages_tags.tag_id)) " + + "INNER JOIN messages ON messages.message_id = messages_tags.message_id WHERE " + + (before > 0 ? " messages.message_id < :before AND " : StringUtils.EMPTY) + + "(messages.privacy > 0 OR messages.user_id = :visitorUid) " + + "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :visitorUid and b.bl_user_id = messages.user_id) " + + "ORDER BY messages.message_id DESC LIMIT :cnt", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getTags(final String tids, final int visitorUid, final int before, final int cnt) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("cnt", cnt) - .addValue("before", before) - .addValue("visitorUid", visitorUid); - - return getNamedParameterJdbcTemplate().queryForList( - "SELECT messages.message_id FROM messages_tags " + - "INNER JOIN messages USING(message_id) WHERE messages_tags.tag_id IN (" + tids + ") " + - (before > 0 ? - " AND messages.message_id < :before " : StringUtils.EMPTY) + - " AND (messages.privacy > 0 OR messages.user_id = :visitorUid) " + - "ORDER BY messages.message_id DESC LIMIT :cnt", - sqlParameterSource, - Integer.class); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("cnt", cnt) + .addValue("before", before).addValue("visitorUid", visitorUid); + + return getNamedParameterJdbcTemplate().queryForList("SELECT messages.message_id FROM messages_tags " + + "INNER JOIN messages USING(message_id) WHERE messages_tags.tag_id IN (" + tids + ") " + + (before > 0 ? " AND messages.message_id < :before " : StringUtils.EMPTY) + + " AND (messages.privacy > 0 OR messages.user_id = :visitorUid) " + + "ORDER BY messages.message_id DESC LIMIT :cnt", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getPlace(final int placeId, final int visitorUid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("placeId", placeId) - .addValue("before", before) - .addValue("visitorUid", visitorUid); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("placeId", placeId) + .addValue("before", before).addValue("visitorUid", visitorUid); return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM messages WHERE place_id = :placeId " + - (before > 0 ? - " AND message_id < :before " : StringUtils.EMPTY) + - " AND (privacy > 0 OR user_id = :visitorUid) ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + "SELECT message_id FROM messages WHERE place_id = :placeId " + + (before > 0 ? " AND message_id < :before " : StringUtils.EMPTY) + + " AND (privacy > 0 OR user_id = :visitorUid) ORDER BY message_id DESC LIMIT 20", + sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getMyFeed(final int uid, final int before, boolean recommended) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("before", before); - - return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM messages WHERE " + - "(user_id=:uid OR " + - "(EXISTS (SELECT 1 FROM subscr_users WHERE subscr_users.suser_id = :uid " + - "AND subscr_users.user_id = messages.user_id) " + - "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + - "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) AND :uid = bt.user_id) " + - "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " + - "AND EXISTS (SELECT 1 FROM wl_users w WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " + - (recommended ? - "OR (EXISTS (SELECT 1 FROM favorites WHERE favorites.message_id=messages.message_id " + - "AND favorites.user_id IN (SELECT user_id FROM subscr_users WHERE suser_id=:uid)) " + - "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN (SELECT tag_id FROM messages_tags " + - "WHERE message_id = messages.message_id) and :uid = bt.user_id) " + - "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " + - "AND EXISTS (SELECT 1 FROM wl_users w " + - "WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " + - "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and b.bl_user_id = messages.user_id)" : StringUtils.EMPTY) + - ") " + - (before > 0 ? "AND message_id < :before " : StringUtils.EMPTY) + - "ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("before", + before); + + return getNamedParameterJdbcTemplate().queryForList("SELECT message_id FROM messages WHERE " + + "(user_id=:uid OR " + "(EXISTS (SELECT 1 FROM subscr_users WHERE subscr_users.suser_id = :uid " + + "AND subscr_users.user_id = messages.user_id) " + + "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + + "(SELECT tag_id FROM messages_tags WHERE message_id = messages.message_id) AND :uid = bt.user_id) " + + "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " + + "AND EXISTS (SELECT 1 FROM wl_users w WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " + + (recommended ? "OR (EXISTS (SELECT 1 FROM favorites WHERE favorites.message_id=messages.message_id " + + "AND favorites.user_id IN (SELECT user_id FROM subscr_users WHERE suser_id=:uid)) " + + "AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN (SELECT tag_id FROM messages_tags " + + "WHERE message_id = messages.message_id) and :uid = bt.user_id) " + + "AND (privacy >= 0 OR (privacy >= -2 AND privacy <= -1 " + + "AND EXISTS (SELECT 1 FROM wl_users w " + + "WHERE w.wl_user_id = :uid and w.user_id = messages.user_id)))) " + + "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid and b.bl_user_id = messages.user_id)" + : StringUtils.EMPTY) + + ") " + (before > 0 ? "AND message_id < :before " : StringUtils.EMPTY) + + "ORDER BY message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getPrivate(final int uid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("before", before); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("before", + before); - return getNamedParameterJdbcTemplate().queryForList - ("SELECT message_id FROM messages WHERE user_id = :uid AND privacy < 0" + - (before > 0 ? - " AND message_id < :before " : StringUtils.EMPTY) + - "ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate() + .queryForList("SELECT message_id FROM messages WHERE user_id = :uid AND privacy < 0" + + (before > 0 ? " AND message_id < :before " : StringUtils.EMPTY) + + "ORDER BY message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getDiscussions(final int uid, final Long to) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("to", new Timestamp(to)); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("to", + new Timestamp(to)); if (uid == 0) { - return getNamedParameterJdbcTemplate().query("SELECT message_id FROM messages WHERE " + - (to != 0 ? - " updated < :to AND" : StringUtils.EMPTY) + - " NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" + - " AND u.id = messages.user_id and u.id <> :uid) " + - " ORDER BY updated DESC, message_id DESC LIMIT 20", - sqlParameterSource, - (rs, rowNum) -> rs.getInt(1)); + return getNamedParameterJdbcTemplate().query( + "SELECT message_id FROM messages WHERE " + (to != 0 ? " updated < :to AND" : StringUtils.EMPTY) + + " NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" + + " AND u.id = messages.user_id and u.id <> :uid) " + + " ORDER BY updated DESC, message_id DESC LIMIT 20", + sqlParameterSource, (rs, rowNum) -> rs.getInt(1)); } return getNamedParameterJdbcTemplate().query( - "SELECT messages.message_id, messages.updated FROM subscr_messages " + - "INNER JOIN messages ON messages.message_id=subscr_messages.message_id " + - "WHERE suser_id = :uid " + - (to != 0 ? - "AND updated < :to " : StringUtils.EMPTY) + - " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" + - " AND u.id = messages.user_id and u.id <> :uid) " + - "ORDER BY updated DESC, message_id DESC LIMIT 20", - sqlParameterSource, - (rs, rowNum) -> rs.getInt(1)); + "SELECT messages.message_id, messages.updated FROM subscr_messages " + + "INNER JOIN messages ON messages.message_id=subscr_messages.message_id " + + "WHERE suser_id = :uid " + (to != 0 ? "AND updated < :to " : StringUtils.EMPTY) + + " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1" + + " AND u.id = messages.user_id and u.id <> :uid) " + + "ORDER BY updated DESC, message_id DESC LIMIT 20", + sqlParameterSource, (rs, rowNum) -> rs.getInt(1)); } @Transactional(readOnly = true) @Override public List getRecommended(final int uid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("before", before); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("before", + before); - return getNamedParameterJdbcTemplate().queryForList( - "SELECT f.message_id FROM favorites f WHERE " + - "EXISTS (SELECT 1 FROM subscr_users s WHERE s.suser_id = :uid and f.user_id = s.user_id)" + - (before > 0 ? - " AND f.message_id < :before " : StringUtils.EMPTY) + - "ORDER BY f.message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate().queryForList("SELECT f.message_id FROM favorites f WHERE " + + "EXISTS (SELECT 1 FROM subscr_users s WHERE s.suser_id = :uid and f.user_id = s.user_id)" + + (before > 0 ? " AND f.message_id < :before " : StringUtils.EMPTY) + + "ORDER BY f.message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getPopular(final int visitorUid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("vid", visitorUid) + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("vid", visitorUid) .addValue("before", before); - return getNamedParameterJdbcTemplate().queryForList( - "SELECT m.message_id FROM messages m WHERE m.privacy > 0 " + - (before > 0 ? - " AND m.message_id < :before " : StringUtils.EMPTY) + - " AND m.popular > 0 AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " + - " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + - "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" + - " ORDER BY m.message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate().queryForList("SELECT m.message_id FROM messages m WHERE m.privacy > 0 " + + (before > 0 ? " AND m.message_id < :before " : StringUtils.EMPTY) + + " AND m.popular > 0 AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " + + " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + + "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" + + " ORDER BY m.message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getPhotos(final int visitorUid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("vid", visitorUid) + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("vid", visitorUid) .addValue("before", before); - return getNamedParameterJdbcTemplate().queryForList( - "SELECT m.message_id FROM messages m WHERE (m.privacy > 0 OR m.user_id = :vid) " + - (before > 0 ? - " AND m.message_id < :before " : StringUtils.EMPTY) + - " AND m.attach IS NOT NULL " + - " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + - "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" + - " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :vid) " + - " AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " + - " ORDER BY m.message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate() + .queryForList("SELECT m.message_id FROM messages m WHERE (m.privacy > 0 OR m.user_id = :vid) " + + (before > 0 ? " AND m.message_id < :before " : StringUtils.EMPTY) + + " AND m.attach IS NOT NULL " + " AND NOT EXISTS (SELECT 1 FROM bl_tags bt WHERE bt.tag_id IN " + + "(SELECT tag_id FROM messages_tags WHERE message_id = m.message_id) and :vid = bt.user_id)" + + " AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = m.user_id and u.id <> :vid) " + + " AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :vid and b.bl_user_id = m.user_id) " + + " ORDER BY m.message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @@ -731,139 +660,97 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public List getUserBlog(final int uid, final int privacy, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("privacy", privacy) - .addValue("before", before); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid) + .addValue("privacy", privacy).addValue("before", before); return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM messages INNER JOIN users" + - " ON messages.user_id = users.id" + - " WHERE user_id = :uid" + - (before > 0 ? - " AND message_id < :before" : StringUtils.EMPTY) + - " AND privacy >= :privacy AND users.banned = 0 ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + "SELECT message_id FROM messages INNER JOIN users" + " ON messages.user_id = users.id" + + " WHERE user_id = :uid" + (before > 0 ? " AND message_id < :before" : StringUtils.EMPTY) + + " AND privacy >= :privacy AND users.banned = 0 ORDER BY message_id DESC LIMIT 20", + sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getUserTag(final int uid, final int tid, final int privacy, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("tid", tid) - .addValue("privacy", privacy) - .addValue("before", before); - - return getNamedParameterJdbcTemplate().queryForList( - "SELECT messages.message_id FROM messages_tags INNER JOIN messages" + - " ON messages.message_id = messages_tags.message_id" + - " INNER JOIN users" + - " ON messages.user_id=users.id" + - " WHERE messages.user_id = :uid AND messages_tags.tag_id = :tid" + - (before > 0 ? - " AND messages.message_id < :before " : StringUtils.EMPTY) + - " AND messages.privacy >= :privacy AND users.banned = 0" + - " ORDER BY messages.message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("tid", tid) + .addValue("privacy", privacy).addValue("before", before); + + return getNamedParameterJdbcTemplate() + .queryForList("SELECT messages.message_id FROM messages_tags INNER JOIN messages" + + " ON messages.message_id = messages_tags.message_id" + " INNER JOIN users" + + " ON messages.user_id=users.id" + + " WHERE messages.user_id = :uid AND messages_tags.tag_id = :tid" + + (before > 0 ? " AND messages.message_id < :before " : StringUtils.EMPTY) + + " AND messages.privacy >= :privacy AND users.banned = 0" + + " ORDER BY messages.message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getUserBlogAtDay(final int uid, final int privacy, final int daysback) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("privacy", privacy) - .addValue("daysback", daysback); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid) + .addValue("privacy", privacy).addValue("daysback", daysback); return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM messages" + - " INNER JOIN users" + - " ON messages.user_id = users.id" + - " WHERE user_id = :uid" + - (daysback > 0 ? - " AND ts >= date(NOW() - INTERVAL :daysback day)" + - " AND ts < date(NOW() - INTERVAL :daysback day + INTERVAL 1 day)" : StringUtils.EMPTY) + - " AND privacy >= :privacy AND users.banned = 0 ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + "SELECT message_id FROM messages" + " INNER JOIN users" + " ON messages.user_id = users.id" + + " WHERE user_id = :uid" + + (daysback > 0 + ? " AND ts >= date(NOW() - INTERVAL :daysback day)" + + " AND ts < date(NOW() - INTERVAL :daysback day + INTERVAL 1 day)" + : StringUtils.EMPTY) + + " AND privacy >= :privacy AND users.banned = 0 ORDER BY message_id DESC LIMIT 20", + sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getUserBlogWithRecommendations(final int uid, final int privacy, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("privacy", privacy) - .addValue("before", before); - - return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM " + - "(SELECT message_id FROM favorites " + - " INNER JOIN users" + - " ON favorites.user_id = users.id" + - " WHERE user_id = :uid AND users.banned = 0" + - (before > 0 ? - " AND message_id < :before " : StringUtils.EMPTY) + - " ORDER BY message_id DESC LIMIT 20) as r" + - " UNION ALL " + - "SELECT message_id FROM " + - "(SELECT message_id FROM messages" + - " INNER JOIN users" + - " ON messages.user_id = users.id" + - " WHERE user_id = :uid AND users.banned = 0" + - (before > 0 ? - " AND message_id < :before" : StringUtils.EMPTY) + - " AND privacy >= :privacy ORDER BY message_id DESC LIMIT 20) as m " + - "ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid) + .addValue("privacy", privacy).addValue("before", before); + + return getNamedParameterJdbcTemplate() + .queryForList("SELECT message_id FROM " + "(SELECT message_id FROM favorites " + " INNER JOIN users" + + " ON favorites.user_id = users.id" + " WHERE user_id = :uid AND users.banned = 0" + + (before > 0 ? " AND message_id < :before " : StringUtils.EMPTY) + + " ORDER BY message_id DESC LIMIT 20) as r" + " UNION ALL " + "SELECT message_id FROM " + + "(SELECT message_id FROM messages" + " INNER JOIN users" + " ON messages.user_id = users.id" + + " WHERE user_id = :uid AND users.banned = 0" + + (before > 0 ? " AND message_id < :before" : StringUtils.EMPTY) + + " AND privacy >= :privacy ORDER BY message_id DESC LIMIT 20) as m " + + "ORDER BY message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getUserRecommendations(final int uid, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("before", before); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid).addValue("before", + before); - return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM favorites" + - " INNER JOIN users" + - " ON favorites.user_id = users.id" + - " WHERE user_id = :uid AND users.banned = 0 " + - (before > 0 ? - " AND message_id < :before " : StringUtils.EMPTY) + - " ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + return getNamedParameterJdbcTemplate().queryForList("SELECT message_id FROM favorites" + " INNER JOIN users" + + " ON favorites.user_id = users.id" + " WHERE user_id = :uid AND users.banned = 0 " + + (before > 0 ? " AND message_id < :before " : StringUtils.EMPTY) + + " ORDER BY message_id DESC LIMIT 20", sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override public List getUserPhotos(final int uid, final int privacy, final int before) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("uid", uid) - .addValue("privacy", privacy) - .addValue("before", before); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("uid", uid) + .addValue("privacy", privacy).addValue("before", before); return getNamedParameterJdbcTemplate().queryForList( - "SELECT message_id FROM messages" + - " INNER JOIN users" + - " ON messages.user_id = users.id" + - " WHERE user_id = :uid and users.banned = 0" + - (before > 0 ? - " AND message_id < :before " : StringUtils.EMPTY) + - " AND privacy >= :privacy AND attach IS NOT NULL ORDER BY message_id DESC LIMIT 20", - sqlParameterSource, - Integer.class); + "SELECT message_id FROM messages" + " INNER JOIN users" + " ON messages.user_id = users.id" + + " WHERE user_id = :uid and users.banned = 0" + + (before > 0 ? " AND message_id < :before " : StringUtils.EMPTY) + + " AND privacy >= :privacy AND attach IS NOT NULL ORDER BY message_id DESC LIMIT 20", + sqlParameterSource, Integer.class); } @Transactional(readOnly = true) @Override - public List getUserSearch(final User visitor, final int UID, final String search, final int privacy, final int page) { + public List getUserSearch(final User visitor, final int UID, final String search, final int privacy, + final int page) { return searchService.searchByStringAndUser(visitor, search, UID, page); } @@ -872,44 +759,34 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ public List getMessages(final User visitor, final List mids) { if (CollectionUtils.isNotEmpty(mids)) { - List msgs = getNamedParameterJdbcTemplate().query( - "WITH RECURSIVE banned(message_id, reply_id) " - + "AS (SELECT message_id, reply_id FROM replies WHERE replies.message_id IN (:ids) " - + "AND (EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " - + "OR EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)) " - + "UNION ALL SELECT replies.message_id, replies.reply_id FROM replies INNER JOIN banned " - + "ON banned.reply_id = replies.replyto AND replies.reply_id != replies.replyto AND banned.message_id=replies.message_id " - + "WHERE replies.message_id IN (:ids)) " - + "SELECT messages.message_id, 0 as rid, 0 as replyto, " - + "messages.user_id,users.nick, 0 as usr_banned, " - + "messages.ts," - + "messages.readonly,messages.privacy, messages.replies-COUNT(DISTINCT banned.reply_id) as replies," - + "messages.attach,COUNT(DISTINCT favorites.user_id) AS likes,messages.hidden," - + "GROUP_CONCAT(tags.name SEPARATOR ' '), messages_txt.repliesby, messages_txt.txt, '' as q, " - + "messages.updated, 0 as to_uid, NULL as to_name, messages_txt.updated_at, '' as m_user_uri, " - + "'' as to_uri, '' as msg_reply_uri, 0 as html, cast(messages.replies as signed)-cast(subscr_messages.last_read_rid as signed) > 0 as unread " - + "FROM (messages INNER JOIN messages_txt " - + "ON messages.message_id=messages_txt.message_id) " - + "INNER JOIN users ON messages.user_id=users.id " - + "LEFT JOIN subscr_messages " - + "ON messages.message_id=subscr_messages.message_id AND subscr_messages.suser_id=:uid " - + "LEFT JOIN favorites " - + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 " - + "LEFT JOIN banned " - + "ON messages.message_id = banned.message_id " - + "LEFT JOIN messages_tags ON messages_tags.message_id=messages_txt.message_id " - + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id " - + "WHERE messages.message_id IN (:ids) GROUP BY " - + "messages.message_id, rid, replyto, messages.user_id, users.nick, usr_banned, messages.ts, " - + "messages.readonly, messages.privacy, messages.attach, messages.hidden, " - + "messages_txt.repliesby, messages_txt.txt, q, messages.updated, to_uid, to_name, updated_at, " - + "m_user_uri, msg_reply_uri, html", - new MapSqlParameterSource("ids", mids) - .addValue("uid", visitor.getUid()), - new MessageMapper()); - - - Map> likes = updateReactionsFor(mids); + List msgs = getNamedParameterJdbcTemplate().query("WITH RECURSIVE banned(message_id, reply_id) " + + "AS (SELECT message_id, reply_id FROM replies WHERE replies.message_id IN (:ids) " + + "AND (EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " + + "OR EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)) " + + "UNION ALL SELECT replies.message_id, replies.reply_id FROM replies INNER JOIN banned " + + "ON banned.reply_id = replies.replyto AND replies.reply_id != replies.replyto AND banned.message_id=replies.message_id " + + "WHERE replies.message_id IN (:ids)) " + "SELECT messages.message_id, 0 as rid, 0 as replyto, " + + "messages.user_id,users.nick, 0 as usr_banned, " + "messages.ts," + + "messages.readonly,messages.privacy, messages.replies-COUNT(DISTINCT banned.reply_id) as replies," + + "messages.attach,COUNT(DISTINCT favorites.user_id) AS likes,messages.hidden," + + "GROUP_CONCAT(tags.name SEPARATOR ' '), messages_txt.repliesby, messages_txt.txt, '' as q, " + + "messages.updated, 0 as to_uid, NULL as to_name, messages_txt.updated_at, '' as m_user_uri, " + + "'' as to_uri, '' as msg_reply_uri, 0 as html, cast(messages.replies as signed)-cast(subscr_messages.last_read_rid as signed) > 0 as unread " + + "FROM (messages INNER JOIN messages_txt " + "ON messages.message_id=messages_txt.message_id) " + + "INNER JOIN users ON messages.user_id=users.id " + "LEFT JOIN subscr_messages " + + "ON messages.message_id=subscr_messages.message_id AND subscr_messages.suser_id=:uid " + + "LEFT JOIN favorites " + "ON messages.message_id = favorites.message_id AND favorites.like_id=1 " + + "LEFT JOIN banned " + "ON messages.message_id = banned.message_id " + + "LEFT JOIN messages_tags ON messages_tags.message_id=messages_txt.message_id " + + "LEFT JOIN tags ON tags.tag_id=messages_tags.tag_id " + + "WHERE messages.message_id IN (:ids) GROUP BY " + + "messages.message_id, rid, replyto, messages.user_id, users.nick, usr_banned, messages.ts, " + + "messages.readonly, messages.privacy, messages.attach, messages.hidden, " + + "messages_txt.repliesby, messages_txt.txt, q, messages.updated, to_uid, to_name, updated_at, " + + "m_user_uri, msg_reply_uri, html", + new MapSqlParameterSource("ids", mids).addValue("uid", visitor.getUid()), new MessageMapper()); + + Map> likes = updateReactionsFor(mids); msgs.forEach(i -> i.setReactions(likes.get(i.getMid()))); @@ -930,72 +807,59 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ return Collections.emptyList(); } - @Transactional(readOnly = true) @Override - public Map> updateReactionsFor(final List mids) { - - return getNamedParameterJdbcTemplate().query("select f.message_id as mid, f.like_id as lid," + - " r.description as descr, count(f.like_id) as cnt" + - " from favorites f LEFT JOIN reactions r ON f.like_id = r.like_id " + - " where f.message_id IN (:mids) " + - " group by f.message_id, f.like_id", new MapSqlParameterSource("mids", mids), (ResultSet rs) -> { - Map> results = new HashMap<>(); - - - while (rs.next()) { - int messageId = rs.getInt("mid"); - int likeId = rs.getInt("lid"); - int count = rs.getInt("cnt"); - String description = rs.getString("descr"); - Reaction reaction = new Reaction(likeId); - reaction.setCount(count); - reaction.setDescription(description); - results.computeIfAbsent(messageId, HashSet::new); - results.get(messageId).add(reaction); - } + public Map> updateReactionsFor(final List mids) { - return results; - }); + return getNamedParameterJdbcTemplate().query( + "select f.message_id as mid, f.like_id as lid," + " r.description as descr, count(f.like_id) as cnt" + + " from favorites f LEFT JOIN reactions r ON f.like_id = r.like_id " + + " where f.message_id IN (:mids) " + " group by f.message_id, f.like_id", + new MapSqlParameterSource("mids", mids), (ResultSet rs) -> { + Map> results = new HashMap<>(); + + while (rs.next()) { + int messageId = rs.getInt("mid"); + int likeId = rs.getInt("lid"); + int count = rs.getInt("cnt"); + String description = rs.getString("descr"); + Reaction reaction = new Reaction(likeId); + reaction.setCount(count); + reaction.setDescription(description); + results.computeIfAbsent(messageId, HashSet::new); + results.get(messageId).add(reaction); + } - } + return results; + }); + } @Transactional @Override public List getReplies(final User user, final int mid) { - List replies = getNamedParameterJdbcTemplate().query( - "WITH RECURSIVE banned(reply_id, user_id) AS (" + - "SELECT reply_id, user_id FROM replies " + - "WHERE replies.message_id = :mid " + - "AND EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " + - "UNION ALL SELECT replies.reply_id, replies.user_id FROM replies " + - "INNER JOIN banned ON banned.reply_id = replies.replyto " + - "WHERE replies.message_id = :mid) " + - "SELECT replies.message_id as mid, replies.reply_id, replies.replyto, " + - "replies.user_id, users.nick, users.banned, " + - "replies.ts, " + - "0 as readonly, 0 as privacy, 0 as replies, " + - "replies.attach, 0 as likes, 0 as hidden, " + - "NULL as tags, NULL as repliesby, replies.txt, " + - "IFNULL(qw.txt, t.txt) as q, " + - "NOW(), " + - "COALESCE(qw.user_id, m.user_id) as to_uid, COALESCE(qu.nick, mu.nick) as to_name, " + - "replies.updated_at, replies.user_uri as uri, " + - "qw.user_uri as to_uri, replies.reply_uri, replies.html, 0 as unread " + - "FROM replies LEFT JOIN users " + - "ON replies.user_id = users.id " + - "LEFT JOIN replies qw ON replies.message_id = qw.message_id and replies.replyto = qw.reply_id " + - "LEFT JOIN messages_txt t on replies.message_id = t.message_id " + - "LEFT JOIN messages m on replies.message_id = m.message_id " + - "LEFT JOIN users qu ON qw.user_id=qu.id " + - "LEFT JOIN users mu ON m.user_id=mu.id " + - "WHERE replies.message_id = :mid " + - "AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)" + - "AND NOT EXISTS (SELECT 1 FROM banned WHERE banned.reply_id = replies.reply_id) " + - "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = m.user_id) " + - "ORDER BY replies.reply_id ASC", - new MapSqlParameterSource("mid", mid).addValue("uid", user.getUid()), + List replies = getNamedParameterJdbcTemplate().query("WITH RECURSIVE banned(reply_id, user_id) AS (" + + "SELECT reply_id, user_id FROM replies " + "WHERE replies.message_id = :mid " + + "AND EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = replies.user_id) " + + "UNION ALL SELECT replies.reply_id, replies.user_id FROM replies " + + "INNER JOIN banned ON banned.reply_id = replies.replyto " + "WHERE replies.message_id = :mid) " + + "SELECT replies.message_id as mid, replies.reply_id, replies.replyto, " + + "replies.user_id, users.nick, users.banned, " + "replies.ts, " + + "0 as readonly, 0 as privacy, 0 as replies, " + "replies.attach, 0 as likes, 0 as hidden, " + + "NULL as tags, NULL as repliesby, replies.txt, " + "IFNULL(qw.txt, t.txt) as q, " + "NOW(), " + + "COALESCE(qw.user_id, m.user_id) as to_uid, COALESCE(qu.nick, mu.nick) as to_name, " + + "replies.updated_at, replies.user_uri as uri, " + + "qw.user_uri as to_uri, replies.reply_uri, replies.html, 0 as unread " + + "FROM replies LEFT JOIN users " + "ON replies.user_id = users.id " + + "LEFT JOIN replies qw ON replies.message_id = qw.message_id and replies.replyto = qw.reply_id " + + "LEFT JOIN messages_txt t on replies.message_id = t.message_id " + + "LEFT JOIN messages m on replies.message_id = m.message_id " + + "LEFT JOIN users qu ON qw.user_id=qu.id " + "LEFT JOIN users mu ON m.user_id=mu.id " + + "WHERE replies.message_id = :mid " + + "AND NOT EXISTS (SELECT 1 from users u WHERE u.banned = 1 and u.id = replies.user_id and u.id <> :uid)" + + "AND NOT EXISTS (SELECT 1 FROM banned WHERE banned.reply_id = replies.reply_id) " + + "AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.user_id = :uid AND b.bl_user_id = m.user_id) " + + "ORDER BY replies.reply_id ASC", new MapSqlParameterSource("mid", mid).addValue("uid", user.getUid()), new MessageMapper()); if (replies.size() > 0 && !user.isAnonymous()) { setRead(user, mid); @@ -1008,28 +872,24 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Override public boolean setMessagePopular(final int mid, final int popular) { int ret; - MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("mid", mid) - .addValue("popular", popular); + MapSqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("mid", mid).addValue("popular", + popular); switch (popular) { case -2: - ret = getNamedParameterJdbcTemplate().update( - "UPDATE messages SET hidden = 1 WHERE message_id = :mid", + ret = getNamedParameterJdbcTemplate().update("UPDATE messages SET hidden = 1 WHERE message_id = :mid", sqlParameterSource); break; case -1: sqlParameterSource.addValue("popular", 0); default: - ret = getNamedParameterJdbcTemplate().update( - "UPDATE messages SET popular = :popular WHERE message_id = :mid", - sqlParameterSource); + ret = getNamedParameterJdbcTemplate() + .update("UPDATE messages SET popular = :popular WHERE message_id = :mid", sqlParameterSource); break; } if (popular == -1) - ret = getNamedParameterJdbcTemplate().update( - "INSERT INTO top_ignore_messages VALUES (:mid)", + ret = getNamedParameterJdbcTemplate().update("INSERT INTO top_ignore_messages VALUES (:mid)", sqlParameterSource); return ret > 0; @@ -1044,43 +904,64 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional @Override public boolean deleteMessage(final int uid, final int mid) { - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("mid", mid) - .addValue("uid", uid); - - if (getNamedParameterJdbcTemplate().update( - "DELETE FROM messages WHERE message_id = :mid AND user_id = :uid", sqlParameterSource) > 0) { - - getNamedParameterJdbcTemplate().update("DELETE FROM messages_txt WHERE message_id = :mid", sqlParameterSource); - getNamedParameterJdbcTemplate().update("DELETE FROM replies WHERE message_id = :mid", sqlParameterSource); - getNamedParameterJdbcTemplate().update("DELETE FROM subscr_messages WHERE message_id = :mid", sqlParameterSource); - getNamedParameterJdbcTemplate().update("DELETE FROM messages_tags WHERE message_id = :mid", sqlParameterSource); - - return true; + Instant now = Instant.now(); + Instant messageDeletingWindow = now.minus(3, ChronoUnit.DAYS); + Optional message = getMessage(mid); + if (message.isPresent()) { + Instant ts = message.get().getUpdatedAt(); + if (ts.compareTo(messageDeletingWindow) >= 0) { + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("mid", mid).addValue("uid", + uid); + + if (getNamedParameterJdbcTemplate().update( + "DELETE FROM messages WHERE message_id = :mid AND user_id = :uid", + sqlParameterSource) > 0) { + + getNamedParameterJdbcTemplate().update("DELETE FROM messages_txt WHERE message_id = :mid", + sqlParameterSource); + getNamedParameterJdbcTemplate().update("DELETE FROM replies WHERE message_id = :mid", + sqlParameterSource); + getNamedParameterJdbcTemplate().update("DELETE FROM subscr_messages WHERE message_id = :mid", + sqlParameterSource); + getNamedParameterJdbcTemplate().update("DELETE FROM messages_tags WHERE message_id = :mid", + sqlParameterSource); + + return true; + } + } } return false; } + @Transactional @Override public boolean deleteReply(final int uid, final int mid, final int rid) { - User author = getMessageAuthor(mid); - SqlParameterSource sqlParameterSource = new MapSqlParameterSource() - .addValue("mid", mid) - .addValue("uid", uid) - .addValue("rid", rid); - boolean result; - if (author.getUid() == uid) { - result = getNamedParameterJdbcTemplate() - .update("DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid", sqlParameterSource) > 0; - } else { - result = getNamedParameterJdbcTemplate() - .update("DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid AND user_id=:uid" - , sqlParameterSource) > 0; - } - if (result) { - getNamedParameterJdbcTemplate().update("UPDATE messages SET replies=replies-1 WHERE message_id=:mid", sqlParameterSource); - updateRepliesBy(mid); - return true; + Instant now = Instant.now(); + Instant messageDeletingWindow = now.minus(3, ChronoUnit.DAYS); + Message reply = getReply(mid, rid); + if (reply != null) { + Instant ts = reply.getUpdatedAt(); + if (ts.compareTo(messageDeletingWindow) >= 0) { + User author = getMessageAuthor(mid); + SqlParameterSource sqlParameterSource = new MapSqlParameterSource().addValue("mid", mid) + .addValue("uid", uid).addValue("rid", rid); + boolean result; + if (author.getUid() == uid) { + result = getNamedParameterJdbcTemplate().update( + "DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid", + sqlParameterSource) > 0; + } else { + result = getNamedParameterJdbcTemplate().update( + "DELETE FROM replies WHERE message_id=:mid AND reply_id=:rid AND user_id=:uid", + sqlParameterSource) > 0; + } + if (result) { + getNamedParameterJdbcTemplate() + .update("UPDATE messages SET replies=replies-1 WHERE message_id=:mid", sqlParameterSource); + updateRepliesBy(mid); + return true; + } + } } return false; } @@ -1088,59 +969,64 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public List getLastMessages(int hours) { - return getJdbcTemplate().queryForList("SELECT message_id FROM messages WHERE messages.ts>TIMESTAMPADD(HOUR,?,NOW())", - Integer.class, -hours); + return getJdbcTemplate().queryForList( + "SELECT message_id FROM messages WHERE messages.ts>TIMESTAMPADD(HOUR,?,NOW())", Integer.class, -hours); } @Transactional(readOnly = true) @Override public List getLastReplies(int hours) { - return getJdbcTemplate().query("SELECT users2.nick,replies.message_id,replies.reply_id," + - "users.nick,replies.txt," + - "replies.ts,replies.attach,replies.ts+0, replies.html " + - "FROM ((replies INNER JOIN users ON replies.user_id=users.id) " + - "INNER JOIN messages ON replies.message_id=messages.message_id) " + - "INNER JOIN users AS users2 ON messages.user_id=users2.id " + - "WHERE replies.ts>TIMESTAMPADD(HOUR,?,NOW()) AND messages.privacy>0", (rs, rowNum) -> { - ResponseReply reply = new ResponseReply(); - reply.setMuname(rs.getString(1)); - reply.setMid(rs.getInt(2)); - reply.setRid(rs.getInt(3)); - reply.setUname(rs.getString(4)); - reply.setDescription(rs.getString(5)); - reply.setPubDate(rs.getTimestamp(6)); - reply.setAttachmentType(rs.getString(7)); - reply.setHtml(rs.getBoolean(8)); - return reply; - }, -hours); + return getJdbcTemplate().query("SELECT users2.nick,replies.message_id,replies.reply_id," + + "users.nick,replies.txt," + "replies.ts,replies.attach,replies.ts+0, replies.html " + + "FROM ((replies INNER JOIN users ON replies.user_id=users.id) " + + "INNER JOIN messages ON replies.message_id=messages.message_id) " + + "INNER JOIN users AS users2 ON messages.user_id=users2.id " + + "WHERE replies.ts>TIMESTAMPADD(HOUR,?,NOW()) AND messages.privacy>0", (rs, rowNum) -> { + ResponseReply reply = new ResponseReply(); + reply.setMuname(rs.getString(1)); + reply.setMid(rs.getInt(2)); + reply.setRid(rs.getInt(3)); + reply.setUname(rs.getString(4)); + reply.setDescription(rs.getString(5)); + reply.setPubDate(rs.getTimestamp(6)); + reply.setAttachmentType(rs.getString(7)); + reply.setHtml(rs.getBoolean(8)); + return reply; + }, -hours); } + @Transactional(readOnly = true) @Override public List getPopularCandidates() { - return getJdbcTemplate().queryForList("SELECT replies.message_id FROM replies " + - "INNER JOIN messages ON replies.message_id = messages.message_id " + - "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " + - "WHERE COALESCE(messages_tags.tag_id, 0) != 2 " + - "AND COALESCE(messages_tags.tag_id, 0) != 805 AND replies.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " + - "AND messages.popular=0 GROUP BY messages.message_id having COUNT(DISTINCT(replies.user_id)) > 5 " + - "UNION ALL SELECT favorites.message_id FROM favorites " + - "INNER JOIN messages ON messages.message_id = favorites.message_id " + - "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " + - "WHERE COALESCE(messages_tags.tag_id, 0) != 2 AND favorites.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " + - "AND messages.popular=0 GROUP BY messages.message_id HAVING COUNT(DISTINCT favorites.user_id) > 1;", Integer.class); + return getJdbcTemplate().queryForList("SELECT replies.message_id FROM replies " + + "INNER JOIN messages ON replies.message_id = messages.message_id " + + "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " + + "WHERE COALESCE(messages_tags.tag_id, 0) != 2 " + + "AND COALESCE(messages_tags.tag_id, 0) != 805 AND replies.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " + + "AND messages.popular=0 GROUP BY messages.message_id having COUNT(DISTINCT(replies.user_id)) > 5 " + + "UNION ALL SELECT favorites.message_id FROM favorites " + + "INNER JOIN messages ON messages.message_id = favorites.message_id " + + "LEFT JOIN messages_tags ON messages_tags.message_id = messages.message_id " + + "WHERE COALESCE(messages_tags.tag_id, 0) != 2 AND favorites.ts > TIMESTAMPADD(HOUR, -2, CURRENT_TIMESTAMP) " + + "AND messages.popular=0 GROUP BY messages.message_id HAVING COUNT(DISTINCT favorites.user_id) > 1;", + Integer.class); } + @Transactional @Override public void setLastReadComment(User user, Integer mid, Integer rid) { - jdbcTemplate.update("UPDATE subscr_messages SET last_read_rid=GREATEST(?, last_read_rid) WHERE message_id=? AND suser_id=?", + jdbcTemplate.update( + "UPDATE subscr_messages SET last_read_rid=GREATEST(?, last_read_rid) WHERE message_id=? AND suser_id=?", rid, mid, user.getUid()); } + @Transactional @Override public void setRead(User user, Integer mid) { - jdbcTemplate.update("UPDATE subscr_messages SET last_read_rid=(select replies from messages " + - "where messages.message_id=subscr_messages.message_id) WHERE message_id=? AND suser_id=?", + jdbcTemplate.update( + "UPDATE subscr_messages SET last_read_rid=(select replies from messages " + + "where messages.message_id=subscr_messages.message_id) WHERE message_id=? AND suser_id=?", mid, user.getUid()); } @@ -1148,12 +1034,11 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Override public List getUnread(User user) { return jdbcTemplate.queryForList( - "select subscr_messages.message_id " + - "from subscr_messages inner join messages on subscr_messages.message_id=messages.message_id " + - "where subscr_messages.suser_id=? " + - "AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " + - "user_id = ? AND bl_user_id = messages.user_id) AND " + - "messages.replies>subscr_messages.last_read_rid", + "select subscr_messages.message_id " + + "from subscr_messages inner join messages on subscr_messages.message_id=messages.message_id " + + "where subscr_messages.suser_id=? " + "AND NOT EXISTS (SELECT 1 FROM bl_users WHERE " + + "user_id = ? AND bl_user_id = messages.user_id) AND " + + "messages.replies>subscr_messages.last_read_rid", Integer.class, user.getUid(), user.getUid()); } @@ -1161,11 +1046,29 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Override public boolean updateMessage(Integer mid, Integer rid, String body) { Instant now = Instant.now(); + Instant messageEditingWindow = now.minus(15, ChronoUnit.MINUTES); if (rid == 0) { - return jdbcTemplate.update("UPDATE messages_txt SET txt=?, updated_at=? WHERE message_id=?", body, Timestamp.from(now), mid) > 0; + Optional message = getMessage(mid); + if (message.isPresent()) { + Instant ts = message.get().getUpdatedAt(); + if (ts.compareTo(messageEditingWindow) >= 0) { + return jdbcTemplate.update( + "UPDATE messages_txt SET txt=?, updated_at=? WHERE messages_txt.message_id=?", body, + Timestamp.from(now), mid) > 0; + } + } + return false; } else { - return jdbcTemplate.update("UPDATE replies SET txt=?, updated_at=? WHERE message_id=? and reply_id=?", - body, Timestamp.from(now), mid, rid) > 0; + Message reply = getReply(mid, rid); + if (reply != null) { + Instant ts = reply.getUpdatedAt(); + if (ts.compareTo(messageEditingWindow) >= 0) { + return jdbcTemplate.update( + "UPDATE replies SET txt=?, updated_at=? WHERE message_id=? AND reply_id=?", body, + Timestamp.from(now), mid, rid) > 0; + } + } + return false; } } @@ -1179,14 +1082,16 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional(readOnly = true) @Override public boolean replyExists(URI replyUri) { - return jdbcTemplate.queryForList("SELECT reply_id FROM replies WHERE reply_uri=?", - Integer.class, replyUri.toASCIIString()).size() > 0; + return jdbcTemplate + .queryForList("SELECT reply_id FROM replies WHERE reply_uri=?", Integer.class, replyUri.toASCIIString()) + .size() > 0; } @Transactional @Override public boolean deleteReply(URI userUri, URI replyUri) { - return jdbcTemplate.update("DELETE FROM replies WHERE user_uri=? AND reply_uri=?", + return jdbcTemplate.update( + "DELETE FROM replies WHERE user_uri=? AND reply_uri=?", userUri.toASCIIString(), replyUri.toASCIIString()) > 0; } @@ -1205,30 +1110,28 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ @Transactional @Override public void setMessageProperty(Integer mid, Integer rid, String key, String value) { - SqlParameterSource parameterSource = new MapSqlParameterSource() - .addValue("mid", mid) - .addValue("rid", rid) - .addValue("key", key) - .addValue("value", value); + SqlParameterSource parameterSource = new MapSqlParameterSource().addValue("mid", mid).addValue("rid", rid) + .addValue("key", key).addValue("value", value); if (StringUtils.isNotEmpty(value)) { try { - getNamedParameterJdbcTemplate().update("INSERT INTO messages_properties(message_id, reply_id, property_key, property_value) " + - "VALUES(:mid, :rid, :key, :value)", parameterSource); + getNamedParameterJdbcTemplate() + .update("INSERT INTO messages_properties(message_id, reply_id, property_key, property_value) " + + "VALUES(:mid, :rid, :key, :value)", parameterSource); } catch (DataIntegrityViolationException ex) { - getNamedParameterJdbcTemplate().update("UPDATE messages_properties SET property_value=:value " + - "WHERE message_id=:mid AND reply_id=:rid AND property_key=:key", parameterSource); + getNamedParameterJdbcTemplate().update("UPDATE messages_properties SET property_value=:value " + + "WHERE message_id=:mid AND reply_id=:rid AND property_key=:key", parameterSource); } } else { - getNamedParameterJdbcTemplate().update("DELETE FROM messages_properties " + - "WHERE message_id=:mid AND reply_id=:rid AND property_key=:key", parameterSource); + getNamedParameterJdbcTemplate().update("DELETE FROM messages_properties " + + "WHERE message_id=:mid AND reply_id=:rid AND property_key=:key", parameterSource); } } @Transactional(readOnly = true) @Override public Optional> findMessageByProperty(String key, String value) { - List> results = jdbcTemplate.query("SELECT message_id, reply_id FROM messages_properties " + - "WHERE property_key=? AND property_value=?", + List> results = jdbcTemplate.query( + "SELECT message_id, reply_id FROM messages_properties " + "WHERE property_key=? AND property_value=?", (rs, rowNum) -> Pair.of(rs.getInt(1), rs.getInt(2)), key, value); if (results.size() > 0) { return Optional.of(results.get(0)); diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index d19c76cb..faee1f53 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -1306,7 +1306,17 @@ public class ServerTests { .getNewMessage().get(); assertThat(editedComment.getText(), is("HEY, JOE")); assertThat(editedComment.getUpdatedAt(), greaterThan(editedComment.getCreated())); - messagesService.deleteMessage(ugnich.getUid(), original.getMid()); + jdbcTemplate.update("UPDATE replies SET updated_at='1990-05-05 00:00:00' WHERE message_id=? AND reply_id=?", editedComment.getMid(), editedComment.getRid()); + result = mockMvc + .perform(post("/api/update").with(httpBasic(freefdName, freefdPassword)) + .param("mid", String.valueOf(comment.getNewMessage().get().getMid())) + .param("rid", String.valueOf(comment.getNewMessage().get().getRid())).param("body", "HEY, JOE AGAIN")) + .andExpect(status().isBadRequest()).andReturn(); + jdbcTemplate.update("UPDATE messages_txt SET updated_at='1990-05-05 00:00:00' WHERE message_id=?", original.getMid()); + assertThat(messagesService.deleteMessage(ugnich.getUid(), original.getMid()), is(false)); + jdbcTemplate.update("UPDATE messages_txt SET updated_at=? WHERE message_id=?", Instant.now(), original.getMid()); + assertThat(messagesService.deleteMessage(ugnich.getUid(), original.getMid()), is(true)); + } @Test -- cgit v1.2.3