aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--juick-api/src/main/java/com/juick/api/configuration/ApiSecurityConfig.java3
-rw-r--r--juick-api/src/main/java/com/juick/api/controllers/Tags.java45
-rw-r--r--juick-api/src/test/java/com/juick/api/tests/MessagesTests.java81
-rw-r--r--juick-core/src/main/java/com/juick/Tag.java5
-rw-r--r--juick-server/src/main/java/com/juick/server/MessagesQueries.java13
-rw-r--r--juick-server/src/main/java/com/juick/server/TagQueries.java16
-rw-r--r--juick-server/src/main/java/com/juick/server/helpers/TagStats.java29
-rw-r--r--juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java5
-rw-r--r--juick-server/src/main/java/com/juick/service/MessagesService.java4
-rw-r--r--juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java26
-rw-r--r--juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java11
-rw-r--r--juick-server/src/main/java/com/juick/service/TagService.java8
-rw-r--r--juick-server/src/main/java/com/juick/service/TagServiceImpl.java68
-rw-r--r--juick-www/src/main/java/com/juick/www/NewMessage.java17
-rw-r--r--juick-www/src/main/java/com/juick/www/PageTemplates.java14
-rw-r--r--juick-www/src/main/java/com/juick/www/User.java19
-rw-r--r--juick-www/src/main/java/com/juick/www/UserThread.java10
-rw-r--r--src/test/java/com/juick/tests/ApiTests.java8
18 files changed, 262 insertions, 120 deletions
diff --git a/juick-api/src/main/java/com/juick/api/configuration/ApiSecurityConfig.java b/juick-api/src/main/java/com/juick/api/configuration/ApiSecurityConfig.java
index 99731d2a..da7f5d3b 100644
--- a/juick-api/src/main/java/com/juick/api/configuration/ApiSecurityConfig.java
+++ b/juick-api/src/main/java/com/juick/api/configuration/ApiSecurityConfig.java
@@ -3,7 +3,6 @@ package com.juick.api.configuration;
import com.juick.server.security.JuickAuthenticationEntryPoint;
import com.juick.service.UserService;
import com.juick.service.security.JuickUserDetailsService;
-import com.juick.service.security.deprecated.CookieSimpleHashRememberMeServices;
import com.juick.service.security.deprecated.RequestParamHashRememberMeServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -45,7 +44,7 @@ public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
- .antMatchers("/messages", "/users", "/thread").permitAll()
+ .antMatchers("/messages", "/users", "/thread", "/tags").permitAll()
.anyRequest().hasRole("USER")
.and().httpBasic().authenticationEntryPoint(getJuickAuthenticationEntryPoint())
.and().anonymous()
diff --git a/juick-api/src/main/java/com/juick/api/controllers/Tags.java b/juick-api/src/main/java/com/juick/api/controllers/Tags.java
new file mode 100644
index 00000000..5548da17
--- /dev/null
+++ b/juick-api/src/main/java/com/juick/api/controllers/Tags.java
@@ -0,0 +1,45 @@
+package com.juick.api.controllers;
+
+import com.juick.User;
+import com.juick.server.helpers.TagStats;
+import com.juick.service.TagService;
+import com.juick.service.UserService;
+import com.juick.util.UserUtils;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.inject.Inject;
+import java.security.Principal;
+import java.util.List;
+
+/**
+ * Created by vitalyster on 29.11.2016.
+ */
+@Controller
+@ResponseBody
+public class Tags {
+ @Inject
+ UserService userService;
+ @Inject
+ TagService tagService;
+
+ @RequestMapping(value = "/tags", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+ public List<TagStats> tags(
+ Principal principal,
+ @RequestParam(required = false, defaultValue = "0") int user_id
+ ) {
+ String name = UserUtils.getUsername(principal, null);
+ User visitor = userService.getUserByName(name);
+ if (user_id == 0) {
+ user_id = visitor.getUid();
+ }
+ if (user_id > 0) {
+ return tagService.getUserTagStats(user_id);
+ }
+ return tagService.getTagStats();
+ }
+}
diff --git a/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java b/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java
index 05744a61..e0f9b840 100644
--- a/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java
+++ b/juick-api/src/test/java/com/juick/api/tests/MessagesTests.java
@@ -7,7 +7,9 @@ import com.juick.api.configuration.ApiAppConfiguration;
import com.juick.api.configuration.ApiMvcConfiguration;
import com.juick.api.configuration.ApiSecurityConfig;
import com.juick.configuration.DataConfiguration;
+import com.juick.server.helpers.TagStats;
import com.juick.service.MessagesService;
+import com.juick.service.TagService;
import com.juick.service.UserService;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Before;
@@ -59,6 +61,12 @@ public class MessagesTests {
UserService userService() {
return Mockito.mock(UserService.class);
}
+
+ @Bean
+ @Primary
+ TagService tagService() {
+ return Mockito.mock(TagService.class);
+ }
}
private MockMvc mockMvc;
@@ -69,6 +77,11 @@ public class MessagesTests {
private MessagesService messagesService;
@Inject
private UserService userService;
+ @Inject
+ private TagService tagService;
+
+ private User ugnich, freefd;
+ String ugnichName, ugnichPassword, freefdName, freefdPassword;
private static Message getMessage(final User user, final String messageText) {
Message msg = new Message();
@@ -98,12 +111,30 @@ public class MessagesTests {
.apply(SecurityMockMvcConfigurers.springSecurity())
.dispatchOptions(true)
.build();
+ ugnichName = "ugnich";
+ ugnichPassword = "MyPassw0rd!";
+ freefdName = "freefd";
+ freefdPassword = "MyPassw0rd!";
+
+ ugnich = getUser(1, ugnichName, ugnichPassword);
+ freefd = getUser(2, freefdName, freefdPassword);
+
+ List<String> users = new ArrayList<>(2);
+ users.add(ugnichName);
+ users.add(freefdName);
+
+ when(userService.getUsersByName(users))
+ .thenReturn(Arrays.asList(ugnich, freefd));
+ when(userService.getUserByName(ugnichName))
+ .thenReturn(ugnich);
+ when(userService.getFullyUserByName(ugnichName))
+ .thenReturn(ugnich);
+ when(userService.getUserByName(null))
+ .thenReturn(new User());
}
@Test
public void testAllUnAuthorized() throws Exception {
- when(userService.getUserByName(null))
- .thenReturn(new User());
mockMvc.perform(get("/"))
.andExpect(status().is4xxClientError());
@@ -120,17 +151,11 @@ public class MessagesTests {
@Test
public void homeTestWithMessages() throws Exception {
- String ugnichName = "ugnich";
- String uginchPassword = "MyPassw0rd!";
String msgText = "Привет, я - Угнич";
- User user = getUser(1, ugnichName, uginchPassword);
- Message msg = getMessage(user, msgText);
+ Message msg = getMessage(ugnich, msgText);
+
- when(userService.getUserByName(ugnichName))
- .thenReturn(user);
- when(userService.getFullyUserByName(ugnichName))
- .thenReturn(user);
when(messagesService.getMyFeed(1, 0))
.thenReturn(Collections.singletonList(1));
when(messagesService.getMessages(Collections.singletonList(1)))
@@ -138,7 +163,7 @@ public class MessagesTests {
mockMvc.perform(
get("/home")
- .with(httpBasic(ugnichName, uginchPassword)))
+ .with(httpBasic(ugnichName, ugnichPassword)))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(1)))
@@ -233,20 +258,7 @@ public class MessagesTests {
@Test
public void anonymousApis() throws Exception {
- String ugnichName = "ugnich";
- String uginchPassword = "MyPassw0rd!";
- String freefdName = "freefd";
- String freefdPassword = "MyPassw0rd!";
-
- User ugnich = getUser(1, ugnichName, uginchPassword);
- User freefd = getUser(2, freefdName, freefdPassword);
-
- List<String> users = new ArrayList<>(2);
- users.add(ugnichName);
- users.add(freefdName);
- when(userService.getUsersByName(users))
- .thenReturn(Arrays.asList(ugnich, freefd));
mockMvc.perform(get("/messages"))
.andExpect(status().isOk());
@@ -258,4 +270,25 @@ public class MessagesTests {
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(2)));
}
+ @Test
+ public void tags() throws Exception {
+ Tag weather = new Tag("weather");
+ TagStats sw = new TagStats();
+ sw.setTag(weather);
+ sw.setUsageCount(15);
+ Tag yo = new Tag("yo");
+ TagStats sy = new TagStats();
+ sy.setTag(yo);
+ sy.setUsageCount(5);
+ when(tagService.getUserTagStats(1)).thenReturn(Collections.singletonList(sy));
+ when(tagService.getTagStats()).thenReturn(Arrays.asList(sy, sw));
+ mockMvc.perform(get("/tags"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(2)));
+ mockMvc.perform(get("/tags")
+ .param("user_id", "1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].messages", is(5)));
+ }
}
diff --git a/juick-core/src/main/java/com/juick/Tag.java b/juick-core/src/main/java/com/juick/Tag.java
index 3f5add6e..98fe60ff 100644
--- a/juick-core/src/main/java/com/juick/Tag.java
+++ b/juick-core/src/main/java/com/juick/Tag.java
@@ -17,7 +17,6 @@
*/
package com.juick;
-import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import javax.xml.bind.annotation.XmlAccessType;
@@ -36,7 +35,6 @@ public class Tag {
public int TID = 0;
public int SynonymID = 0;
- public int UsageCnt = 0;
public Tag() {
@@ -52,14 +50,13 @@ public class Tag {
(o instanceof Tag) && Objects.equals(name, ((Tag) o).name);
}
- @JsonIgnore
@XmlValue
+ @JsonValue
public String getName() {
return name;
}
@Override
- @JsonValue
public String toString() {
return name;
}
diff --git a/juick-server/src/main/java/com/juick/server/MessagesQueries.java b/juick-server/src/main/java/com/juick/server/MessagesQueries.java
index fd1e5b51..36d311df 100644
--- a/juick-server/src/main/java/com/juick/server/MessagesQueries.java
+++ b/juick-server/src/main/java/com/juick/server/MessagesQueries.java
@@ -21,6 +21,7 @@ import com.juick.Message;
import com.juick.Tag;
import com.juick.User;
import com.juick.server.helpers.PrivacyOpts;
+import com.juick.server.helpers.TagStats;
import com.juick.util.MessageUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -308,16 +309,18 @@ public class MessagesQueries {
}
}
- public static List<com.juick.Tag> getMessageTags(JdbcTemplate sql, int mid) {
+ public static List<TagStats> getMessageTags(JdbcTemplate sql, int mid) {
return sql.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)",
- new Object[]{mid}, (rs, num) -> {
+ (rs, num) -> {
com.juick.Tag t = new com.juick.Tag(StringEscapeUtils.unescapeHtml4(rs.getString(3)));
t.TID = rs.getInt(1);
t.SynonymID = rs.getInt(2);
- t.UsageCnt = rs.getInt(4);
- return t;
- });
+ TagStats s = new TagStats();
+ s.setTag(t);
+ s.setUsageCount(rs.getInt(4));
+ return s;
+ }, mid);
}
public static List<Integer> getMessageTagsIDs(JdbcTemplate sql, int mid) {
diff --git a/juick-server/src/main/java/com/juick/server/TagQueries.java b/juick-server/src/main/java/com/juick/server/TagQueries.java
index ee9a1e21..6d416a37 100644
--- a/juick-server/src/main/java/com/juick/server/TagQueries.java
+++ b/juick-server/src/main/java/com/juick/server/TagQueries.java
@@ -18,6 +18,7 @@
package com.juick.server;
import com.juick.Tag;
+import com.juick.server.helpers.TagStats;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -109,15 +110,16 @@ public class TagQueries {
return holder.getKey().intValue();
}
- public static List<com.juick.Tag> getUserTagsAll(JdbcTemplate sql, int uid) {
+ public static List<TagStats> getTagsStats(JdbcTemplate sql, int uid) {
return sql.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",
(rs, rowNum) -> {
- Tag t = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(1)));
- t.UsageCnt = rs.getInt(2);
- return t;
+ TagStats s = new TagStats();
+ s.setTag(new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(1))));
+ s.setUsageCount(rs.getInt(2));
+ return s;
}, uid);
}
@@ -132,12 +134,14 @@ public class TagQueries {
.map(StringEscapeUtils::unescapeHtml4).collect(Collectors.toList());
}
public static List<Tag> updateTags(JdbcTemplate sql, int mid, List<Tag> newTags) {
- List<Tag> currentTags = MessagesQueries.getMessageTags(sql, mid);
+ List<Tag> currentTags = MessagesQueries.getMessageTags(sql, mid).stream()
+ .map(TagStats::getTag).collect(Collectors.toList());
newTags.stream().filter(currentTags::contains)
.forEach(t -> sql.update("DELETE FROM messages_tags WHERE message_id=? AND tag_id=?", mid, t.TID));
newTags.stream().filter(t -> !currentTags.contains(t))
.forEach(t -> sql.update("INSERT INTO messages_tags(message_id,tag_id) VALUES (?,?)", mid, t.TID));
- return MessagesQueries.getMessageTags(sql, mid);
+ return MessagesQueries.getMessageTags(sql, mid).stream()
+ .map(TagStats::getTag).collect(Collectors.toList());
}
public static List<Tag> fromString(JdbcTemplate sql, String txt, boolean tagsOnly) {
diff --git a/juick-server/src/main/java/com/juick/server/helpers/TagStats.java b/juick-server/src/main/java/com/juick/server/helpers/TagStats.java
new file mode 100644
index 00000000..e8720991
--- /dev/null
+++ b/juick-server/src/main/java/com/juick/server/helpers/TagStats.java
@@ -0,0 +1,29 @@
+package com.juick.server.helpers;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.juick.Tag;
+
+/**
+ * Created by vitalyster on 01.12.2016.
+ */
+public class TagStats {
+ private Tag tag;
+ private int usageCount;
+
+ public Tag getTag() {
+ return tag;
+ }
+
+ public void setTag(Tag tag) {
+ this.tag = tag;
+ }
+
+ @JsonProperty("messages")
+ public int getUsageCount() {
+ return usageCount;
+ }
+
+ public void setUsageCount(int usageCount) {
+ this.usageCount = usageCount;
+ }
+}
diff --git a/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java b/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java
index 1bac9fce..68c7c37c 100644
--- a/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java
+++ b/juick-server/src/main/java/com/juick/server/protocol/JuickProtocol.java
@@ -8,6 +8,7 @@ import com.juick.Tag;
import com.juick.User;
import com.juick.formatters.PlainTextFormatter;
import com.juick.server.*;
+import com.juick.server.helpers.TagStats;
import com.juick.server.protocol.annotation.UserCommand;
import com.juick.util.TagUtils;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -179,10 +180,10 @@ public class JuickProtocol {
@UserCommand(pattern = "\\*", help = "* - Show your tags")
public ProtocolReply commandTags(User currentUser, String... args) {
- List<Tag> tags = TagQueries.getUserTagsAll(sql, currentUser.getUid());
+ List<TagStats> tags = TagQueries.getTagsStats(sql, currentUser.getUid());
String msg = "Your tags: (tag - messages)\n" +
tags.stream()
- .map(t -> String.format("\n*%s - %d", t.getName(), t.UsageCnt)).collect(Collectors.joining());
+ .map(t -> String.format("\n*%s - %d", t.getTag().getName(), t.getUsageCount())).collect(Collectors.joining());
return new ProtocolReply(msg, Optional.empty());
}
diff --git a/juick-server/src/main/java/com/juick/service/MessagesService.java b/juick-server/src/main/java/com/juick/service/MessagesService.java
index 5990f408..f7175967 100644
--- a/juick-server/src/main/java/com/juick/service/MessagesService.java
+++ b/juick-server/src/main/java/com/juick/service/MessagesService.java
@@ -32,10 +32,6 @@ public interface MessagesService {
User getMessageAuthor(int mid);
- List<com.juick.Tag> getMessageTags(int mid);
-
- List<Integer> getMessageTagsIDs(int mid);
-
List<String> getMessageRecommendations(int mid);
List<Integer> getAll(int visitorUid, int before);
diff --git a/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java b/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java
index 948e9137..9cf103a1 100644
--- a/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java
+++ b/juick-server/src/main/java/com/juick/service/MessagesServiceImpl.java
@@ -7,7 +7,6 @@ import com.juick.server.helpers.PrivacyOpts;
import com.juick.service.search.SearchService;
import com.juick.util.MessageUtils;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
@@ -346,31 +345,6 @@ public class MessagesServiceImpl extends BaseJdbcService implements MessagesServ
@Transactional(readOnly = true)
@Override
- public List<com.juick.Tag> 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)",
- new Object[]{mid},
- (rs, num) -> {
- com.juick.Tag t = new com.juick.Tag(StringEscapeUtils.unescapeHtml4(rs.getString(3)));
- t.TID = rs.getInt(1);
- t.SynonymID = rs.getInt(2);
- t.UsageCnt = rs.getInt(4);
- return t;
- });
- }
-
- @Transactional(readOnly = true)
- @Override
- public List<Integer> getMessageTagsIDs(final int mid) {
- return getJdbcTemplate().queryForList(
- "SELECT tag_id FROM messages_tags WHERE message_id = ?",
- new Object[]{mid},
- Integer.class);
- }
-
- @Transactional(readOnly = true)
- @Override
public List<String> getMessageRecommendations(final int mid) {
return getJdbcTemplate().queryForList(
"SELECT users.nick FROM favorites INNER JOIN users " +
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 bd915961..767c62fc 100644
--- a/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
+++ b/juick-server/src/main/java/com/juick/service/SubscriptionServiceImpl.java
@@ -23,9 +23,11 @@ import java.util.stream.Collectors;
public class SubscriptionServiceImpl extends BaseJdbcService implements SubscriptionService {
private final UserService userService;
private final MessagesService messagesService;
+ private final TagService tagService;
@Inject
- public SubscriptionServiceImpl(JdbcTemplate jdbcTemplate, UserService userService, MessagesService messagesService) {
+ public SubscriptionServiceImpl(JdbcTemplate jdbcTemplate, UserService userService,
+ MessagesService messagesService, TagService tagService) {
super(jdbcTemplate, null);
Assert.notNull(userService);
@@ -33,6 +35,9 @@ public class SubscriptionServiceImpl extends BaseJdbcService implements Subscrip
Assert.notNull(messagesService);
this.messagesService = messagesService;
+
+ Assert.notNull(tagService);
+ this.tagService = tagService;
}
@Transactional(readOnly = true)
@@ -60,7 +65,7 @@ public class SubscriptionServiceImpl extends BaseJdbcService implements Subscrip
.map(User::getUid)
.collect(Collectors.toList()));
- List<Integer> tags = messagesService.getMessageTagsIDs(mid);
+ List<Integer> tags = tagService.getMessageTagsIDs(mid);
if (!tags.isEmpty()) {
List<Integer> tagUsers = getNamedParameterJdbcTemplate().queryForList(
"SELECT st.suser_id FROM subscr_tags st " +
@@ -94,7 +99,7 @@ public class SubscriptionServiceImpl extends BaseJdbcService implements Subscrip
@Transactional(readOnly = true)
@Override
public List<User> getUsersSubscribedToUserRecommendations(final int uid, final int mid, final int muid) {
- List<Integer> tags = messagesService.getMessageTagsIDs(mid);
+ List<Integer> tags = tagService.getMessageTagsIDs(mid);
String query = "SELECT s.suser_id FROM subscr_users s WHERE s.user_id = :uid " +
" AND NOT EXISTS (SELECT 1 FROM bl_users b WHERE b.bl_user_id = :muid and b.user_id = s.user_id) " +
diff --git a/juick-server/src/main/java/com/juick/service/TagService.java b/juick-server/src/main/java/com/juick/service/TagService.java
index 03dcd842..2fcc7097 100644
--- a/juick-server/src/main/java/com/juick/service/TagService.java
+++ b/juick-server/src/main/java/com/juick/service/TagService.java
@@ -1,6 +1,7 @@
package com.juick.service;
import com.juick.Tag;
+import com.juick.server.helpers.TagStats;
import java.util.Collection;
import java.util.List;
@@ -19,13 +20,18 @@ public interface TagService {
int createTag(String name);
- List<com.juick.Tag> getUserTagsAll(int uid);
+ List<TagStats> getUserTagStats(int uid);
List<String> getUserBLTags(int uid);
List<String> getPopularTags();
+ List<TagStats> getTagStats();
List<Tag> updateTags(int mid, Collection<Tag> newTags);
List<Tag> fromString(String txt, boolean tagsOnly);
+
+ List<TagStats> getMessageTags(int mid);
+
+ List<Integer> getMessageTagsIDs(int mid);
}
diff --git a/juick-server/src/main/java/com/juick/service/TagServiceImpl.java b/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
index 8f420ba9..23b8d2a9 100644
--- a/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
+++ b/juick-server/src/main/java/com/juick/service/TagServiceImpl.java
@@ -1,11 +1,13 @@
package com.juick.service;
import com.juick.Tag;
+import com.juick.server.helpers.TagStats;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
+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;
@@ -14,9 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.inject.Inject;
-import java.sql.PreparedStatement;
-import java.sql.Statement;
-import java.sql.Types;
+import java.sql.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -132,19 +132,27 @@ public class TagServiceImpl extends BaseJdbcService implements TagService {
return holder.getKey().intValue();
}
+ private class TagStatsMapper implements RowMapper<TagStats> {
+
+ @Override
+ public TagStats mapRow(ResultSet rs, int rowNum) throws SQLException {
+ Tag t = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(1)));
+ TagStats s = new TagStats();
+ s.setTag(t);
+ s.setUsageCount(rs.getInt(2));
+ return s;
+ }
+ }
+
@Transactional(readOnly = true)
@Override
- public List<com.juick.Tag> getUserTagsAll(final int uid) {
+ 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",
- (rs, rowNum) -> {
- Tag t = new Tag(StringEscapeUtils.unescapeHtml4(rs.getString(1)));
- t.UsageCnt = rs.getInt(2);
- return t;
- },
+ new TagStatsMapper(),
uid);
}
@@ -167,13 +175,24 @@ public class TagServiceImpl extends BaseJdbcService implements TagService {
.collect(Collectors.toList());
}
+ @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 = messagesService.getMessageTags(mid);
+ List<TagStats> currentTags = getMessageTags(mid);
if (CollectionUtils.isEmpty(newTags))
- return currentTags;
+ return currentTags.stream().map(TagStats::getTag).collect(Collectors.toList());
List<Integer> ids = new ArrayList<>(newTags.size());
List<Object[]> params = new ArrayList<>(newTags.size());
@@ -198,7 +217,7 @@ public class TagServiceImpl extends BaseJdbcService implements TagService {
.addValue("mid", mid)
.addValue("ids", ids));
- return messagesService.getMessageTags(mid);
+ return getMessageTags(mid).stream().map(TagStats::getTag).collect(Collectors.toList());
}
@Override
@@ -219,4 +238,29 @@ public class TagServiceImpl extends BaseJdbcService implements TagService {
}
return Collections.emptyList();
}
+
+ @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(StringEscapeUtils.unescapeHtml4(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);
+ }
}
diff --git a/juick-www/src/main/java/com/juick/www/NewMessage.java b/juick-www/src/main/java/com/juick/www/NewMessage.java
index c066c5b3..ca783779 100644
--- a/juick-www/src/main/java/com/juick/www/NewMessage.java
+++ b/juick-www/src/main/java/com/juick/www/NewMessage.java
@@ -19,6 +19,7 @@ package com.juick.www;
import com.juick.Tag;
import com.juick.server.*;
+import com.juick.server.helpers.TagStats;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.math.NumberUtils;
@@ -100,16 +101,16 @@ public class NewMessage {
}
void printUserTags(JdbcTemplate sql, PrintWriter out, com.juick.User visitor) {
- List<Tag> tags = TagQueries.getUserTagsAll(sql, visitor.getUid());
+ List<TagStats> tags = TagQueries.getTagsStats(sql, visitor.getUid());
if (tags.isEmpty()) {
return;
}
- int min = tags.get(0).UsageCnt;
- int max = tags.get(0).UsageCnt;
+ int min = tags.get(0).getUsageCount();
+ int max = tags.get(0).getUsageCount();
for (int i = 1; i < tags.size(); i++) {
- int usagecnt = tags.get(i).UsageCnt;
+ int usagecnt = tags.get(i).getUsageCount();
if (usagecnt < min) {
min = usagecnt;
}
@@ -126,12 +127,12 @@ public class NewMessage {
}
String taglink = "";
try {
- taglink = "<a onclick=\"return addTag('" + StringEscapeUtils.escapeHtml4(tags.get(i).getName()) + "')\" href=\"/" +
- visitor.getName() + "/?tag=" + URLEncoder.encode(tags.get(i).getName(), "utf-8") +
- "\" title=\"" + tags.get(i).UsageCnt + "\">" + StringEscapeUtils.escapeHtml4(tags.get(i).getName()) + "</a>";
+ taglink = "<a onclick=\"return addTag('" + StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName()) + "')\" href=\"/" +
+ visitor.getName() + "/?tag=" + URLEncoder.encode(tags.get(i).getTag().getName(), "utf-8") +
+ "\" title=\"" + tags.get(i).getUsageCount() + "\">" + StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName()) + "</a>";
} catch (UnsupportedEncodingException e) {
}
- int usagecnt = tags.get(i).UsageCnt;
+ int usagecnt = tags.get(i).getUsageCount();
if (usagecnt <= max / 5 + min) {
out.print("<span style=\"font-size: small\">" + taglink + "</span>");
} else if (usagecnt <= max / 5 * 2 + min) {
diff --git a/juick-www/src/main/java/com/juick/www/PageTemplates.java b/juick-www/src/main/java/com/juick/www/PageTemplates.java
index 180e852f..504a4b8b 100644
--- a/juick-www/src/main/java/com/juick/www/PageTemplates.java
+++ b/juick-www/src/main/java/com/juick/www/PageTemplates.java
@@ -18,10 +18,10 @@
package com.juick.www;
import com.juick.Message;
-import com.juick.Tag;
import com.juick.server.MessagesQueries;
import com.juick.server.TagQueries;
import com.juick.server.UserQueries;
+import com.juick.server.helpers.TagStats;
import com.juick.util.MessageUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
@@ -185,13 +185,13 @@ public class PageTemplates {
out.println("</body></html>");
}
- public static String formatTags(List<Tag> tags) {
+ public static String formatTags(List<TagStats> tags) {
String ret = "";
- for (Tag tag : tags) {
- String tagName = StringEscapeUtils.escapeHtml4(tag.getName());
+ for (TagStats tag : tags) {
+ String tagName = StringEscapeUtils.escapeHtml4(tag.getTag().getName());
try {
- ret += "<a href=\"/tag/" + URLEncoder.encode(tag.getName(), "utf-8") + "\"";
- if (tag.UsageCnt < 2) {
+ ret += "<a href=\"/tag/" + URLEncoder.encode(tag.getTag().getName(), "utf-8") + "\"";
+ if (tag.getUsageCount() < 2) {
ret += " rel=\"nofollow\"";
}
ret += ">" + tagName + "</a>";
@@ -301,7 +301,7 @@ public class PageTemplates {
for (Message msg : msgs) {
- List<Tag> tags = MessagesQueries.getMessageTags(sql, msg.getMid());
+ List<TagStats> tags = MessagesQueries.getMessageTags(sql, msg.getMid());
String tagsStr = formatTags(tags);
if (msg.ReadOnly) {
tagsStr += "<a>readonly</a>";
diff --git a/juick-www/src/main/java/com/juick/www/User.java b/juick-www/src/main/java/com/juick/www/User.java
index 3cc38b37..088fb004 100644
--- a/juick-www/src/main/java/com/juick/www/User.java
+++ b/juick-www/src/main/java/com/juick/www/User.java
@@ -17,10 +17,10 @@
*/
package com.juick.www;
-import com.juick.Tag;
import com.juick.server.MessagesQueries;
import com.juick.server.TagQueries;
import com.juick.server.UserQueries;
+import com.juick.server.helpers.TagStats;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
+import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
@@ -323,22 +324,22 @@ public class User {
}
public static String pageUserTags(JdbcTemplate sql, com.juick.User user, com.juick.User visitor, int cnt) {
- List<Tag> tags = TagQueries.getUserTagsAll(sql, user.getUid()).stream()
- .sorted((e1, e2) -> Integer.compare(e2.UsageCnt, e1.UsageCnt)).collect(Collectors.toList());
- int maxUsageCnt = tags.stream().map(t -> t.UsageCnt).max(Integer::max).orElse(0);
+ List<TagStats> tags = TagQueries.getTagsStats(sql, user.getUid()).stream()
+ .sorted((e1, e2) -> Integer.compare(e2.getUsageCount(), e1.getUsageCount())).collect(Collectors.toList());
+ int maxUsageCnt = tags.stream().map(TagStats::getUsageCount).max(Comparator.naturalOrder()).orElse(0);
String ret = "";
int count = cnt > 0 ? Math.min(tags.size(), cnt) : tags.size();
for (int i = 0; i < count; i++) {
- String tag = StringEscapeUtils.escapeHtml4(tags.get(i).getName());
+ String tag = StringEscapeUtils.escapeHtml4(tags.get(i).getTag().getName());
try {
- tag = "<a href=\"./?tag=" + URLEncoder.encode(tags.get(i).getName(), "UTF-8") + "\" title=\""
- + tags.get(i).UsageCnt + "\" rel=\"nofollow\">" + tag + "</a>";
+ tag = "<a href=\"./?tag=" + URLEncoder.encode(tags.get(i).getTag().getName(), "UTF-8") + "\" title=\""
+ + tags.get(i).getUsageCount() + "\" rel=\"nofollow\">" + tag + "</a>";
} catch (UnsupportedEncodingException e) {
}
- if (tags.get(i).UsageCnt > maxUsageCnt / 3 * 2) {
+ if (tags.get(i).getUsageCount() > maxUsageCnt / 3 * 2) {
ret += "<big>" + tag + "</big> ";
- } else if (tags.get(i).UsageCnt > maxUsageCnt / 3) {
+ } else if (tags.get(i).getUsageCount() > maxUsageCnt / 3) {
ret += "<small>" + tag + "</small> ";
} else {
ret += tag + " ";
diff --git a/juick-www/src/main/java/com/juick/www/UserThread.java b/juick-www/src/main/java/com/juick/www/UserThread.java
index d94f2156..79ec42fc 100644
--- a/juick-www/src/main/java/com/juick/www/UserThread.java
+++ b/juick-www/src/main/java/com/juick/www/UserThread.java
@@ -18,19 +18,19 @@
package com.juick.www;
import com.juick.Message;
-import com.juick.Tag;
import com.juick.server.MessagesQueries;
import com.juick.server.UserQueries;
+import com.juick.server.helpers.TagStats;
import com.juick.util.MessageUtils;
import org.springframework.jdbc.core.JdbcTemplate;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
/**
*
@@ -95,7 +95,7 @@ public class UserThread {
public static com.juick.Message printMessage(PrintWriter out, JdbcTemplate sql, com.juick.Message msg, com.juick.User visitor) {
msg.VisitorCanComment = visitor.getUid() > 0;
- List<Tag> tags = MessagesQueries.getMessageTags(sql, msg.getMid());
+ List<TagStats> tags = MessagesQueries.getMessageTags(sql, msg.getMid());
String tagsStr = PageTemplates.formatTags(tags);
if (msg.ReadOnly) {
tagsStr += "<a>readonly</a>";
diff --git a/src/test/java/com/juick/tests/ApiTests.java b/src/test/java/com/juick/tests/ApiTests.java
index 727447e0..1d777d62 100644
--- a/src/test/java/com/juick/tests/ApiTests.java
+++ b/src/test/java/com/juick/tests/ApiTests.java
@@ -11,6 +11,7 @@ import com.juick.server.MessagesQueries;
import com.juick.server.SubscriptionsQueries;
import com.juick.server.TagQueries;
import com.juick.server.UserQueries;
+import com.juick.server.helpers.TagStats;
import com.juick.server.protocol.JuickProtocol;
import com.juick.server.protocol.ProtocolReply;
import com.juick.www.PageTemplates;
@@ -26,6 +27,7 @@ import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -93,11 +95,13 @@ public class ApiTests {
MessagesQueries.deleteMessage(jdbc, user_id, mid2);
String htmlTagName = ">_<";
Tag htmlTag = TagQueries.getTag(jdbc, htmlTagName, true);
+ TagStats htmlTagStats = new TagStats();
+ htmlTagStats.setTag(htmlTag);
String dbTagName = jdbc.queryForObject("select name from tags where name=?", String.class, StringEscapeUtils.escapeHtml4(htmlTagName));
assertNotEquals("db tags should be escaped", dbTagName, htmlTag.getName());
assertEquals("object tags should unescaped", htmlTag.getName(), StringEscapeUtils.unescapeHtml4(dbTagName));
assertEquals("template should encode escaped tag in url and show escaped tag in name",
- "<a href=\"/tag/%3E_%3C\" rel=\"nofollow\">&gt;_&lt;</a>", PageTemplates.formatTags(new ArrayList<Tag>() {{ add(htmlTag); }} ));
+ "<a href=\"/tag/%3E_%3C\" rel=\"nofollow\">&gt;_&lt;</a>", PageTemplates.formatTags(Collections.singletonList(htmlTagStats)));
}
@Test
@@ -115,7 +119,7 @@ public class ApiTests {
assertEquals("text should match", "yoyo",
MessagesQueries.getMessage(jdbc, mid).getText());
assertEquals("tag should match", "yo",
- MessagesQueries.getMessageTags(jdbc, mid).get(0).getName());
+ MessagesQueries.getMessageTags(jdbc, mid).get(0).getTag().getName());
assertNotEquals("should not be error", "Error", protocol.getReply(user, "#" + mid).getDescription());
assertEquals("should be PONG", "PONG", protocol.getReply(user, " ping \n ").getDescription());
int readerUid = UserQueries.createUser(jdbc, "dummyReader", "dummySecret");