Skip to content

Commit 97e27e3

Browse files
committed
Import series: redesign an import process to not use series creation page.
Fix #709
1 parent b42bd7f commit 97e27e3

File tree

15 files changed

+521
-129
lines changed

15 files changed

+521
-129
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ public static Map<String, String> asMap(boolean serveContentFromSingleHost) {
139139
map.put("ADD_IMAGE_SERIES_PAGE", ADD_IMAGE_SERIES_PAGE);
140140
map.put("SEARCH_SERIES_BY_CATALOG", SEARCH_SERIES_BY_CATALOG);
141141
map.put("REQUEST_IMPORT_SERIES_PAGE", REQUEST_IMPORT_SERIES_PAGE);
142+
map.put("REQUEST_IMPORT_PAGE", REQUEST_IMPORT_PAGE);
142143
map.put("SUGGEST_SERIES_COUNTRY", SUGGEST_SERIES_COUNTRY);
143144
map.put("ADD_CATEGORY_PAGE", ADD_CATEGORY_PAGE);
144145
map.put("INFO_CATEGORY_PAGE", INFO_CATEGORY_PAGE);

src/main/java/ru/mystamps/web/config/ControllersConfig.java

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ public SeriesController getSeriesController() {
114114
@Bean
115115
public SeriesImportController getSeriesImportController() {
116116
return new SeriesImportController(
117+
servicesConfig.getCategoryService(),
118+
servicesConfig.getCountryService(),
119+
servicesConfig.getSeriesService(),
117120
servicesConfig.getSeriesImportService(),
118121
eventPublisher
119122
);

src/main/java/ru/mystamps/web/config/MvcConfig.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,11 @@ public void addInterceptors(InterceptorRegistry registry) {
133133

134134
registry
135135
.addInterceptor(getDownloadImageInterceptor())
136-
.addPathPatterns(Url.ADD_SERIES_PAGE, Url.ADD_IMAGE_SERIES_PAGE);
136+
.addPathPatterns(
137+
Url.ADD_SERIES_PAGE,
138+
Url.ADD_IMAGE_SERIES_PAGE,
139+
Url.REQUEST_IMPORT_PAGE.replace("{id}", "*")
140+
);
137141
}
138142

139143
@Override

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

+3-14
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@
9393
@RequiredArgsConstructor
9494
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods", "PMD.GodClass" })
9595
public class SeriesController {
96+
97+
@SuppressWarnings("PMD.DefaultPackage")
98+
/* default */ static final Map<Integer, Integer> YEARS;
9699

97100
private static final Integer CURRENT_YEAR = Integer.valueOf(Year.now().getValue());
98101

99-
private static final Map<Integer, Integer> YEARS;
100-
101102
private final CategoryService categoryService;
102103
private final CollectionService collectionService;
103104
private final CountryService countryService;
@@ -131,8 +132,6 @@ protected void initSeriesSalesFormBinder(WebDataBinder binder) {
131132
public void showForm(
132133
@Category @RequestParam(name = "category", required = false) LinkEntityDto category,
133134
@Country @RequestParam(name = "country", required = false) LinkEntityDto country,
134-
@RequestParam(name = "image_url", required = false) String imageUrl,
135-
@RequestParam(name = "year", required = false) Integer year,
136135
Model model,
137136
Locale userLocale) {
138137

@@ -160,16 +159,6 @@ public void showForm(
160159
addSeriesForm.setCountry(country);
161160
}
162161

163-
if (imageUrl != null) {
164-
// in case user doesn't have permission to specify image URL,
165-
// field won't be shown on the page and this value will be ignored
166-
addSeriesForm.setImageUrl(imageUrl);
167-
}
168-
169-
if (year != null) {
170-
addSeriesForm.setYear(year);
171-
}
172-
173162
model.addAttribute("addSeriesForm", addSeriesForm);
174163
}
175164

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

+100-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package ru.mystamps.web.controller;
1919

2020
import java.io.IOException;
21+
import java.util.List;
2122
import java.util.Locale;
2223

2324
import javax.servlet.http.HttpServletResponse;
@@ -38,11 +39,19 @@
3839

3940
import ru.mystamps.web.Url;
4041
import ru.mystamps.web.controller.converter.annotation.CurrentUser;
42+
import ru.mystamps.web.controller.dto.FirstLevelCategoryDto;
43+
import ru.mystamps.web.controller.dto.ImportSeriesForm;
4144
import ru.mystamps.web.controller.dto.RequestImportForm;
4245
import ru.mystamps.web.controller.event.ImportRequestCreated;
46+
import ru.mystamps.web.dao.dto.CategoryDto;
4347
import ru.mystamps.web.dao.dto.ImportRequestDto;
48+
import ru.mystamps.web.dao.dto.LinkEntityDto;
4449
import ru.mystamps.web.dao.dto.ParsedDataDto;
50+
import ru.mystamps.web.service.CategoryService;
51+
import ru.mystamps.web.service.CountryService;
4552
import ru.mystamps.web.service.SeriesImportService;
53+
import ru.mystamps.web.service.SeriesService;
54+
import ru.mystamps.web.support.thymeleaf.GroupByParent;
4655
import ru.mystamps.web.util.LocaleUtils;
4756

4857
import static ru.mystamps.web.controller.ControllerUtils.redirectTo;
@@ -51,6 +60,9 @@
5160
@RequiredArgsConstructor
5261
public class SeriesImportController {
5362

63+
private final CategoryService categoryService;
64+
private final CountryService countryService;
65+
private final SeriesService seriesService;
5466
private final SeriesImportService seriesImportService;
5567
private final ApplicationEventPublisher eventPublisher;
5668

@@ -107,10 +119,97 @@ public String showRequestAndImportSeriesForm(
107119

108120
String lang = LocaleUtils.getLanguageOrNull(userLocale);
109121
ParsedDataDto parsedData = seriesImportService.getParsedData(requestId, lang);
110-
model.addAttribute("parsedData", parsedData);
122+
123+
ImportSeriesForm form = new ImportSeriesForm();
124+
form.setPerforated(Boolean.TRUE);
125+
126+
boolean hasParsedData = parsedData != null;
127+
if (hasParsedData) {
128+
if (parsedData.getCategory() != null) {
129+
form.setCategory(parsedData.getCategory());
130+
}
131+
if (parsedData.getCountry() != null) {
132+
form.setCountry(parsedData.getCountry());
133+
}
134+
if (parsedData.getImageUrl() != null) {
135+
form.setImageUrl(parsedData.getImageUrl());
136+
}
137+
if (parsedData.getIssueYear() != null) {
138+
form.setYear(parsedData.getIssueYear());
139+
}
140+
}
141+
142+
model.addAttribute("importSeriesForm", form);
143+
model.addAttribute("showForm", hasParsedData);
144+
145+
// @todo #709 SeriesImportController.showRequestAndImportSeriesForm():
146+
// extract a method for adding shared attributes to the model
147+
List<CategoryDto> categories =
148+
categoryService.findCategoriesWithParents(lang);
149+
List<FirstLevelCategoryDto> groupedCategories =
150+
GroupByParent.transformCategories(categories);
151+
model.addAttribute("categories", groupedCategories);
152+
153+
List<LinkEntityDto> countries = countryService.findAllAsLinkEntities(lang);
154+
model.addAttribute("countries", countries);
155+
156+
model.addAttribute("years", SeriesController.YEARS);
111157

112158
return "series/import/info";
113159
}
114160

161+
@PostMapping(Url.REQUEST_IMPORT_PAGE)
162+
public String processImportSeriesForm(
163+
@PathVariable("id") Integer requestId,
164+
Model model,
165+
@Valid ImportSeriesForm form,
166+
BindingResult result,
167+
@CurrentUser Integer currentUserId,
168+
Locale userLocale,
169+
HttpServletResponse response)
170+
throws IOException {
171+
172+
if (requestId == null) {
173+
response.sendError(HttpServletResponse.SC_NOT_FOUND);
174+
return null;
175+
}
176+
177+
ImportRequestDto request = seriesImportService.findById(requestId);
178+
if (request == null) {
179+
response.sendError(HttpServletResponse.SC_NOT_FOUND);
180+
return null;
181+
}
182+
183+
// @todo #709 SeriesImportController.processImportSeriesForm():
184+
// handle errors from interceptor
185+
186+
model.addAttribute("request", request);
187+
188+
String lang = LocaleUtils.getLanguageOrNull(userLocale);
189+
190+
ParsedDataDto parsedData = seriesImportService.getParsedData(requestId, lang);
191+
boolean hasParsedData = parsedData != null;
192+
model.addAttribute("showForm", hasParsedData);
193+
194+
List<CategoryDto> categories =
195+
categoryService.findCategoriesWithParents(lang);
196+
List<FirstLevelCategoryDto> groupedCategories =
197+
GroupByParent.transformCategories(categories);
198+
model.addAttribute("categories", groupedCategories);
199+
200+
List<LinkEntityDto> countries = countryService.findAllAsLinkEntities(lang);
201+
model.addAttribute("countries", countries);
202+
203+
model.addAttribute("years", SeriesController.YEARS);
204+
205+
if (result.hasErrors()) {
206+
return "series/import/info";
207+
}
208+
209+
Integer seriesId = seriesService.add(form, currentUserId, false);
210+
211+
return redirectTo(Url.INFO_SERIES_PAGE, seriesId);
212+
}
213+
115214
}
116215

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (C) 2009-2017 Slava Semushin <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
package ru.mystamps.web.controller.dto;
19+
20+
import java.math.BigDecimal;
21+
22+
import javax.validation.constraints.Max;
23+
import javax.validation.constraints.Min;
24+
import javax.validation.constraints.NotNull;
25+
26+
import org.hibernate.validator.constraints.URL;
27+
28+
import org.springframework.web.multipart.MultipartFile;
29+
30+
import lombok.Getter;
31+
import lombok.Setter;
32+
33+
import ru.mystamps.web.controller.converter.annotation.Category;
34+
import ru.mystamps.web.controller.converter.annotation.Country;
35+
import ru.mystamps.web.dao.dto.LinkEntityDto;
36+
import ru.mystamps.web.service.dto.AddSeriesDto;
37+
38+
import static ru.mystamps.web.validation.ValidationRules.MAX_STAMPS_IN_SERIES;
39+
import static ru.mystamps.web.validation.ValidationRules.MIN_RELEASE_YEAR;
40+
import static ru.mystamps.web.validation.ValidationRules.MIN_STAMPS_IN_SERIES;
41+
42+
@Getter
43+
@Setter
44+
public class ImportSeriesForm implements AddSeriesDto {
45+
46+
// @todo #709 /series/import/request/{id}(category): add integration test for required field
47+
@NotNull
48+
@Category
49+
private LinkEntityDto category;
50+
51+
@Country
52+
private LinkEntityDto country;
53+
54+
// @todo #709 /series/import/request/{id}(quantity): add integration test for required field
55+
// @todo #709 /series/import/request/{id}(quantity): add integration test for min value
56+
// @todo #709 /series/import/request/{id}(quantity): add integration test for max value
57+
@NotNull
58+
@Min(MIN_STAMPS_IN_SERIES)
59+
@Max(MAX_STAMPS_IN_SERIES)
60+
private Integer quantity;
61+
62+
// @todo #709 /series/import/request/{id}(perforated): add integration test for required field
63+
@NotNull
64+
private Boolean perforated;
65+
66+
// Name of this field must match with the value of DownloadImageInterceptor.URL_PARAMETER_NAME.
67+
// @todo #709 /series/import/request/{id}(imageUrl): add validation for valid url
68+
@NotNull
69+
@URL
70+
private String imageUrl;
71+
72+
// @todo #709 /series/import/request/{id}(year): add validation for min value
73+
// @todo #709 /series/import/request/{id}(year): add validation for year in future
74+
@Min(value = MIN_RELEASE_YEAR, message = "{series.too-early-release-year}")
75+
private Integer year;
76+
77+
// This field holds a file that was downloaded from imageUrl.
78+
// Name of this field must match with the value of
79+
// DownloadImageInterceptor.DOWNLOADED_IMAGE_FIELD_NAME.
80+
// @todo #709 /series/import/request/{id}(imageUrl): add integration test for required field
81+
// @todo #709 /series/import/request/{id}(imageUrl): add validation for non-empty file
82+
// @todo #709 /series/import/request/{id}(imageUrl): add validation for file size
83+
// @todo #709 /series/import/request/{id}(imageUrl): add validation for file type
84+
@NotNull
85+
private MultipartFile downloadedImage;
86+
87+
//
88+
// The methods bellow required for AddSeriesDto interface.
89+
// They are no-op methods because we don't support all values during series import.
90+
//
91+
92+
@Override
93+
public MultipartFile getImage() {
94+
return downloadedImage;
95+
}
96+
97+
@Override
98+
public Integer getDay() {
99+
return null;
100+
}
101+
102+
@Override
103+
public Integer getMonth() {
104+
return null;
105+
}
106+
107+
@Override
108+
public String getMichelNumbers() {
109+
return null;
110+
}
111+
112+
@Override
113+
public BigDecimal getMichelPrice() {
114+
return null;
115+
}
116+
117+
@Override
118+
public String getScottNumbers() {
119+
return null;
120+
}
121+
122+
@Override
123+
public BigDecimal getScottPrice() {
124+
return null;
125+
}
126+
127+
@Override
128+
public String getYvertNumbers() {
129+
return null;
130+
}
131+
132+
@Override
133+
public BigDecimal getYvertPrice() {
134+
return null;
135+
}
136+
137+
@Override
138+
public String getGibbonsNumbers() {
139+
return null;
140+
}
141+
142+
@Override
143+
public BigDecimal getGibbonsPrice() {
144+
return null;
145+
}
146+
147+
@Override
148+
public String getComment() {
149+
return null;
150+
}
151+
152+
}

src/main/java/ru/mystamps/web/controller/interceptor/DownloadImageInterceptor.java

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ public boolean preHandle(
9494
}
9595

9696
if (!(request instanceof StandardMultipartHttpServletRequest)) {
97+
// It could mean that <form> tag doesn't have enctype="multipart/form-data" attribute.
9798
LOG.warn(
9899
"Unknown type of request ({}). "
99100
+ "Downloading images from external servers won't work!",

src/main/java/ru/mystamps/web/dao/dto/ParsedDataDto.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
@Getter
2424
@RequiredArgsConstructor
2525
public class ParsedDataDto {
26-
private final EntityWithSlugDto category;
27-
private final EntityWithSlugDto country;
26+
private final LinkEntityDto category;
27+
private final LinkEntityDto country;
2828
private final String imageUrl;
2929
private final Integer issueYear;
3030
}

0 commit comments

Comments
 (0)