Skip to content

Commit 7f54e0d

Browse files
committed
/series/{id}: allow to specify image URL.
1 parent 6cfbcb2 commit 7f54e0d

File tree

6 files changed

+191
-25
lines changed

6 files changed

+191
-25
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public void addInterceptors(InterceptorRegistry registry) {
130130

131131
registry
132132
.addInterceptor(getDownloadImageInterceptor())
133-
.addPathPatterns(Url.ADD_SERIES_PAGE);
133+
.addPathPatterns(Url.ADD_SERIES_PAGE, Url.ADD_IMAGE_SERIES_PAGE);
134134
}
135135

136136
@Override

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

+37-2
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,47 @@ public String showInfo(
266266
return "series/info";
267267
}
268268

269-
@PostMapping(Url.ADD_IMAGE_SERIES_PAGE)
269+
@SuppressWarnings("checkstyle:parameternumber")
270+
@PostMapping(path = Url.ADD_IMAGE_SERIES_PAGE, params = "imageUrl")
271+
public String processImageWithImageUrl(
272+
@Validated({
273+
AddImageForm.ImageUrlChecks.class,
274+
AddImageForm.ImageChecks.class
275+
}) AddImageForm form,
276+
BindingResult result,
277+
@PathVariable("id") Integer seriesId,
278+
Model model,
279+
@CurrentUser Integer currentUserId,
280+
Locale userLocale,
281+
HttpServletRequest request,
282+
HttpServletResponse response)
283+
throws IOException {
284+
285+
return processImage(
286+
form,
287+
result,
288+
seriesId,
289+
model,
290+
currentUserId,
291+
userLocale,
292+
request,
293+
response
294+
);
295+
}
296+
297+
@SuppressWarnings("checkstyle:parameternumber")
298+
@PostMapping(path = Url.ADD_IMAGE_SERIES_PAGE, params = "!imageUrl")
270299
public String processImage(
271-
@Valid AddImageForm form,
300+
@Validated({
301+
AddImageForm.RequireImageCheck.class,
302+
AddImageForm.ImageChecks.class })
303+
AddImageForm form,
272304
BindingResult result,
273305
@PathVariable("id") Integer seriesId,
274306
Model model,
275307
@CurrentUser Integer currentUserId,
276308
Locale userLocale,
309+
HttpServletRequest request,
277310
HttpServletResponse response)
278311
throws IOException {
279312

@@ -289,6 +322,8 @@ public String processImage(
289322
return null;
290323
}
291324

325+
loadErrorsFromDownloadInterceptor(form, result, request);
326+
292327
boolean maxQuantityOfImagesExceeded = !isAdmin() && !isAllowedToAddingImages(series);
293328
model.addAttribute("maxQuantityOfImagesExceeded", maxQuantityOfImagesExceeded);
294329

src/main/java/ru/mystamps/web/controller/dto/AddImageForm.java

+73-16
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,96 @@
1818
package ru.mystamps.web.controller.dto;
1919

2020
import javax.validation.GroupSequence;
21-
import javax.validation.constraints.NotNull;
21+
22+
import org.apache.commons.lang3.StringUtils;
23+
24+
import org.hibernate.validator.constraints.URL;
2225

2326
import org.springframework.web.multipart.MultipartFile;
2427

2528
import lombok.Getter;
2629
import lombok.Setter;
2730

2831
import ru.mystamps.web.service.dto.AddImageDto;
32+
import ru.mystamps.web.support.beanvalidation.HasImageOrImageUrl;
2933
import ru.mystamps.web.support.beanvalidation.ImageFile;
3034
import ru.mystamps.web.support.beanvalidation.MaxFileSize;
3135
import ru.mystamps.web.support.beanvalidation.MaxFileSize.Unit;
3236
import ru.mystamps.web.support.beanvalidation.NotEmptyFile;
3337
import ru.mystamps.web.support.beanvalidation.NotEmptyFilename;
38+
import ru.mystamps.web.support.beanvalidation.RequireImageOrImageUrl;
3439

3540
import static ru.mystamps.web.validation.ValidationRules.MAX_IMAGE_SIZE;
3641

3742
@Getter
3843
@Setter
39-
@GroupSequence({
40-
AddImageForm.class,
41-
Group.Level1.class,
42-
Group.Level2.class,
43-
Group.Level3.class,
44-
Group.Level4.class,
45-
Group.Level5.class
46-
})
47-
public class AddImageForm implements AddImageDto {
48-
49-
@NotNull(groups = Group.Level1.class)
50-
@NotEmptyFilename(groups = Group.Level2.class)
51-
@NotEmptyFile(groups = Group.Level3.class)
52-
@MaxFileSize(value = MAX_IMAGE_SIZE, unit = Unit.Kbytes, groups = Group.Level4.class)
53-
@ImageFile(groups = Group.Level5.class)
44+
@RequireImageOrImageUrl(groups = AddImageForm.ImageUrl1Checks.class)
45+
public class AddImageForm implements AddImageDto, HasImageOrImageUrl, NullableImageUrl {
46+
47+
// Name of this field should match with the value of
48+
// DownloadImageInterceptor.UPLOADED_IMAGE_FIELD_NAME.
49+
@NotEmptyFilename(groups = RequireImageCheck.class)
50+
@NotEmptyFile(groups = Group.Level1.class)
51+
@MaxFileSize(value = MAX_IMAGE_SIZE, unit = Unit.Kbytes, groups = Group.Level2.class)
52+
@ImageFile(groups = Group.Level2.class)
5453
private MultipartFile image;
5554

55+
// Name of this field must match with the value of DownloadImageInterceptor.URL_PARAMETER_NAME.
56+
@URL(groups = ImageUrl2Checks.class)
57+
private String imageUrl;
58+
59+
// This field holds a file that was downloaded from imageUrl.
60+
// Name of this field must match with the value of
61+
// DownloadImageInterceptor.DOWNLOADED_IMAGE_FIELD_NAME.
62+
@NotEmptyFile(groups = Group.Level1.class)
63+
@MaxFileSize(value = MAX_IMAGE_SIZE, unit = Unit.Kbytes, groups = Group.Level2.class)
64+
@ImageFile(groups = Group.Level2.class)
65+
private MultipartFile downloadedImage;
66+
67+
@Override
68+
public MultipartFile getImage() {
69+
if (hasImage()) {
70+
return image;
71+
}
72+
73+
return downloadedImage;
74+
}
75+
76+
// This method has to be implemented to satisfy HasImageOrImageUrl requirements.
77+
// The latter is being used by RequireImageOrImageUrl validator.
78+
@Override
79+
public boolean hasImage() {
80+
return image != null && StringUtils.isNotEmpty(image.getOriginalFilename());
81+
}
82+
83+
// This method has to be implemented to satisfy HasImageOrImageUrl requirements.
84+
// The latter is being used by RequireImageOrImageUrl validator.
85+
@Override
86+
public boolean hasImageUrl() {
87+
return StringUtils.isNotEmpty(imageUrl);
88+
}
89+
90+
public interface RequireImageCheck {
91+
}
92+
93+
@GroupSequence({
94+
ImageUrl1Checks.class,
95+
ImageUrl2Checks.class,
96+
})
97+
public interface ImageUrlChecks {
98+
}
99+
100+
public interface ImageUrl1Checks {
101+
}
102+
103+
public interface ImageUrl2Checks {
104+
}
105+
106+
@GroupSequence({
107+
Group.Level1.class,
108+
Group.Level2.class
109+
})
110+
public interface ImageChecks {
111+
}
112+
56113
}

src/main/webapp/WEB-INF/views/series/info.html

+22-1
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,33 @@
100100
</span>
101101
</label>
102102
<div class="col-sm-9">
103-
<input type="file" id="image" style="box-shadow: none; border: 0px;" required="required" accept="image/png,image/jpeg" th:field="*{image}" />
103+
<input id="image"
104+
type="file"
105+
style="box-shadow: none; border: 0px;"
106+
accept="image/png,image/jpeg"
107+
th:field="*{image}"
108+
th:attr="required=${#authorization.expression('hasAuthority(''DOWNLOAD_IMAGE'')') ? null : 'required'}" />
104109
<!--/*/
105110
<span id="image.errors" class="help-block" th:if="${#fields.hasErrors('image')}" th:each="error : ${#fields.errors('image')}" th:text="${error}"></span>
106111
/*/-->
107112
</div>
108113
</div>
114+
<div class="form-group form-group-sm"
115+
th:classappend="${#fields.hasErrors('imageUrl') or #fields.hasErrors('downloadedImage') ? 'has-error' : ''}"
116+
sec:authorize="hasAuthority('DOWNLOAD_IMAGE')">
117+
<label for="image-url" class="control-label col-sm-3">
118+
<span class="field-label" th:text="#{t_image_url}">
119+
Image URL
120+
</span>
121+
</label>
122+
<div class="col-sm-9">
123+
<input type="url" id="image-url" class="form-control" th:field="*{imageUrl}" />
124+
<!--/*/
125+
<span id="image-url.errors" class="help-block" th:if="${#fields.hasErrors('imageUrl')}" th:each="error : ${#fields.errors('imageUrl')}" th:text="${error}"></span>
126+
<span id="image-url.errors" class="help-block" th:if="${#fields.hasErrors('downloadedImage')}" th:each="error : ${#fields.errors('downloadedImage')}" th:text="${error}"></span>
127+
/*/-->
128+
</div>
129+
</div>
109130
<div class="form-group from-group-sm">
110131
<div class="col-sm-offset-3 col-sm-5">
111132
<input type="submit" class="btn btn-primary" value="Add image" th:value="#{t_add_image}" />

src/test/robotframework/series/add-image/logic.robot

+10-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@ Test Setup Before Test
88
Force Tags series add-image logic
99

1010
*** Test Cases ***
11-
Add additional image
12-
[Documentation] Verify adding an additional image to a series
11+
Add additional image by providing a file
12+
[Documentation] Verify uploading an additional image to a series
1313
Page Should Not Contain Image id=series-image-2
1414
Choose File id=image ${MAIN_RESOURCE_DIR}${/}test.png
1515
Submit Form id=add-image-form
1616
Location Should Be ${SITE_URL}/series/1
1717
Page Should Contain Image id=series-image-2
1818

19+
Add additional image by providing a URL to image
20+
[Documentation] Verify downloading an additional image to a series
21+
Page Should Not Contain Image id=series-image-3
22+
Input Text id=image-url ${SITE_URL}/image/1
23+
Submit Form id=add-image-form
24+
Location Should Be ${SITE_URL}/series/1
25+
Page Should Contain Image id=series-image-3
26+
1927
*** Keywords ***
2028
Before Test Suite
2129
[Documentation] Open browser, register fail hook and login as admin

src/test/robotframework/series/add-image/validation.robot

+48-3
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,62 @@ Suite Teardown After Test Suite
77
Force Tags series add-image validation
88

99
*** Test Cases ***
10-
Add image but without filling a required field
11-
[Documentation] Verify validation of a required field
10+
Add image with empty required fields
11+
[Documentation] Verify validation of mandatory fields
1212
Submit Form id=add-image-form
13-
Element Text Should Be id=image.errors Value must not be empty
13+
Element Text Should Be id=image.errors Image or image URL must be specified
14+
Element Text Should Be id=image-url.errors Image or image URL must be specified
1415

1516
Add image with empty file
1617
[Documentation] Verify validation of an empty file
1718
Choose File id=image ${TEST_RESOURCE_DIR}${/}empty.png
1819
Submit Form id=add-image-form
1920
Element Text Should Be id=image.errors File must not be empty
2021

22+
Add image with both image and an image URL
23+
[Documentation] Verify validation of an image and an image URL provided at the same time
24+
Choose File id=image ${MAIN_RESOURCE_DIR}${/}test.png
25+
Input Text id=image-url ${SITE_URL}/image/1
26+
Submit Form id=add-image-form
27+
Element Text Should Be id=image.errors Image or image URL must be specified
28+
Element Text Should Be id=image-url.errors Image or image URL must be specified
29+
30+
Add image with invalid URL
31+
[Documentation] Verify validation of invalid URL
32+
Input Text id=image-url invalid-url
33+
Submit Form id=add-image-form
34+
Element Text Should Be id=image-url.errors Value must be a valid URL
35+
36+
Add image with image URL with invalid response
37+
[Documentation] Verify validation of invalid response from a server
38+
Input Text id=image-url ${SITE_URL}/test/invalid/response-400
39+
Submit Form id=add-image-form
40+
Element Text Should Be id=image-url.errors Could not download file
41+
42+
Add image with image URL to a file that does not exist
43+
[Documentation] Verify validation of URL to non existing file
44+
Input Text id=image-url ${SITE_URL}/test/invalid/response-404
45+
Submit Form id=add-image-form
46+
Element Text Should Be id=image-url.errors File not found
47+
48+
Add image with image URL that causes a redirect
49+
[Documentation] Verify validation of URL with redirect
50+
Input Text id=image-url ${SITE_URL}/test/invalid/response-301
51+
Submit Form id=add-image-form
52+
Element Text Should Be id=image-url.errors URL must not redirect to another address
53+
54+
Add image with image URL to an empty file
55+
[Documentation] Verify validation of URL to an empty file
56+
Input Text id=image-url ${SITE_URL}/test/invalid/empty-jpeg-file
57+
Submit Form id=add-image-form
58+
Element Text Should Be id=image-url.errors File must not be empty
59+
60+
Add image with image URL to not an image file
61+
[Documentation] Verify validation of URL to a file of unsupported type
62+
Input Text id=image-url ${SITE_URL}/test/invalid/not-image-file
63+
Submit Form id=add-image-form
64+
Element Text Should Be id=image-url.errors Invalid file type
65+
2166
*** Keywords ***
2267
Before Test Suite
2368
[Documentation] Login as admin and open a page with a series info

0 commit comments

Comments
 (0)