Skip to content

Guess Country #563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/main/java/ru/mystamps/web/Url.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public final class Url {
public static final String ADD_IMAGE_SERIES_PAGE = "/series/{id}/image";
public static final String SEARCH_SERIES_BY_CATALOG = "/series/search/by_catalog";

public static final String SUGGEST_SERIES_COUNTRY = "/suggest/series_country";

public static final String ADD_CATEGORY_PAGE = "/category/add";
public static final String LIST_CATEGORIES_PAGE = "/category/list";
public static final String INFO_CATEGORY_PAGE = "/category/{slug}";
Expand All @@ -77,7 +79,7 @@ public final class Url {
public static final String ADD_SERIES_WITH_COUNTRY_PAGE = "/series/add/country/{slug}";

// MUST be updated when any of our resources were modified
public static final String RESOURCES_VERSION = "v0.3.0";
public static final String RESOURCES_VERSION = "v0.3.1";

// CheckStyle: ignore LineLength for next 4 lines
public static final String MAIN_CSS = "/static/" + RESOURCES_VERSION + "/styles/main.min.css";
Expand Down Expand Up @@ -125,6 +127,7 @@ public static Map<String, String> asMap(boolean serveContentFromSingleHost) {
map.put("INFO_SERIES_PAGE", INFO_SERIES_PAGE);
map.put("ADD_IMAGE_SERIES_PAGE", ADD_IMAGE_SERIES_PAGE);
map.put("SEARCH_SERIES_BY_CATALOG", SEARCH_SERIES_BY_CATALOG);
map.put("SUGGEST_SERIES_COUNTRY", SUGGEST_SERIES_COUNTRY);
map.put("ADD_CATEGORY_PAGE", ADD_CATEGORY_PAGE);
map.put("INFO_CATEGORY_PAGE", INFO_CATEGORY_PAGE);
map.put("LIST_CATEGORIES_PAGE", LIST_CATEGORIES_PAGE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,12 @@ public SiteController getSiteController() {
public SitemapController getSitemapController() {
return new SitemapController(servicesConfig.getSeriesService());
}


@Bean
public SuggestionController getSuggestionController() {
return new SuggestionController(
servicesConfig.getCountryService()
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2009-2017 Slava Semushin <slava.semushin@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package ru.mystamps.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import lombok.RequiredArgsConstructor;

import ru.mystamps.web.Url;
import ru.mystamps.web.controller.converter.annotation.CurrentUser;
import ru.mystamps.web.service.CountryService;

@Controller
@RequiredArgsConstructor
public class SuggestionController {

private final CountryService countryService;

/**
* @author John Shkarin
*/
@ResponseBody
@GetMapping(Url.SUGGEST_SERIES_COUNTRY)
public String suggestCountryForUser(@CurrentUser Integer currentUserId) {
return countryService.suggestCountryForUser(currentUserId);
}

}

3 changes: 3 additions & 0 deletions src/main/java/ru/mystamps/web/dao/CountryDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import ru.mystamps.web.dao.dto.AddCountryDbDto;
import ru.mystamps.web.dao.dto.LinkEntityDto;

@SuppressWarnings("PMD.TooManyMethods")
public interface CountryDao {
Integer add(AddCountryDbDto country);
long countAll();
Expand All @@ -35,4 +36,6 @@ public interface CountryDao {
List<Object[]> getStatisticsOf(Integer collectionId, String lang);
List<LinkEntityDto> findAllAsLinkEntities(String lang);
LinkEntityDto findOneAsLinkEntity(String slug, String lang);
String findLastCreatedByUser(Integer userId);
String findPopularCountryInCollection(Integer userId);
}
41 changes: 40 additions & 1 deletion src/main/java/ru/mystamps/web/dao/impl/JdbcCountryDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import ru.mystamps.web.dao.dto.LinkEntityDto;

@RequiredArgsConstructor
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods"})
public class JdbcCountryDao implements CountryDao {

private final NamedParameterJdbcTemplate jdbcTemplate;
Expand Down Expand Up @@ -76,6 +76,13 @@ public class JdbcCountryDao implements CountryDao {

@Value("${country.find_country_link_info_by_slug}")
private String findCountryLinkEntityBySlugSql;

@Value("${country.find_last_created_by_user}")
private String findLastCreatedByUserSql;

@SuppressWarnings("PMD.LongVariable")
@Value("${country.find_popular_country_from_user_collection}")
private String findPopularCountryInCollectionSql;

@Override
public Integer add(AddCountryDbDto country) {
Expand Down Expand Up @@ -206,5 +213,37 @@ public LinkEntityDto findOneAsLinkEntity(String slug, String lang) {
return null;
}
}

/**
* @author Shkarin John
*/
@Override
public String findLastCreatedByUser(Integer userId) {
try {
return jdbcTemplate.queryForObject(
findLastCreatedByUserSql,
Collections.singletonMap("created_by", userId),
String.class
);
} catch (EmptyResultDataAccessException ignored) {
return null;
}
}

/**
* @author Shkarin John
*/
@Override
public String findPopularCountryInCollection(Integer userId) {
try {
return jdbcTemplate.queryForObject(
findPopularCountryInCollectionSql,
Collections.singletonMap("user_id", userId),
String.class
);
} catch (EmptyResultDataAccessException ignored) {
return null;
}
}

}
2 changes: 2 additions & 0 deletions src/main/java/ru/mystamps/web/service/CountryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import ru.mystamps.web.dao.dto.LinkEntityDto;
import ru.mystamps.web.service.dto.AddCountryDto;

@SuppressWarnings("PMD.TooManyMethods")
public interface CountryService {
String add(AddCountryDto dto, Integer userId);
List<LinkEntityDto> findAllAsLinkEntities(String lang);
Expand All @@ -35,4 +36,5 @@ public interface CountryService {
long countAddedSince(Date date);
long countUntranslatedNamesSince(Date date);
List<Object[]> getStatisticsOf(Integer collectionId, String lang);
String suggestCountryForUser(Integer userId);
}
31 changes: 30 additions & 1 deletion src/main/java/ru/mystamps/web/service/CountryServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import ru.mystamps.web.util.SlugUtils;

@RequiredArgsConstructor
@SuppressWarnings("PMD.TooManyMethods")
public class CountryServiceImpl implements CountryService {
private static final Logger LOG = LoggerFactory.getLogger(CountryServiceImpl.class);

Expand Down Expand Up @@ -162,5 +163,33 @@ public List<Object[]> getStatisticsOf(Integer collectionId, String lang) {

return countryDao.getStatisticsOf(collectionId, lang);
}


/**
* @author Shkarin John
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize(HasAuthority.CREATE_SERIES)
public String suggestCountryForUser(Integer userId) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Этот метод должен вызывать сначала методы дао -- сначала findLastCreatedByUser(), а потом findPopularCountryInCollection().

Собственно, в сервисах должна быть вся логика, а дао методы должны быть как атомарные действия и следовать SRP (https://ru.wikipedia.org/wiki/Принцип_единственной_ответственности).

Validate.isTrue(userId != null, "User id must be non null");

String slug = countryDao.findLastCreatedByUser(userId);
if (slug != null) {
LOG.debug(
"Country {} has been suggested to user #{} as a recently created",
slug,
userId
);
return slug;
}

slug = countryDao.findPopularCountryInCollection(userId);
LOG.debug(
"Country {} has been suggested to user #{} as popular in his collection",
slug,
userId
);

return slug;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ protected void configure(HttpSecurity http) throws Exception {
.mvcMatchers(Url.ADD_COUNTRY_PAGE).hasAuthority(StringAuthority.CREATE_COUNTRY)
.mvcMatchers(Url.ADD_SERIES_PAGE).hasAuthority(StringAuthority.CREATE_SERIES)
.mvcMatchers(Url.SITE_EVENTS_PAGE).hasAuthority(StringAuthority.VIEW_SITE_EVENTS)
.mvcMatchers(Url.SUGGEST_SERIES_COUNTRY).hasAuthority(StringAuthority.CREATE_SERIES)
.regexMatchers(HttpMethod.POST, "/series/[0-9]+")
.hasAnyAuthority(
StringAuthority.UPDATE_COLLECTION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ public enum Features implements Feature {

@Label("View site events")
@EnabledByDefault
VIEW_SITE_EVENTS;
VIEW_SITE_EVENTS,

@Label("/series/add: show link with auto-suggestions")
@EnabledByDefault
INFO_COUNTRY_SERIES;

public boolean isActive() {
return FeatureContext.getFeatureManager().isActive(this);
Expand Down
20 changes: 19 additions & 1 deletion src/main/javascript/series/add.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// IMPORTANT:
// You have to update Url.RESOURCES_VERSION each time whenever you're modified this file!
//
function initPage() {
function initPage(suggestCountryUrl) {
$('#country').selectize();

$('.js-catalog-numbers').on('blur', function() {
Expand All @@ -21,4 +21,22 @@ function initPage() {
$('.js-with-tooltip').tooltip({
'placement': 'right'
});

if (suggestCountryUrl != null) {
$.get(suggestCountryUrl, function handleSuggestedCountry(slug) {
if (slug == "") {
return;
}

var country = $("#js-guess-country-link");
country.show();
country.click(function chooseSuggestedCountry() {
$(this).hide();

var select_country = $("#country").selectize();
var selectize = select_country[0].selectize;
selectize.setValue(slug);
});
});
}
}
1 change: 1 addition & 0 deletions src/main/resources/ru/mystamps/i18n/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ t_add_more_images_hint = Later you will be able to add additional images
t_not_chosen = Not chosen
t_create_category_hint = You can also <a tabindex="-1" href="{0}">add a new category</a>
t_create_country_hint = You can also <a tabindex="-1" href="{0}">add a new country</a>
t_guess_country = Guess a country

# series/info.html
t_series_info = Info about series
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ t_add_more_images_hint = Вы сможете добавить дополните
t_not_chosen = Не выбрана
t_create_category_hint = Вы также можете <a tabindex="-1" href="{0}">добавить новую категорию</a>
t_create_country_hint = Вы также можете <a tabindex="-1" href="{0}">добавить новую страну</a>
t_guess_country = Угадать страну

# series/info.html
t_series_info = Информация о серии
Expand Down
20 changes: 20 additions & 0 deletions src/main/resources/sql/country_dao_queries.properties
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,23 @@ country.find_country_link_info_by_slug = \
FROM countries c \
WHERE c.slug = :slug \
ORDER BY CASE WHEN 'ru' = :lang THEN COALESCE(c.name_ru, c.name) ELSE c.name END

country.find_last_created_by_user = \
SELECT c.slug \
FROM series s \
JOIN countries c \
ON c.id = s.country_id \
WHERE s.created_by = :created_by \
ORDER BY s.created_at DESC \
LIMIT 1

country.find_popular_country_from_user_collection = \
SELECT co.slug \
FROM collections c \
JOIN collections_series cs ON c.id = cs.collection_id \
JOIN series s ON s.id = cs.series_id \
JOIN countries co ON co.id = s.country_id \
WHERE c.user_id = :user_id \
GROUP BY co.id \
ORDER BY COUNT(*) DESC \
LIMIT 1
6 changes: 5 additions & 1 deletion src/main/webapp/WEB-INF/views/series/add.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<link rel="stylesheet" href="../../static/styles/main.css" th:href="${MAIN_CSS}" />
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.12.3/css/selectize.bootstrap3.min.css" th:href="${SELECTIZE_CSS}" />
</head>
<body onload="initPage()">
<body th:onload="|initPage('@{${SUGGEST_SERIES_COUNTRY}}')|" onload="initPage(null)">
<div class="container-fluid">
<div class="row" id="header">
<div id="logo" class="col-sm-9 vcenter">
Expand Down Expand Up @@ -202,6 +202,10 @@ <h3 th:text="${#strings.capitalize(add_series)}">
<span id="country.errors" class="help-block" th:if="${#fields.hasErrors('country')}" th:each="error : ${#fields.errors('country')}" th:text="${error}"></span>
/*/-->
</div>

<small togglz:active="INFO_COUNTRY_SERIES">
<a tabindex="-1" th:text="#{t_guess_country}" href="javascript:void(0)" id="js-guess-country-link" th:style="'display: none; position: relative; top: 7px;'">Guess a country</a>
</small>
</div>

<div class="form-group form-group-sm" th:classappend="${#fields.hasErrors('quantity') ? 'has-error' : ''}">
Expand Down