1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.wicket.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.console.SyncopeConsoleSession;
33 import org.apache.syncope.client.console.SyncopeWebApplication;
34 import org.apache.syncope.client.console.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 = Bytes.megabytes(SyncopeWebApplication.get().getMaxUploadFileSizeMB());
107 uploadForm = new StatelessForm<>("uploadForm");
108 uploadForm.setMultiPart(true);
109 add(uploadForm);
110
111 container = new WebMarkupContainer("previewContainer");
112 container.setOutputMarkupId(true);
113
114 emptyFragment = new Fragment("panelPreview", "emptyFragment", container);
115 emptyFragment.setOutputMarkupId(true);
116 container.add(emptyFragment);
117 uploadForm.add(container);
118
119 field = new TextField<>("textField", model);
120 add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
121
122 uploadForm.add(new Label("preview", StringUtils.isBlank(mimeType) ? StringUtils.EMPTY : '(' + mimeType + ')'));
123
124 fileDownload = new BinaryFieldDownload(name, fileKey, mimeType, true) {
125
126 private static final long serialVersionUID = 7203445884857810583L;
127
128 @Override
129 protected HttpResourceStream getResourceStream() {
130 return new HttpResourceStream(new ResponseHolder(buildResponse()));
131 }
132 };
133
134 add(fileDownload);
135
136 downloadLink = new AjaxLink<>("downloadLink") {
137
138 private static final long serialVersionUID = -4331619903296515985L;
139
140 @Override
141 public void onClick(final AjaxRequestTarget target) {
142 try {
143 fileDownload.initiate(target);
144 } catch (Exception e) {
145 SyncopeConsoleSession.get().onException(e);
146 }
147 }
148 };
149 downloadLink.setOutputMarkupId(true);
150 uploadForm.add(downloadLink);
151
152 FileInputConfig config = new FileInputConfig().
153 showUpload(false).showRemove(false).showPreview(false).
154 browseClass("btn btn-success").browseIcon("<i class=\"fas fa-folder-open\"></i> ");
155 String language = SyncopeConsoleSession.get().getLocale().getLanguage();
156 if (!Locale.ENGLISH.getLanguage().equals(language)) {
157 config.withLocale(language);
158 }
159 fileUpload = new BootstrapFileInputField("fileUpload", new ListModel<>(new ArrayList<>()), config);
160 fileUpload.add(new AjaxFormSubmitBehavior(Constants.ON_CHANGE) {
161
162 private static final long serialVersionUID = -1107858522700306810L;
163
164 @Override
165 protected void onSubmit(final AjaxRequestTarget target) {
166 FileUpload uploaded = fileUpload.getFileUpload();
167 if (uploaded != null) {
168 if (maxUploadSize != null && uploaded.getSize() > maxUploadSize.bytes()) {
169
170 SyncopeConsoleSession.get().error(getString("tooLargeFile").
171 replace("${maxUploadSizeB}", String.valueOf(maxUploadSize.bytes())).
172 replace("${maxUploadSizeMB}", String.valueOf(maxUploadSize.bytes() / 1000000L)));
173 ((BaseWebPage) getPageReference().getPage()).getNotificationPanel().refresh(target);
174 } else {
175 byte[] uploadedBytes = uploaded.getBytes();
176 String uploadedEncoded = Base64.getEncoder().encodeToString(uploadedBytes);
177 field.setModelObject(uploadedEncoded);
178 target.add(field);
179
180 Component panelPreview = previewer.preview(uploadedBytes);
181 changePreviewer(panelPreview);
182 fileUpload.setModelObject(null);
183 uploadForm.addOrReplace(fileUpload);
184
185 setVisibleFileButtons(StringUtils.isNotBlank(uploadedEncoded));
186 downloadLink.setEnabled(StringUtils.isNotBlank(uploadedEncoded));
187
188 target.add(uploadForm);
189 }
190 }
191 }
192 });
193 uploadForm.add(fileUpload);
194
195 resetLink = new IndicatingAjaxLink<>("resetLink") {
196
197 private static final long serialVersionUID = -7978723352517770644L;
198
199 @Override
200 public void onClick(final AjaxRequestTarget target) {
201 field.setModelObject(null);
202 target.add(field);
203 downloadLink.setEnabled(false);
204 container.addOrReplace(emptyFragment);
205 setVisibleFileButtons(false);
206 target.add(uploadForm);
207 }
208
209 @Override
210 public String getAjaxIndicatorMarkupId() {
211 return Constants.VEIL_INDICATOR_MARKUP_ID;
212 }
213
214 };
215 uploadForm.add(resetLink);
216 }
217
218 protected Response buildResponse() {
219 return Response.ok(new ByteArrayInputStream(Base64.getMimeDecoder().decode(getModelObject()))).
220 type(StringUtils.isBlank(mimeType) ? MediaType.APPLICATION_OCTET_STREAM : mimeType).
221 header(HttpHeaders.LOCATION, StringUtils.EMPTY).
222 build();
223 }
224
225 protected void changePreviewer(final Component panelPreview) {
226 Fragment fragment = new Fragment("panelPreview", "previewFragment", container);
227 fragment.add(panelPreview);
228 container.addOrReplace(fragment);
229 uploadForm.addOrReplace(container);
230 }
231
232 private void setVisibleFileButtons(final boolean visible) {
233 resetLink.setVisible(visible);
234 downloadLink.setVisible(visible);
235 }
236
237 @Override
238 public BinaryFieldPanel clone() {
239 LOG.debug("Custom clone for binary field panel...");
240 return new BinaryFieldPanel(getId(), this.name, this.model, this.mimeType, this.fileKey);
241 }
242
243 @Override
244 public FieldPanel<String> setNewModel(final IModel<String> model) {
245 field.setModel(model);
246 String modelObj = model.getObject();
247
248 if (StringUtils.isNotBlank(modelObj)) {
249 Optional.ofNullable(previewer.preview(modelObj)).ifPresent(this::changePreviewer);
250 }
251
252 downloadLink.setEnabled(StringUtils.isNotBlank(modelObj));
253 setVisibleFileButtons(StringUtils.isNotBlank(modelObj));
254 return this;
255 }
256
257 @Override
258 protected void sendError(final Exception exception) {
259 SyncopeConsoleSession.get().onException(exception);
260 }
261
262 @Override
263 public FieldPanel<String> setReadOnly(final boolean readOnly) {
264 super.setReadOnly(readOnly);
265 fileUpload.setEnabled(!readOnly);
266 return this;
267 }
268 }