fixed import bugs
This commit is contained in:
parent
dc7df0620c
commit
258ba2939f
10 changed files with 129 additions and 36 deletions
|
@ -33,7 +33,6 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
|
|||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.form.Form;
|
||||
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
|
||||
|
@ -278,7 +277,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
pageService.getWidgetFactory())
|
||||
.setDialogWidth(600);
|
||||
|
||||
final ImportFormBuilder importFormBuilder = new ImportFormBuilder(
|
||||
final ImportFormContext importFormContext = new ImportFormContext(
|
||||
pageService,
|
||||
action.pageContext());
|
||||
|
||||
|
@ -287,8 +286,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
formHandle -> SebExamConfigPropForm.doImport(
|
||||
pageService,
|
||||
formHandle),
|
||||
Utils.EMPTY_EXECUTION,
|
||||
importFormBuilder);
|
||||
importFormContext::cancelUpload,
|
||||
importFormContext);
|
||||
|
||||
return action;
|
||||
};
|
||||
|
@ -303,7 +302,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
final Control fieldControl = form.getFieldControl(API.IMPORT_FILE_ATTR_NAME);
|
||||
final PageContext context = formHandle.getContext();
|
||||
if (fieldControl != null && fieldControl instanceof FileUploadSelection) {
|
||||
final InputStream inputStream = ((FileUploadSelection) fieldControl).getInputStream();
|
||||
final FileUploadSelection fileUpload = (FileUploadSelection) fieldControl;
|
||||
final InputStream inputStream = fileUpload.getInputStream();
|
||||
if (inputStream != null) {
|
||||
final Configuration configuration = pageService.getRestService()
|
||||
.getBuilder(ImportExamConfig.class)
|
||||
|
@ -313,7 +313,10 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
form.getFieldValue(API.IMPORT_PASSWORD_ATTR_NAME))
|
||||
.withBody(inputStream)
|
||||
.call()
|
||||
.get(context::notifyError);
|
||||
.get(e -> {
|
||||
fileUpload.close();
|
||||
return context.notifyError(e);
|
||||
});
|
||||
|
||||
if (configuration != null) {
|
||||
context.publishInfo(FORM_IMPORT_CONFIRM_TEXT_KEY);
|
||||
|
@ -326,12 +329,14 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class ImportFormBuilder implements ModalInputDialogComposer<FormHandle<ConfigurationNode>> {
|
||||
private static final class ImportFormContext implements ModalInputDialogComposer<FormHandle<ConfigurationNode>> {
|
||||
|
||||
private final PageService pageService;
|
||||
private final PageContext pageContext;
|
||||
|
||||
protected ImportFormBuilder(final PageService pageService, final PageContext pageContext) {
|
||||
private Form form = null;
|
||||
|
||||
protected ImportFormContext(final PageService pageService, final PageContext pageContext) {
|
||||
this.pageService = pageService;
|
||||
this.pageContext = pageContext;
|
||||
}
|
||||
|
@ -353,8 +358,18 @@ public class SebExamConfigPropForm implements TemplateComposer {
|
|||
"").asPasswordField())
|
||||
.build();
|
||||
|
||||
this.form = formHandle.getForm();
|
||||
return () -> formHandle;
|
||||
}
|
||||
|
||||
void cancelUpload() {
|
||||
if (this.form != null) {
|
||||
final Control fieldControl = this.form.getFieldControl(API.IMPORT_FILE_ATTR_NAME);
|
||||
if (fieldControl != null && fieldControl instanceof FileUploadSelection) {
|
||||
((FileUploadSelection) fieldControl).close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import org.eclipse.swt.layout.GridData;
|
|||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
|
@ -34,6 +36,8 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
|||
|
||||
public class FileUploadSelection extends Composite {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FileUploadSelection.class);
|
||||
|
||||
private static final long serialVersionUID = 5800153475027387363L;
|
||||
|
||||
private static final LocTextKey PLEASE_SELECT_TEXT =
|
||||
|
@ -48,6 +52,8 @@ public class FileUploadSelection extends Composite {
|
|||
|
||||
private Consumer<String> errorHandler;
|
||||
private InputStream inputStream;
|
||||
private final FileUploadHandler uploadHandler;
|
||||
private final InputReceiver inputReceiver;
|
||||
|
||||
public FileUploadSelection(
|
||||
final Composite parent,
|
||||
|
@ -70,12 +76,15 @@ public class FileUploadSelection extends Composite {
|
|||
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||
this.fileName.setLayoutData(new GridData());
|
||||
this.fileUpload = null;
|
||||
this.uploadHandler = null;
|
||||
this.inputReceiver = null;
|
||||
} else {
|
||||
this.fileUpload = new FileUpload(this, SWT.NONE);
|
||||
this.fileUpload.setImage(WidgetFactory.ImageIcon.IMPORT.getImage(parent.getDisplay()));
|
||||
this.fileUpload.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
|
||||
this.fileUpload.setToolTipText(this.i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||
final FileUploadHandler uploadHandler = new FileUploadHandler(new InputReceiver());
|
||||
this.inputReceiver = new InputReceiver();
|
||||
this.uploadHandler = new FileUploadHandler(this.inputReceiver);
|
||||
|
||||
this.fileName = new Label(this, SWT.NONE);
|
||||
this.fileName.setText(i18nSupport.getText(PLEASE_SELECT_TEXT));
|
||||
|
@ -93,7 +102,7 @@ public class FileUploadSelection extends Composite {
|
|||
}
|
||||
return;
|
||||
}
|
||||
FileUploadSelection.this.fileUpload.submit(uploadHandler.getUploadUrl());
|
||||
FileUploadSelection.this.fileUpload.submit(this.uploadHandler.getUploadUrl());
|
||||
FileUploadSelection.this.fileName.setText(fileName);
|
||||
FileUploadSelection.this.errorHandler.accept(null);
|
||||
});
|
||||
|
@ -101,6 +110,20 @@ public class FileUploadSelection extends Composite {
|
|||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (this.inputReceiver != null) {
|
||||
this.inputReceiver.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (this.uploadHandler != null) {
|
||||
this.uploadHandler.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
if (this.fileName != null) {
|
||||
return this.fileName.getText();
|
||||
|
@ -149,21 +172,37 @@ public class FileUploadSelection extends Composite {
|
|||
}
|
||||
|
||||
private final class InputReceiver extends FileUploadReceiver {
|
||||
private PipedInputStream pIn = null;
|
||||
private PipedOutputStream pOut = null;
|
||||
|
||||
@Override
|
||||
public void receive(final InputStream stream, final FileDetails details) throws IOException {
|
||||
final PipedInputStream pIn = new PipedInputStream();
|
||||
final PipedOutputStream pOut = new PipedOutputStream(pIn);
|
||||
if (this.pIn != null || this.pOut != null) {
|
||||
throw new IllegalStateException("InputReceiver already in use");
|
||||
}
|
||||
|
||||
FileUploadSelection.this.inputStream = pIn;
|
||||
this.pIn = new PipedInputStream();
|
||||
this.pOut = new PipedOutputStream(this.pIn);
|
||||
|
||||
FileUploadSelection.this.inputStream = this.pIn;
|
||||
|
||||
try {
|
||||
IOUtils.copyLarge(stream, pOut);
|
||||
IOUtils.copyLarge(stream, this.pOut);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
log.warn("IO error: {}", e.getMessage());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(pOut);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void close() {
|
||||
try {
|
||||
this.pOut.flush();
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to flush: ", e);
|
||||
}
|
||||
IOUtils.closeQuietly(this.pOut);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -241,6 +241,11 @@ public class ExamConfigImportHandler extends DefaultHandler {
|
|||
: top.name;
|
||||
final ConfigurationAttribute attribute = this.attributeResolver.apply(attrName);
|
||||
|
||||
if (attribute == null) {
|
||||
log.warn("*********************** Save null value: {}", attrName);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we have a simple values array
|
||||
if (attribute.type == AttributeType.MULTI_CHECKBOX_SELECTION
|
||||
|| attribute.type == AttributeType.MULTI_SELECTION) {
|
||||
|
|
|
@ -331,11 +331,15 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
.getOrThrow();
|
||||
|
||||
Future<Exception> streamDecrypted = null;
|
||||
InputStream cryptIn = null;
|
||||
PipedInputStream plainIn = null;
|
||||
PipedOutputStream cryptOut = null;
|
||||
InputStream unzippedIn = null;
|
||||
try {
|
||||
|
||||
final InputStream cryptIn = this.examConfigIO.unzip(input);
|
||||
final PipedInputStream plainIn = new PipedInputStream();
|
||||
final PipedOutputStream cryptOut = new PipedOutputStream(plainIn);
|
||||
cryptIn = this.examConfigIO.unzip(input);
|
||||
plainIn = new PipedInputStream();
|
||||
cryptOut = new PipedOutputStream(plainIn);
|
||||
|
||||
// decrypt
|
||||
streamDecrypted = this.sebConfigEncryptionService.streamDecrypted(
|
||||
|
@ -344,11 +348,11 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
EncryptionContext.contextOf(password));
|
||||
|
||||
// if zipped, unzip attach unzip stream first
|
||||
final InputStream _plainIn = this.examConfigIO.unzip(plainIn);
|
||||
unzippedIn = this.examConfigIO.unzip(plainIn);
|
||||
|
||||
// parse XML and import
|
||||
this.examConfigIO.importPlainXML(
|
||||
_plainIn,
|
||||
unzippedIn,
|
||||
newConfig.institutionId,
|
||||
newConfig.id);
|
||||
|
||||
|
@ -369,6 +373,11 @@ public class SebExamConfigServiceImpl implements SebExamConfigService {
|
|||
}
|
||||
|
||||
throw new RuntimeException("Failed to import SEB configuration. Cause is: " + e.getMessage());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(cryptIn);
|
||||
IOUtils.closeQuietly(plainIn);
|
||||
IOUtils.closeQuietly(cryptOut);
|
||||
IOUtils.closeQuietly(unzippedIn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -81,11 +81,13 @@ public class ZipServiceImpl implements ZipService {
|
|||
} finally {
|
||||
try {
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close OutputStream: ", e);
|
||||
}
|
||||
|
||||
IOUtils.closeQuietly(out);
|
||||
IOUtils.closeQuietly(zipInputStream);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Finish streaming asynchronous unzipping of SEB exam configuration data");
|
||||
}
|
||||
|
|
|
@ -8,17 +8,22 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -27,12 +32,14 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
|
@ -167,7 +174,7 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
|
|||
method = RequestMethod.POST,
|
||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
public Configuration importExamConfig(
|
||||
public Object importExamConfig(
|
||||
@PathVariable final Long modelId,
|
||||
@RequestHeader(name = API.IMPORT_PASSWORD_ATTR_NAME, required = false) final String password,
|
||||
@RequestParam(
|
||||
|
@ -176,11 +183,27 @@ public class ConfigurationNodeController extends EntityController<ConfigurationN
|
|||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||
final HttpServletRequest request) throws IOException {
|
||||
|
||||
return this.sebExamConfigService.importFromSEBFile(
|
||||
modelId,
|
||||
request.getInputStream(),
|
||||
password)
|
||||
.getOrThrow();
|
||||
final InputStream inputStream = new BufferedInputStream(request.getInputStream());
|
||||
try {
|
||||
|
||||
return this.sebExamConfigService.importFromSEBFile(
|
||||
modelId,
|
||||
inputStream,
|
||||
password)
|
||||
.getOrThrow();
|
||||
|
||||
} catch (final Exception e) {
|
||||
// NOTE: It seems that this has to be manually closed on error case
|
||||
// We expected that this is closed by the API but if this manual close is been left
|
||||
// some left-overs will affect strange behavior.
|
||||
// TODO: find a better solution for this
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
//throw e;
|
||||
return new ResponseEntity<>(
|
||||
Arrays.asList(APIMessage.ErrorMessage.UNEXPECTED.of(e.getMessage())),
|
||||
Utils.createJsonContentHeader(),
|
||||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`lms_clientsecret` VARCHAR(4000) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_type` VARCHAR(45) NOT NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(255) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(255) NULL,
|
||||
`active` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `setupInstitutionRef_idx` (`institution_id` ASC),
|
||||
|
|
|
@ -50,8 +50,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`lms_clientsecret` VARCHAR(4000) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_type` VARCHAR(45) NOT NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(255) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(255) NULL,
|
||||
`active` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `setupInstitutionRef_idx` (`institution_id` ASC),
|
||||
|
|
|
@ -41,8 +41,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`lms_clientsecret` VARCHAR(4000) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_type` VARCHAR(45) NOT NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(255) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(255) NULL,
|
||||
`active` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `setupInstitutionRef_idx` (`institution_id` ASC),
|
||||
|
|
|
@ -31,8 +31,8 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
`lms_clientsecret` VARCHAR(4000) NULL,
|
||||
`lms_rest_api_token` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_type` VARCHAR(45) NOT NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(4000) NULL,
|
||||
`lms_proxy_auth_username` VARCHAR(255) NULL,
|
||||
`lms_proxy_auth_secret` VARCHAR(255) NULL,
|
||||
`active` INT(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `setupInstitutionRef_idx` (`institution_id` ASC),
|
||||
|
|
Loading…
Reference in a new issue