Skip to content

Commit 27d1204

Browse files
committed
Implement ability to add additional images to series.
1 parent 70bb03b commit 27d1204

File tree

19 files changed

+233
-51
lines changed

19 files changed

+233
-51
lines changed

src/main/config/checkstyle-suppressions.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<suppress checks="LineLength" files="AbstractPage.java" lines="44,45" />
99
<suppress checks="LineLength" files="AbstractPageWithForm.java" lines="27,28,33" />
1010
<suppress checks="LineLength" files="Form.java" lines="31,32,37" />
11-
<suppress checks="LineLength" files="Url.java" lines="73" />
11+
<suppress checks="LineLength" files="Url.java" lines="71" />
1212
<suppress checks="LineLength" files="ErrorController.java" lines="73" />
1313
<suppress checks="LineLength" files="SecurityConfig.java" lines="35,36,40" />
1414
<suppress checks="LineLength" files="JdbcSeriesDaoImpl.java" lines="123" />

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222

23-
import ru.mystamps.web.service.ImageService;
24-
2523
/**
2624
* Holds path to site and all URLs.
2725
*
@@ -59,7 +57,7 @@ public final class Url {
5957

6058
public static final String INFO_COLLECTION_PAGE = "/collection/{id}/{slug}";
6159

62-
public static final String GET_IMAGE_PAGE = ImageService.GET_IMAGE_PAGE;
60+
public static final String GET_IMAGE_PAGE = "/image/{id}";
6361

6462
public static final String UNAUTHORIZED_PAGE = "/error/401";
6563
public static final String FORBIDDEN_PAGE = "/error/403";
@@ -97,6 +95,7 @@ public static Map<String, String> asMap() {
9795
map.put("ADD_COUNTRY_PAGE", ADD_COUNTRY_PAGE);
9896
map.put("INFO_COUNTRY_PAGE", INFO_COUNTRY_PAGE);
9997
map.put("INFO_COLLECTION_PAGE", INFO_COLLECTION_PAGE);
98+
map.put("GET_IMAGE_PAGE", GET_IMAGE_PAGE);
10099
map.put("FAVICON_ICO", FAVICON_ICO);
101100
map.put("MAIN_CSS", MAIN_CSS);
102101
map.put("BOOTSTRAP_CSS", BOOTSTRAP_CSS);

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

+36
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import ru.mystamps.web.Url;
4646
import ru.mystamps.web.entity.Collection;
4747
import ru.mystamps.web.entity.User;
48+
import ru.mystamps.web.model.AddImageForm;
4849
import ru.mystamps.web.model.AddSeriesForm;
4950
import ru.mystamps.web.model.AddSeriesForm.ScottCatalogChecks;
5051
import ru.mystamps.web.model.AddSeriesForm.GibbonsCatalogChecks;
@@ -151,6 +152,7 @@ public String showInfo(@PathVariable("id") Series series, Model model, User curr
151152
throw new NotFoundException();
152153
}
153154

155+
model.addAttribute("addImageForm", new AddImageForm());
154156
model.addAttribute("series", series);
155157
model.addAttribute("michelNumbers", CatalogUtils.toShortForm(series.getMichel()));
156158
model.addAttribute("scottNumbers", CatalogUtils.toShortForm(series.getScott()));
@@ -165,6 +167,40 @@ public String showInfo(@PathVariable("id") Series series, Model model, User curr
165167
return "series/info";
166168
}
167169

170+
@RequestMapping(value = Url.INFO_SERIES_PAGE, method = RequestMethod.POST)
171+
public String processImage(
172+
@Validated({ Default.class, AddImageForm.ImageChecks.class }) AddImageForm form,
173+
BindingResult result,
174+
@PathVariable("id") Series series,
175+
Model model,
176+
User currentUser) {
177+
178+
model.addAttribute("series", series);
179+
model.addAttribute("michelNumbers", CatalogUtils.toShortForm(series.getMichel()));
180+
model.addAttribute("scottNumbers", CatalogUtils.toShortForm(series.getScott()));
181+
model.addAttribute("yvertNumbers", CatalogUtils.toShortForm(series.getYvert()));
182+
model.addAttribute("gibbonsNumbers", CatalogUtils.toShortForm(series.getGibbons()));
183+
184+
model.addAttribute(
185+
"isSeriesInCollection",
186+
collectionService.isSeriesInCollection(currentUser, series)
187+
);
188+
189+
if (result.hasErrors()) {
190+
// don't try to re-display file upload field
191+
form.setImage(null);
192+
return "series/info";
193+
}
194+
195+
if (series == null) {
196+
throw new NotFoundException();
197+
}
198+
199+
seriesService.addImageToSeries(form, series);
200+
201+
return "series/info";
202+
}
203+
168204
@RequestMapping(
169205
value = Url.INFO_SERIES_PAGE,
170206
method = RequestMethod.POST,

src/main/java/ru/mystamps/web/entity/Series.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package ru.mystamps.web.entity;
1919

20+
import java.util.LinkedHashSet;
2021
import java.util.Set;
2122

2223
import javax.persistence.AttributeOverride;
@@ -28,8 +29,11 @@
2829
import javax.persistence.FetchType;
2930
import javax.persistence.GeneratedValue;
3031
import javax.persistence.Id;
32+
import javax.persistence.JoinColumn;
33+
import javax.persistence.JoinTable;
3134
import javax.persistence.ManyToMany;
3235
import javax.persistence.ManyToOne;
36+
import javax.persistence.OneToMany;
3337
import javax.persistence.OrderBy;
3438
import javax.persistence.Table;
3539

@@ -47,8 +51,7 @@
4751
@SuppressWarnings("PMD.TooManyFields")
4852
public class Series {
4953

50-
public static final int IMAGE_URL_LENGTH = 255;
51-
public static final int COMMENT_LENGTH = 255;
54+
public static final int COMMENT_LENGTH = 255;
5255

5356
@Id
5457
@GeneratedValue
@@ -143,8 +146,9 @@ public class Series {
143146
})
144147
private Price gibbonsPrice;
145148

146-
@Column(name = "image_url", length = IMAGE_URL_LENGTH)
147-
private String imageUrl;
149+
@OneToMany(fetch = FetchType.EAGER)
150+
@JoinTable(inverseJoinColumns = @JoinColumn(name = "image_id"))
151+
private Set<Image> images;
148152

149153
@Column(length = COMMENT_LENGTH)
150154
private String comment;
@@ -156,4 +160,12 @@ public Series() {
156160
metaInfo = new MetaInfo();
157161
}
158162

163+
public void addImage(Image image) {
164+
if (images == null) {
165+
images = new LinkedHashSet<>();
166+
}
167+
168+
images.add(image);
169+
}
170+
159171
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2009-2015 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.model;
19+
20+
import javax.validation.GroupSequence;
21+
import javax.validation.constraints.NotNull;
22+
23+
import org.springframework.web.multipart.MultipartFile;
24+
25+
import lombok.Getter;
26+
import lombok.Setter;
27+
28+
import ru.mystamps.web.service.dto.AddImageDto;
29+
import ru.mystamps.web.validation.jsr303.NotEmptyFile;
30+
import ru.mystamps.web.validation.jsr303.NotEmptyFilename;
31+
32+
@Getter
33+
@Setter
34+
public class AddImageForm implements AddImageDto {
35+
36+
@NotNull
37+
@NotEmptyFilename(groups = Image1Checks.class)
38+
@NotEmptyFile(groups = Image2Checks.class)
39+
private MultipartFile image;
40+
41+
@GroupSequence({
42+
Image1Checks.class,
43+
Image2Checks.class
44+
})
45+
public interface ImageChecks {
46+
}
47+
48+
public interface Image1Checks {
49+
}
50+
51+
public interface Image2Checks {
52+
}
53+
54+
}

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@
1919

2020
import org.springframework.web.multipart.MultipartFile;
2121

22+
import ru.mystamps.web.entity.Image;
2223
import ru.mystamps.web.service.dto.ImageDto;
2324

2425
public interface ImageService {
25-
String GET_IMAGE_PAGE = "/image/{id}";
26-
27-
String save(MultipartFile file);
26+
Image save(MultipartFile file);
2827
ImageDto get(Integer imageId);
2928
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class ImageServiceImpl implements ImageService {
4646

4747
@Override
4848
@Transactional
49-
public String save(MultipartFile file) {
49+
public Image save(MultipartFile file) {
5050
Validate.isTrue(file != null, "File should be non null");
5151
Validate.isTrue(file.getSize() > 0, "Image size must be greater than zero");
5252

@@ -72,7 +72,7 @@ public String save(MultipartFile file) {
7272

7373
imagePersistenceStrategy.save(file, entity);
7474

75-
return GET_IMAGE_PAGE.replace("{id}", String.valueOf(entity.getId()));
75+
return entity;
7676
}
7777

7878
@Override

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

+3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import ru.mystamps.web.entity.Category;
2121
import ru.mystamps.web.entity.Collection;
2222
import ru.mystamps.web.entity.Country;
23+
import ru.mystamps.web.entity.Series;
2324
import ru.mystamps.web.entity.User;
25+
import ru.mystamps.web.service.dto.AddImageDto;
2426
import ru.mystamps.web.service.dto.AddSeriesDto;
2527
import ru.mystamps.web.service.dto.SeriesInfoDto;
2628
import ru.mystamps.web.service.dto.SitemapInfoDto;
@@ -29,6 +31,7 @@
2931
@SuppressWarnings("PMD.TooManyMethods")
3032
public interface SeriesService {
3133
Integer add(AddSeriesDto dto, User user, boolean userCanAddComments);
34+
void addImageToSeries(AddImageDto dto, Series series);
3235
long countAll();
3336
long countAllStamps();
3437
long countSeriesOf(Collection collection);

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

+18-5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package ru.mystamps.web.service;
1919

20+
import java.util.Collections;
2021
import java.util.Date;
2122
import java.util.Set;
2223

@@ -36,13 +37,15 @@
3637
import ru.mystamps.web.entity.Country;
3738
import ru.mystamps.web.entity.Collection;
3839
import ru.mystamps.web.entity.GibbonsCatalog;
40+
import ru.mystamps.web.entity.Image;
3941
import ru.mystamps.web.entity.MichelCatalog;
4042
import ru.mystamps.web.entity.Price;
4143
import ru.mystamps.web.entity.ScottCatalog;
4244
import ru.mystamps.web.entity.Series;
4345
import ru.mystamps.web.entity.StampsCatalog;
4446
import ru.mystamps.web.entity.User;
4547
import ru.mystamps.web.entity.YvertCatalog;
48+
import ru.mystamps.web.service.dto.AddImageDto;
4649
import ru.mystamps.web.service.dto.AddSeriesDto;
4750
import ru.mystamps.web.service.dto.SeriesInfoDto;
4851
import ru.mystamps.web.service.dto.SitemapInfoDto;
@@ -95,11 +98,8 @@ public Integer add(AddSeriesDto dto, User user, boolean userCanAddComments) {
9598
series.setGibbons(getCatalogNumbersOrNull(dto.getGibbonsNumbers(), GibbonsCatalog.class));
9699
series.setGibbonsPrice(Price.valueOf(dto.getGibbonsPrice(), dto.getGibbonsCurrency()));
97100

98-
String imageUrl = imageService.save(dto.getImage());
99-
Validate.validState(imageUrl != null, "Image url must be non null");
100-
Validate.validState(imageUrl.length() <= Series.IMAGE_URL_LENGTH, "Too long image path");
101-
102-
series.setImageUrl(imageUrl);
101+
Image image = imageService.save(dto.getImage());
102+
series.setImages(Collections.singleton(image));
103103

104104
if (userCanAddComments && dto.getComment() != null) {
105105
Validate.isTrue(
@@ -122,6 +122,19 @@ public Integer add(AddSeriesDto dto, User user, boolean userCanAddComments) {
122122

123123
return entity.getId();
124124
}
125+
126+
@Override
127+
@Transactional
128+
public void addImageToSeries(AddImageDto dto, Series series) {
129+
Validate.isTrue(dto != null, "DTO must be non null");
130+
Validate.isTrue(series != null, "DTO must be non null");
131+
132+
Image image = imageService.save(dto.getImage());
133+
134+
series.addImage(image);
135+
136+
seriesDao.save(series);
137+
}
125138

126139
@Override
127140
@Transactional(readOnly = true)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (C) 2009-2015 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.service.dto;
19+
20+
import org.springframework.web.multipart.MultipartFile;
21+
22+
public interface AddImageDto {
23+
MultipartFile getImage();
24+
}

src/main/resources/liquibase/version/0.4.xml

+1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
77

88
<include file="0.4/2014-10-28--decimal_price.xml" relativeToChangelogFile="true" />
9+
<include file="0.4/2015-07-22--image_url.xml" relativeToChangelogFile="true" />
910

1011
</databaseChangeLog>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<databaseChangeLog
3+
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
6+
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.0.xsd">
7+
8+
<changeSet id="create-series_images-table" author="php-coder" context="scheme">
9+
<comment>Creates series_images table</comment>
10+
11+
<createTable tableName="series_images">
12+
<column name="series_id" type="INTEGER">
13+
<constraints nullable="false" references="series(id)" foreignKeyName="fk_series_images_series_id" />
14+
</column>
15+
<column name="image_id" type="INTEGER">
16+
<constraints nullable="false" references="images(id)" foreignKeyName="fk_series_images_image_id" />
17+
</column>
18+
</createTable>
19+
20+
<modifySql dbms="mysql">
21+
<append value=" ENGINE=InnoDB" />
22+
</modifySql>
23+
24+
</changeSet>
25+
26+
</databaseChangeLog>

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

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ t_yvert = Yvert
9090
t_sg = Gibbons
9191
t_comment = Comment
9292
t_image = Image
93+
t_add_more_images_hint = Later you will be able to add additional images
9394

9495
# series/info.html
9596
t_series_info = Info about series
@@ -101,6 +102,7 @@ t_add_to_collection = Add to collection
101102
t_remove_from_collection = Remove from collection
102103
t_need_authentication_to_add_series_to_collection = \
103104
In order to add this series to your collection you should <a href="{0}">register</a> or <a href="{1}">pass authentication</a>.
105+
t_add_image = Add image
104106

105107
# category/add.html
106108
t_create_category_ucfirst = Add category

0 commit comments

Comments
 (0)