Skip to content

Commit 93ecb1b

Browse files
committed
Implement a page with list of countries.
Fix #103
1 parent 94b2697 commit 93ecb1b

File tree

16 files changed

+190
-1
lines changed

16 files changed

+190
-1
lines changed

src/main/java/ru/mystamps/web/Url.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public final class Url {
6363

6464
public static final String ADD_COUNTRY_PAGE = "/country/add";
6565
public static final String INFO_COUNTRY_PAGE = "/country/{id}/{slug}";
66+
public static final String LIST_COUNTRIES_PAGE = "/country/list";
6667

6768
public static final String INFO_COLLECTION_PAGE = "/collection/{id}/{slug}";
6869

@@ -111,6 +112,7 @@ public static Map<String, String> asMap(boolean serveContentFromSingleHost) {
111112
map.put("LIST_CATEGORIES_PAGE", LIST_CATEGORIES_PAGE);
112113
map.put("ADD_COUNTRY_PAGE", ADD_COUNTRY_PAGE);
113114
map.put("INFO_COUNTRY_PAGE", INFO_COUNTRY_PAGE);
115+
map.put("LIST_COUNTRIES_PAGE", LIST_COUNTRIES_PAGE);
114116
map.put("INFO_COLLECTION_PAGE", INFO_COLLECTION_PAGE);
115117

116118
if (serveContentFromSingleHost) {

src/main/java/ru/mystamps/web/controller/CountryController.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,5 +100,11 @@ public String showInfo(@PathVariable("id") Country country, Model model, Locale
100100
return "country/info";
101101
}
102102

103+
@RequestMapping(Url.LIST_COUNTRIES_PAGE)
104+
public void list(Model model, Locale userLocale) {
105+
String lang = LocaleUtils.getLanguageOrNull(userLocale);
106+
model.addAttribute("countries", countryService.findAllAsLinkEntities(lang));
107+
}
108+
103109
}
104110

src/main/java/ru/mystamps/web/dao/JdbcCountryDao.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.util.Map;
2121

22+
import ru.mystamps.web.service.dto.LinkEntityDto;
2223
import ru.mystamps.web.service.dto.SelectEntityDto;
2324

2425
public interface JdbcCountryDao {
@@ -28,4 +29,5 @@ public interface JdbcCountryDao {
2829
long countCountriesOfCollection(Integer collectionId);
2930
Map<String, Integer> getStatisticsOf(Integer collectionId, String lang);
3031
Iterable<SelectEntityDto> findAllAsSelectEntries(String lang);
32+
Iterable<LinkEntityDto> findAllAsLinkEntities(String lang);
3133
}

src/main/java/ru/mystamps/web/dao/impl/JdbcCountryDaoImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@
3030
import lombok.RequiredArgsConstructor;
3131

3232
import ru.mystamps.web.dao.JdbcCountryDao;
33+
import ru.mystamps.web.service.dto.LinkEntityDto;
3334
import ru.mystamps.web.service.dto.SelectEntityDto;
3435

3536
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
3637
@RequiredArgsConstructor
3738
public class JdbcCountryDaoImpl implements JdbcCountryDao {
3839

40+
private static final RowMapper<LinkEntityDto> LINK_ENTITY_DTO_ROW_MAPPER =
41+
new LinkEntityDtoRowMapper();
42+
3943
private static final RowMapper<Pair<String, Integer>> NAME_AND_COUNTER_ROW_MAPPER =
4044
new StringIntegerPairRowMapper("name", "counter");
4145

@@ -62,6 +66,9 @@ public class JdbcCountryDaoImpl implements JdbcCountryDao {
6266
@Value("${country.find_all_countries_names_with_ids}")
6367
private String findCountriesNamesWithIdsSql;
6468

69+
@Value("${country.find_all_countries_names_with_slug}")
70+
private String findCountriesNamesWithSlugSql;
71+
6572
@Override
6673
public long countAll() {
6774
return jdbcTemplate.queryForObject(
@@ -137,4 +144,13 @@ public Iterable<SelectEntityDto> findAllAsSelectEntries(String lang) {
137144
return result;
138145
}
139146

147+
@Override
148+
public Iterable<LinkEntityDto> findAllAsLinkEntities(String lang) {
149+
return jdbcTemplate.query(
150+
findCountriesNamesWithSlugSql,
151+
Collections.singletonMap("lang", lang),
152+
LINK_ENTITY_DTO_ROW_MAPPER
153+
);
154+
}
155+
140156
}

src/main/java/ru/mystamps/web/service/CountryService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import ru.mystamps.web.entity.Collection;
2323
import ru.mystamps.web.entity.User;
2424
import ru.mystamps.web.service.dto.AddCountryDto;
25+
import ru.mystamps.web.service.dto.LinkEntityDto;
2526
import ru.mystamps.web.service.dto.SelectEntityDto;
2627
import ru.mystamps.web.service.dto.UrlEntityDto;
2728

2829
public interface CountryService {
2930
UrlEntityDto add(AddCountryDto dto, User user);
3031
Iterable<SelectEntityDto> findAll(String lang);
32+
Iterable<LinkEntityDto> findAllAsLinkEntities(String lang);
3133
long countAll();
3234
long countCountriesOf(Collection collection);
3335
long countByName(String name);

src/main/java/ru/mystamps/web/service/CountryServiceImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import ru.mystamps.web.entity.User;
3838
import ru.mystamps.web.dao.CountryDao;
3939
import ru.mystamps.web.service.dto.AddCountryDto;
40+
import ru.mystamps.web.service.dto.LinkEntityDto;
4041
import ru.mystamps.web.service.dto.SelectEntityDto;
4142
import ru.mystamps.web.service.dto.UrlEntityDto;
4243
import ru.mystamps.web.util.SlugUtils;
@@ -87,6 +88,12 @@ public Iterable<SelectEntityDto> findAll(String lang) {
8788
return jdbcCountryDao.findAllAsSelectEntries(lang);
8889
}
8990

91+
@Override
92+
@Transactional(readOnly = true)
93+
public Iterable<LinkEntityDto> findAllAsLinkEntities(String lang) {
94+
return jdbcCountryDao.findAllAsLinkEntities(lang);
95+
}
96+
9097
@Override
9198
@Transactional(readOnly = true)
9299
public long countAll() {

src/main/java/ru/mystamps/web/support/togglz/Features.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ public enum Features implements Feature {
5454

5555
@Label("Show link to list of categories on index page")
5656
@EnabledByDefault
57-
LIST_CATEGORIES;
57+
LIST_CATEGORIES,
58+
59+
@Label("Show link to list of countries on index page")
60+
@EnabledByDefault
61+
LIST_COUNTRIES;
5862

5963
public boolean isActive() {
6064
return FeatureContext.getFeatureManager().isActive(this);

src/main/resources/ru/mystamps/i18n/Messages.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ t_write_email = Write e-mail
3131
t_index_title = create your own virtual collection!
3232
t_you_may = You may
3333
t_show_categories_list = show list of categories
34+
t_show_countries_list = show list of countries
3435
t_in_db = In our database
3536
t_categories_amount = Amount of categories
3637
t_countries_amount = Amount of countries
@@ -127,6 +128,9 @@ t_add_country_ucfirst = Add country
127128
t_country_info = Country info
128129
t_country_just_added = Country has been added.<br />Now you could <a href="{0}" class="alert-link">proceed with creating series</a>.
129130

131+
# country/list.html
132+
t_country_list = country list
133+
130134
# collection/info.html
131135
t_collection_of = {0}'s collection
132136
t_collection_just_added = Series has been added to your collection

src/main/resources/ru/mystamps/i18n/Messages_ru.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ t_write_email = Написать письмо
3131
t_index_title = создай свою виртуальную коллекцию!
3232
t_you_may = Вы можете
3333
t_show_categories_list = посмотреть список категорий
34+
t_show_countries_list = посмотреть список стран
3435
t_in_db = В нашей базе
3536
t_categories_amount = Категорий
3637
t_countries_amount = Стран
@@ -127,6 +128,9 @@ t_add_country_ucfirst = Добавить страну
127128
t_country_info = Информация о стране
128129
t_country_just_added = Страна добавлена. Теперь вы можете <a href="{0}" class="alert-link">создать серию</a>.
129130

131+
# country/list.html
132+
t_country_list = список стран
133+
130134
# collection/info.html
131135
t_collection_of = Коллекция пользователя {0}
132136
t_collection_just_added = Серия добавлена в вашу коллекцию

src/main/resources/sql/country_dao_queries.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,10 @@ country.find_all_countries_names_with_ids = \
3535
, c.id \
3636
FROM countries c \
3737
ORDER BY CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END
38+
39+
country.find_all_countries_names_with_slug = \
40+
SELECT CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END AS name \
41+
, c.slug \
42+
, c.id \
43+
FROM countries c \
44+
ORDER BY CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!DOCTYPE html>
2+
<html xmlns="http://www.w3.org/1999/xhtml"
3+
xmlns:th="http://www.thymeleaf.org"
4+
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
5+
<head>
6+
<meta charset="utf-8" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
9+
<title th:text="|MyStamps: #{t_country_list}|">MyStamps: country list</title>
10+
<link rel="shortcut icon" type="image/x-icon" href="../../../favicon.ico" th:href="${FAVICON_ICO}" />
11+
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" th:href="${BOOTSTRAP_CSS}" />
12+
<link rel="stylesheet" href="../../static/styles/main.css" th:href="${MAIN_CSS}" />
13+
</head>
14+
<body lang="en" th:lang="${#locale.language == 'ru' ? 'ru' : 'en'}">
15+
<div class="container-fluid">
16+
<div class="row" id="header">
17+
<div id="logo" class="col-sm-10">
18+
<a href="../site/index.html" th:href="'/'" th:text="#{t_my_stamps}">My stamps</a>
19+
</div>
20+
21+
<div id="user_bar" class="col-sm-2">
22+
<ul class="list-unstyled">
23+
<!--/*/
24+
<li sec:authorize="isAuthenticated()">
25+
<i class="glyphicon glyphicon-user"></i>
26+
<a sec:authentication="principal.user.name"
27+
href="../collection/info.html"
28+
title="Open my collection"
29+
th:title="#{t_open_my_collection}"
30+
th:href="@{${INFO_COLLECTION_PAGE}(id=${#authentication.principal.user.collection.id},slug=${#authentication.principal.user.collection.slug})}">
31+
John Doe
32+
</a>
33+
</li>
34+
/*/-->
35+
<li sec:authorize="isAnonymous()">
36+
<a href="../account/auth.html" th:href="@{${AUTHENTICATION_PAGE}}" th:text="#{t_enter}">Sign in</a>
37+
</li>
38+
<!--/*/
39+
<li sec:authorize="isAuthenticated()">
40+
<form id="LogoutForm" method="get" action="../site/index.html" class="no-margin" th:method="post" th:action="@{${LOGOUT_PAGE}}">
41+
<i class="glyphicon glyphicon-share"></i>&nbsp;<input type="submit" value="Sign out" class="btn btn-link no-padding" th:value="#{t_logout}" />
42+
</form>
43+
</li>
44+
/*/-->
45+
<li sec:authorize="isAnonymous()">
46+
<a href="../account/register.html" th:href="@{${REGISTRATION_PAGE}}" th:text="#{t_register}">Register</a>
47+
</li>
48+
</ul>
49+
</div>
50+
</div>
51+
<div class="row">
52+
<div id="content" class="col-sm-12" th:with="country_list=#{t_country_list}">
53+
<h3 th:text="${#strings.capitalize(country_list)}">
54+
Country list
55+
</h3>
56+
57+
<ul th:if="${not #lists.isEmpty(countries)}">
58+
<li th:each="country : ${countries}">
59+
<a href="../country/info.html" th:href="@{${INFO_COUNTRY_PAGE}(id=${country.id},slug=${country.slug})}" th:text="${country.name}">Italy</a>
60+
</li>
61+
</ul>
62+
</div>
63+
</div>
64+
<div class="row">
65+
<footer class="col-sm-12 text-right">
66+
<i class="glyphicon glyphicon-envelope"></i>
67+
<a href="mailto:slava.semushin@gmail.com" title="Write e-mail" th:href="|mailto:#{t_site_author_email}|" th:title="#{t_write_email}" th:text="#{t_site_author_name}">Slava Semushin</a>, 2009-2015
68+
</footer>
69+
</div>
70+
</div>
71+
72+
<!-- Placed at the end of the document so the pages load faster -->
73+
<script src="http://yandex.st/jquery/1.9.1/jquery.min.js" th:src="${JQUERY_JS}"></script>
74+
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" th:src="${BOOTSTRAP_JS}"></script>
75+
</body>
76+
</html>

src/main/webapp/WEB-INF/views/site/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@
5656
<li togglz:active="LIST_CATEGORIES">
5757
<a th:href="@{${LIST_CATEGORIES_PAGE}}" th:text="#{t_show_categories_list}" href="../category/list.html">show list of categories</a>
5858
</li>
59+
<li togglz:active="LIST_COUNTRIES">
60+
<a th:href="@{${LIST_COUNTRIES_PAGE}}" th:text="#{t_show_countries_list}" href="../country/list.html">show list of countries</a>
61+
</li>
5962
<li sec:authorize="hasAuthority('CREATE_SERIES')">
6063
<a th:href="@{${ADD_SERIES_PAGE}}" th:text="#{t_add_series}" href="../series/add.html">add stamp series</a>
6164
</li>

src/test/groovy/ru/mystamps/web/service/CountryServiceImplTest.groovy

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import ru.mystamps.web.entity.Country
2626
import ru.mystamps.web.entity.Collection
2727
import ru.mystamps.web.entity.User
2828
import ru.mystamps.web.model.AddCountryForm
29+
import ru.mystamps.web.service.dto.LinkEntityDto
2930
import ru.mystamps.web.service.dto.SelectEntityDto
3031
import ru.mystamps.web.service.dto.UrlEntityDto
3132
import ru.mystamps.web.tests.DateUtils
@@ -222,6 +223,40 @@ class CountryServiceImplTest extends Specification {
222223
null | _
223224
}
224225

226+
//
227+
// Tests for findAllAsLinkEntities(String)
228+
//
229+
230+
def "findAllAsLinkEntities(String) should call dao"() {
231+
given:
232+
LinkEntityDto country1 = new LinkEntityDto(1, 'first-country', 'First Country')
233+
and:
234+
LinkEntityDto country2 = new LinkEntityDto(2, 'second-country', 'Second Country')
235+
and:
236+
List<LinkEntityDto> expectedCountries = [ country1, country2 ]
237+
and:
238+
jdbcCountryDao.findAllAsLinkEntities(_ as String) >> expectedCountries
239+
when:
240+
Iterable<LinkEntityDto> resultCountries = service.findAllAsLinkEntities('de')
241+
then:
242+
resultCountries == expectedCountries
243+
}
244+
245+
@Unroll
246+
def "findAllAsLinkEntities(String) should pass language '#expectedLanguage' to dao"(String expectedLanguage) {
247+
when:
248+
service.findAllAsLinkEntities(expectedLanguage)
249+
then:
250+
1 * jdbcCountryDao.findAllAsLinkEntities({ String language ->
251+
assert language == expectedLanguage
252+
return true
253+
})
254+
where:
255+
expectedLanguage | _
256+
'ru' | _
257+
null | _
258+
}
259+
225260
//
226261
// Tests for countAll()
227262
//

src/test/java/ru/mystamps/web/tests/cases/WhenAdminAtIndexPage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ public void shouldExistsLinkForAddingCountries() {
7777
.isTrue();
7878
}
7979

80+
@Test(groups = "misc", dependsOnGroups = "std")
81+
public void shouldExistsLinkForListingCountries() {
82+
assertThat(page.linkWithLabelExists(tr("t_show_countries_list")))
83+
.overridingErrorMessage("should exists link to page for listing countries")
84+
.isTrue();
85+
}
86+
8087
@Test(groups = "misc", dependsOnGroups = "std")
8188
public void shouldExistsLinkForAddingCategories() {
8289
assertThat(page.linkWithLabelExists(tr("t_create_category")))

src/test/java/ru/mystamps/web/tests/cases/WhenAnonymousUserAtIndexPage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ public void shouldExistsLinkForListingCategories() {
5555
.isTrue();
5656
}
5757

58+
@Test(groups = "misc", dependsOnGroups = "std")
59+
public void shouldExistsLinkForListingCountries() {
60+
assertThat(page.linkWithLabelExists(tr("t_show_countries_list")))
61+
.overridingErrorMessage("should exists link to page for listing countries")
62+
.isTrue();
63+
}
64+
5865
@Test(groups = "misc", dependsOnGroups = "std")
5966
public void linkForAddingSeriesShouldBeAbsent() {
6067
assertThat(page.linkWithLabelExists(tr("t_add_series")))

src/test/java/ru/mystamps/web/tests/cases/WhenUserAtIndexPage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ public void linkForAddingCountriesShouldBeAbsent() {
9191
.isFalse();
9292
}
9393

94+
@Test(groups = "misc", dependsOnGroups = "std")
95+
public void shouldExistsLinkForListingCountries() {
96+
assertThat(page.linkWithLabelExists(tr("t_show_countries_list")))
97+
.overridingErrorMessage("should exists link to page for listing countries")
98+
.isTrue();
99+
}
100+
94101
@Override
95102
protected void shouldHaveUserBar() {
96103
// Ignore this check because when user authenticated there is no links for login/register.

0 commit comments

Comments
 (0)