aboutsummaryrefslogtreecommitdiff
path: root/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'juick-server/src/main/java/com/juick/service/TagServiceImpl.java')
-rw-r--r--juick-server/src/main/java/com/juick/service/TagServiceImpl.java273
1 files changed, 273 insertions, 0 deletions
diff --git a/juick-server/src/main/java/com/juick/service/TagServiceImpl.java b/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
new file mode 100644
index 00000000..524ad32d
--- /dev/null
+++ b/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2008-2017, Juick
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.juick.service;
+
+import com.juick.Tag;
+import com.juick.User;
+import com.juick.server.helpers.TagStats;
+import com.juick.util.StreamUtils;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+/**
+ * Created by aalexeev on 11/13/16.
+ */
+@Repository
+public class TagServiceImpl extends BaseJdbcService implements TagService {
+
+ @Transactional(readOnly = true)
+ @Override
+ public com.juick.Tag getTag(final int tid) {
+ List<Tag> list = getJdbcTemplate().query(
+ "SELECT synonym_id,name FROM tags WHERE tag_id=?",
+ (rs, num) -> {
+ Tag ret = new Tag(rs.getString(2));
+ ret.TID = tid;
+ ret.SynonymID = rs.getInt(1);
+ return ret;
+ },
+ tid);
+
+ return list.isEmpty() ?
+ null : list.get(0);
+ }
+
+ @Transactional
+ @Override
+ public com.juick.Tag getTag(final String tag, final boolean autoCreate) {
+ if (StringUtils.isBlank(tag))
+ return null;
+
+ List<Tag> list = getJdbcTemplate().query(
+ "SELECT tag_id, synonym_id, name FROM tags WHERE name = ?",
+ (rs, rowNum) -> {
+ Tag ret1 = new Tag(rs.getString(3));
+ ret1.TID = rs.getInt(1);
+ ret1.SynonymID = rs.getInt(2);
+ return ret1;
+ },
+ tag);
+
+ Tag ret = list.isEmpty() ?
+ null : list.get(0);
+
+ if (ret == null && autoCreate) {
+ ret = new com.juick.Tag(tag);
+ ret.TID = createTag(tag);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public List<Tag> getTags(Stream<String> tags, final boolean autoCreate) {
+ return tags.filter(StringUtils::isNotBlank).map(tag -> getTag(tag, autoCreate)).filter(Objects::nonNull).distinct()
+ .collect(Collectors.toList());
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public boolean getTagNoIndex(final int tagId) {
+ List<Integer> list = getJdbcTemplate().queryForList(
+ "SELECT noindex FROM tags WHERE tag_id=?", Integer.class, tagId);
+
+ return !list.isEmpty() && list.get(0) == 1;
+ }
+
+ @Transactional
+ @Override
+ public int createTag(final String name) {
+ KeyHolder holder = new GeneratedKeyHolder();
+ getJdbcTemplate().update(
+ con -> {
+ PreparedStatement stmt = con.prepareStatement(
+ "INSERT INTO tags(name) VALUES (?)",
+ Statement.RETURN_GENERATED_KEYS);
+ stmt.setString(1, name);
+ return stmt;
+ },
+ holder);
+
+ return holder.getKey().intValue();
+ }
+
+ private class TagStatsMapper implements RowMapper<TagStats> {
+
+ @Override
+ public TagStats mapRow(ResultSet rs, int rowNum) throws SQLException {
+ Tag t = new Tag(rs.getString(1));
+ TagStats s = new TagStats();
+ s.setTag(t);
+ s.setUsageCount(rs.getInt(2));
+ return s;
+ }
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<TagStats> getUserTagStats(final int uid) {
+ return getJdbcTemplate().query(
+ "SELECT tags.name,COUNT(messages.message_id) " +
+ "FROM (messages INNER JOIN messages_tags ON (messages.user_id=? " +
+ "AND messages.message_id=messages_tags.message_id)) " +
+ "INNER JOIN tags ON messages_tags.tag_id=tags.tag_id GROUP BY tags.tag_id ORDER BY tags.name ASC",
+ new TagStatsMapper(),
+ uid);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<String> getUserBLTags(final int uid) {
+ return getJdbcTemplate().queryForList(
+ "SELECT tags.name FROM tags INNER JOIN bl_tags " +
+ "ON (bl_tags.user_id = ? AND bl_tags.tag_id = tags.tag_id) ORDER BY tags.name",
+ String.class, uid);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<String> getPopularTags() {
+ return getJdbcTemplate().queryForList(
+ "select name from tags where noindex=0 order by stat_messages desc limit 20", String.class);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<TagStats> getTagStats() {
+ return getJdbcTemplate().query(
+ "SELECT tags.name,COUNT(DISTINCT messages.user_id) AS cnt " +
+ "FROM (messages INNER JOIN messages_tags ON (messages.ts>TIMESTAMPADD(DAY,-3,NOW()) " +
+ "AND messages.message_id=messages_tags.message_id)) " +
+ "INNER JOIN tags ON messages_tags.tag_id=tags.tag_id " +
+ "WHERE tags.tag_id NOT IN (SELECT tag_id FROM tags_ignore) " +
+ "GROUP BY tags.tag_id ORDER BY cnt DESC LIMIT 20", new TagStatsMapper());
+ }
+
+ @Transactional
+ @Override
+ public List<Tag> updateTags(final int mid, final Collection<Tag> newTags) {
+ List<Tag> currentTags = getMessageTags(mid).stream()
+ .map(TagStats::getTag).collect(Collectors.toList());
+
+ if (CollectionUtils.isEmpty(newTags))
+ return currentTags;
+
+ List<Integer> idsForDelete = newTags.stream()
+ .filter(currentTags::contains)
+ .map(tag -> tag.TID)
+ .collect(Collectors.toList());
+ if (newTags.size() - idsForDelete.size() >= 5) {
+ return currentTags;
+ }
+
+ if (!idsForDelete.isEmpty())
+ getNamedParameterJdbcTemplate().update(
+ "DELETE FROM messages_tags WHERE message_id = :mid AND tag_id in (:ids)",
+ new MapSqlParameterSource().addValue("ids", idsForDelete).addValue("mid", mid));
+
+ newTags.stream().filter(t -> !currentTags.contains(t))
+ .forEach(t -> getJdbcTemplate().update("INSERT INTO messages_tags(message_id,tag_id) VALUES (?,?)", mid, t.TID));
+
+ List<Tag> result = getMessageTags(mid).stream()
+ .map(TagStats::getTag).collect(Collectors.toList());
+ jdbcTemplate.update("UPDATE messages_txt SET tags=? WHERE message_id=?", result.stream()
+ .map(Tag::getName).collect(Collectors.joining(" ")), mid);
+ return result;
+ }
+
+ @Override
+ public List<Tag> fromString(final String txt) {
+ String firstLine = txt.split("\\n", 2)[0];
+ return StreamUtils.takeWhile(Arrays.stream(firstLine.split("\\ ")),
+ t -> !t.equals("*") && t.startsWith("*"))
+ .map(t -> getTag(t.substring(1), true))
+ .collect(Collectors.toList());
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<TagStats> getMessageTags(final int mid) {
+ return getJdbcTemplate().query(
+ "SELECT tags.tag_id,synonym_id,name,stat_messages FROM tags " +
+ "INNER JOIN messages_tags ON (messages_tags.message_id = ? AND messages_tags.tag_id = tags.tag_id)",
+ (rs, num) -> {
+ com.juick.Tag t = new com.juick.Tag(rs.getString(3));
+ t.TID = rs.getInt(1);
+ t.SynonymID = rs.getInt(2);
+ TagStats s = new TagStats();
+ s.setTag(t);
+ s.setUsageCount(rs.getInt(4));
+ return s;
+ }, mid);
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public List<Integer> getMessageTagsIDs(final int mid) {
+ return getJdbcTemplate().queryForList(
+ "SELECT tag_id FROM messages_tags WHERE message_id = ?",
+ Integer.class, mid);
+ }
+
+ @Override
+ public boolean blacklistTag(User user, Tag tag) {
+ int rowcount = getNamedParameterJdbcTemplate().update("DELETE FROM bl_tags WHERE tag_id = :tid AND user_id = :uid",
+ new MapSqlParameterSource().addValue("tid", tag.TID).addValue("uid", user.getUid()));
+ return rowcount <= 0 && getNamedParameterJdbcTemplate()
+ .update("INSERT INTO bl_tags(user_id, tag_id) VALUES(:uid,:tid)",
+ new MapSqlParameterSource().addValue("tid", tag.TID)
+ .addValue("uid", user.getUid())) > 0;
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public boolean isInBL(User user, Tag tag) {
+ List<Integer> list = getJdbcTemplate().queryForList(
+ "SELECT 1 FROM bl_tags WHERE user_id = ? AND tag_id = ?",
+ Integer.class, user.getUid(), tag.TID);
+ return !list.isEmpty() && list.get(0) == 1;
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public boolean isSubscribed(User user, Tag tag) {
+ List<Integer> list = getJdbcTemplate().queryForList(
+ "SELECT 1 FROM subscr_tags WHERE suser_id = ? AND tag_id = ?",
+ Integer.class, user.getUid(), tag.TID);
+ return !list.isEmpty() && list.get(0) == 1;
+ }
+
+}