1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.enduser.markup.html.form;
20
21 import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.BootstrapFileInputField;
22 import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.fileinput.FileInputConfig;
23 import java.io.ByteArrayInputStream;
24 import java.util.ArrayList;
25 import java.util.Base64;
26 import java.util.Locale;
27 import java.util.Optional;
28 import javax.ws.rs.core.HttpHeaders;
29 import javax.ws.rs.core.MediaType;
30 import javax.ws.rs.core.Response;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.syncope.client.enduser.SyncopeEnduserSession;
33 import org.apache.syncope.client.enduser.SyncopeWebApplication;
34 import org.apache.syncope.client.enduser.commons.PreviewUtils;
35 import org.apache.syncope.client.ui.commons.Constants;
36 import org.apache.syncope.client.ui.commons.HttpResourceStream;
37 import org.apache.syncope.client.ui.commons.markup.html.form.BaseBinaryFieldPanel;
38 import org.apache.syncope.client.ui.commons.markup.html.form.BinaryFieldDownload;
39 import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
40 import org.apache.syncope.client.ui.commons.markup.html.form.preview.BinaryPreviewer;
41 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
42 import org.apache.syncope.client.ui.commons.rest.ResponseHolder;
43 import org.apache.wicket.Component;
44 import org.apache.wicket.ajax.AjaxRequestTarget;
45 import org.apache.wicket.ajax.form.AjaxFormSubmitBehavior;
46 import org.apache.wicket.ajax.markup.html.AjaxLink;
47 import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
48 import org.apache.wicket.markup.html.WebMarkupContainer;
49 import org.apache.wicket.markup.html.basic.Label;
50 import org.apache.wicket.markup.html.form.Form;
51 import org.apache.wicket.markup.html.form.StatelessForm;
52 import org.apache.wicket.markup.html.form.TextField;
53 import org.apache.wicket.markup.html.form.upload.FileUpload;
54 import org.apache.wicket.markup.html.panel.Fragment;
55 import org.apache.wicket.model.IModel;
56 import org.apache.wicket.model.ResourceModel;
57 import org.apache.wicket.model.util.ListModel;
58 import org.apache.wicket.spring.injection.annot.SpringBean;
59 import org.apache.wicket.util.lang.Bytes;
60
61 public class BinaryFieldPanel extends BaseBinaryFieldPanel {
62
63 private static final long serialVersionUID = 6264462604183088931L;
64
65 @SpringBean
66 protected PreviewUtils previewUtils;
67
68 protected final String mimeType;
69
70 protected final WebMarkupContainer container;
71
72 protected final AjaxLink<Void> downloadLink;
73
74 protected final Form<?> uploadForm;
75
76 protected final Fragment emptyFragment;
77
78 protected final BootstrapFileInputField fileUpload;
79
80 protected final BinaryFieldDownload fileDownload;
81
82 protected final BinaryPreviewer previewer;
83
84 protected final IndicatingAjaxLink<Void> resetLink;
85
86 protected final Bytes maxUploadSize;
87
88 protected final IModel<String> model;
89
90 protected final String fileKey;
91
92 public BinaryFieldPanel(
93 final String id,
94 final String name,
95 final IModel<String> model,
96 final String mimeType,
97 final String fileKey) {
98
99 super(id, name, model);
100 this.model = model;
101 this.fileKey = fileKey;
102 this.mimeType = mimeType;
103
104 previewer = previewUtils.getPreviewer(mimeType);
105
106 maxUploadSize = SyncopeWebApplication.get().getMaxUploadFileSizeMB() == null
107 ? null
108 : Bytes.megabytes(SyncopeWebApplication.get().getMaxUploadFileSizeMB());
109 uploadForm = new StatelessForm<>("uploadForm");
110 uploadForm.setMultiPart(true);
111 add(uploadForm);
112
113 container = new WebMarkupContainer("previewContainer");
114 container.setOutputMarkupId(true);
115
116 emptyFragment = new Fragment("panelPreview", "emptyFragment", container);
117 emptyFragment.setOutputMarkupId(true);
118 container.add(emptyFragment);
119 uploadForm.add(container);
120
121 field = new TextField<>("textField", model);
122 add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
123
124 uploadForm.add(new Label("preview", StringUtils.isBlank(mimeType) ? StringUtils.EMPTY : '(' + mimeType + ')'));
125
126 fileDownload = new BinaryFieldDownload(name, fileKey, mimeType, true) {
127
128 private static final long serialVersionUID = 7203445884857810583L;
129
130 @Override
131 protected HttpResourceStream getResourceStream() {
132 return new HttpResourceStream(new ResponseHolder(buildResponse()));
133 }
134 };
135
136 add(fileDownload);
137
138 downloadLink = new AjaxLink<>("downloadLink") {
139
140 private static final long serialVersionUID = -4331619903296515985L;
141
142 @Override
143 public void onClick(final AjaxRequestTarget target) {
144 try {
145 fileDownload.initiate(target);
146 } catch (Exception e) {
147 SyncopeEnduserSession.get().onException(e);
148 }
149 }
150 };
151 downloadLink.setOutputMarkupId(true);
152 uploadForm.add(downloadLink);
153
154 FileInputConfig config = new FileInputConfig().
155 showUpload(false).showRemove(false).showPreview(false).
156 browseClass("btn btn-success").browseIcon("<i class=\"fas fa-folder-open\"></i> ");
157 String language = SyncopeEnduserSession.get().getLocale().getLanguage();
158 if (!Locale.ENGLISH.getLanguage().equals(language)) {
159 config.withLocale(language);
160 }
161 fileUpload = new BootstrapFileInputField("fileUpload", new ListModel<>(new ArrayList<>()), config);
162 fileUpload.add(new AjaxFormSubmitBehavior(Constants.ON_CHANGE) {
163
164 private static final long serialVersionUID = -1107858522700306810L;
165
166 @Override
167 protected void onSubmit(final AjaxRequestTarget target) {
168 FileUpload uploaded = fileUpload.getFileUpload();
169 if (uploaded != null) {
170 if (maxUploadSize != null && uploaded.getSize() > maxUploadSize.bytes()) {
171
172 SyncopeEnduserSession.get().error(getString("tooLargeFile").
173 replace("${maxUploadSizeB}", String.valueOf(maxUploadSize.bytes())).
174 replace("${maxUploadSizeMB}", String.valueOf(maxUploadSize.bytes() / 1000000L)));
175 ((BaseWebPage) getPageReference().getPage()).getNotificationPanel().refresh(target);
176 } else {
177 byte[] uploadedBytes = uploaded.getBytes();
178 String uploadedEncoded = Base64.getEncoder().encodeToString(uploadedBytes);
179 field.setModelObject(uploadedEncoded);
180 target.add(field);
181
182 Component panelPreview = previewer.preview(uploadedBytes);
183 changePreviewer(panelPreview);
184 fileUpload.setModelObject(null);
185 uploadForm.addOrReplace(fileUpload);
186
187 setVisibleFileButtons(StringUtils.isNotBlank(uploadedEncoded));
188 downloadLink.setEnabled(StringUtils.isNotBlank(uploadedEncoded));
189
190 target.add(uploadForm);
191 }
192 }
193 }
194 });
195 uploadForm.add(fileUpload);
196
197 resetLink = new IndicatingAjaxLink<>("resetLink") {
198
199 private static final long serialVersionUID = -7978723352517770644L;
200
201 @Override
202 public void onClick(final AjaxRequestTarget target) {
203 field.setModelObject(null);
204 target.add(field);
205 downloadLink.setEnabled(false);
206 container.addOrReplace(emptyFragment);
207 setVisibleFileButtons(false);
208 target.add(uploadForm);
209 }
210
211 @Override
212 public String getAjaxIndicatorMarkupId() {
213 return Constants.VEIL_INDICATOR_MARKUP_ID;
214 }
215
216 };
217 uploadForm.add(resetLink);
218 }
219
220 protected Response buildResponse() {
221 return Response.ok(new ByteArrayInputStream(Base64.getMimeDecoder().decode(getModelObject()))).
222 type(StringUtils.isBlank(mimeType) ? MediaType.APPLICATION_OCTET_STREAM : mimeType).
223 header(HttpHeaders.LOCATION, StringUtils.EMPTY).
224 build();
225 }
226
227 protected void changePreviewer(final Component panelPreview) {
228 Fragment fragment = new Fragment("panelPreview", "previewFragment", container);
229 fragment.add(panelPreview);
230 container.addOrReplace(fragment);
231 uploadForm.addOrReplace(container);
232 }
233
234 protected void setVisibleFileButtons(final boolean visible) {
235 resetLink.setVisible(visible);
236 downloadLink.setVisible(visible);
237 }
238
239 @Override
240 public BinaryFieldPanel clone() {
241 LOG.debug("Custom clone for binary field panel...");
242 return new BinaryFieldPanel(getId(), this.name, this.model, this.mimeType, this.fileKey);
243 }
244
245 @Override
246 public FieldPanel<String> setNewModel(final IModel<String> model) {
247 field.setModel(model);
248 String modelObj = model.getObject();
249
250 if (StringUtils.isNotBlank(modelObj)) {
251 Optional.ofNullable(previewer.preview(modelObj)).ifPresent(this::changePreviewer);
252 }
253
254 downloadLink.setEnabled(StringUtils.isNotBlank(modelObj));
255 setVisibleFileButtons(StringUtils.isNotBlank(modelObj));
256 return this;
257 }
258
259 @Override
260 protected void sendError(final Exception exception) {
261 SyncopeEnduserSession.get().onException(exception);
262 }
263
264 @Override
265 public FieldPanel<String> setReadOnly(final boolean readOnly) {
266 super.setReadOnly(readOnly);
267 fileUpload.setEnabled(!readOnly);
268 return this;
269 }
270 }