From e8dfd11d9db721497deaa58f7da7e6cd0ffbd764 Mon Sep 17 00:00:00 2001 From: Olivier Maury <Olivier.Maury@inrae.fr> Date: Fri, 24 Jan 2025 10:32:54 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20permettre=20=C3=A0=20un=20admin=20de=20t?= =?UTF-8?q?=C3=A9l=C3=A9charger=20le=20fichier=20de=20m=C3=A9tadonn=C3=A9e?= =?UTF-8?q?s.=20fixes=20#10571?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + DEV_FR.md | 3 + .../sido/gwt/server/customuser.properties | 4 + .../sido/gwt/server/DataTransferts.java | 10 +- .../downloadfile/FileDownloadServlet.java | 89 ++--------- .../DownloadMetadataServlet.java | 119 ++++++-------- .../server/filter/IdentificationFilter.java | 4 + .../sido/gwt/server/mail/MailService.java | 7 +- .../gwt/server/metadata/MetadataHandler.java | 148 +++++++++--------- .../gwt/server/servlet/AbstractServlet.java | 127 +++++++++++++++ .../sido/gwt/shared/StringUtils.java | 27 +++- .../sido/gwt/shared/StringUtilsTest.java | 18 ++- 12 files changed, 323 insertions(+), 234 deletions(-) create mode 100644 sido-gwt/src/main/config/dev-om/fr/soeretempo/sido/gwt/server/customuser.properties create mode 100644 sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/servlet/AbstractServlet.java diff --git a/.gitignore b/.gitignore index 058c7850..24491601 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .checkstyle .classpath .factorypath +log logs .pmd .pmdruleset.xml diff --git a/DEV_FR.md b/DEV_FR.md index 33bcfbd0..c801bbd6 100644 --- a/DEV_FR.md +++ b/DEV_FR.md @@ -25,6 +25,9 @@ postgres=# CREATE USER sido WITH PASSWORD 'sido'; - créer la base de données applicative : ``` +$ createdb --owner=sido --encoding=UTF8 --locale=fr_FR.UTF-8 sido +# ou +$ psql postgres=# CREATE DATABASE sido WITH OWNER = sido ENCODING = 'UTF8' LC_COLLATE = 'fr_FR.UTF-8' LC_CTYPE = 'fr_FR.UTF-8'; ``` - quitter psql avec `\q` diff --git a/sido-gwt/src/main/config/dev-om/fr/soeretempo/sido/gwt/server/customuser.properties b/sido-gwt/src/main/config/dev-om/fr/soeretempo/sido/gwt/server/customuser.properties new file mode 100644 index 00000000..e354e9f9 --- /dev/null +++ b/sido-gwt/src/main/config/dev-om/fr/soeretempo/sido/gwt/server/customuser.properties @@ -0,0 +1,4 @@ +uid=omaury +username=Olivier Maury +email=Olivier.Maury@inrae.fr +organization=INRAE diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/DataTransferts.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/DataTransferts.java index b7fdd0b1..a6561de5 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/DataTransferts.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/DataTransferts.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -100,6 +101,7 @@ public final class DataTransferts { * @return data interface user */ public static DatasourceDTO toDto(final Datasource entity) { + Objects.requireNonNull(entity); final DatasourceDTO dto = new DatasourceDTO(); dto.setDatasourceId(entity.getId()); dto.setName(entity.getName()); @@ -195,13 +197,11 @@ public final class DataTransferts { dto.setOrganization(entity.getOrganization()); dto.setEmail(entity.getEmail()); dto.setEmailToConfirm(entity.getEmailToConfirm()); - dto.setCreated(formatter.format(Date.from( - entity.getDateCreate().atZone(ZoneId.systemDefault()).toInstant()))); - dto.setLastUpdate(formatter.format(Date.from( - entity.getDateUpdate().atZone(ZoneId.systemDefault()).toInstant()))); + dto.setCreated(formatter.format(localDateTimeToDate(entity.getDateCreate()))); + dto.setLastUpdate(formatter.format(localDateTimeToDate(entity.getDateUpdate()))); dto.setDatasources(datasourceToDto(entity.getDatasources())); dto.setWorkbook(workbooksToDtos(entity.getWorkbook())); - dto.setSidoAdmin(entity.getIsAdmin()); + dto.setSidoAdmin(Boolean.TRUE.equals(entity.getIsAdmin())); } return dto; } diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadfile/FileDownloadServlet.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadfile/FileDownloadServlet.java index 82cfc30f..3d2878e6 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadfile/FileDownloadServlet.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadfile/FileDownloadServlet.java @@ -18,21 +18,15 @@ package fr.soeretempo.sido.gwt.server.downloadfile; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.OutputStream; -import java.util.Locale; +import java.util.Optional; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; -import javax.servlet.ServletContext; import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import fr.soeretempo.sido.gwt.server.SessionAttribute; import fr.soeretempo.sido.gwt.server.SidoConfiguration; import fr.soeretempo.sido.gwt.server.SidoConfiguration.Key; import fr.soeretempo.sido.gwt.server.dao.DatasourceDao; @@ -40,6 +34,7 @@ import fr.soeretempo.sido.gwt.server.dao.WorkbookDao; import fr.soeretempo.sido.gwt.server.model.Datasource; import fr.soeretempo.sido.gwt.server.model.User; import fr.soeretempo.sido.gwt.server.model.Workbook; +import fr.soeretempo.sido.gwt.server.servlet.AbstractServlet; import fr.soeretempo.sido.verification.resources.I18n; import lombok.extern.log4j.Log4j2; @@ -49,29 +44,19 @@ import lombok.extern.log4j.Log4j2; @RequestScoped @WebServlet(urlPatterns = { "/SidoGwt/download" }) @Log4j2 -public class FileDownloadServlet extends HttpServlet { +public class FileDownloadServlet extends AbstractServlet { /** * serial ID. */ private static final long serialVersionUID = -8740967527638496181L; - /** - * Buffer size. - */ - public static final int BUFFER_SIZE = 10240 * 10240; - /** * config.properties. */ @Inject private SidoConfiguration config; - /** - * I18n strings from .properties. - */ - private I18n i18n; - /** * DAO for Datasource. * @@ -91,32 +76,23 @@ public class FileDownloadServlet extends HttpServlet { @Override public final void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { - String filePath = "", headerName = ""; - // user - final HttpSession session = request.getSession(); - final User user = (User) session - .getAttribute(SessionAttribute.USER.name()); - // I18n. - final String tag = (String) session.getAttribute( - SessionAttribute.LOCALE.name()); - Locale locale; - if (tag != null) { - locale = new Locale.Builder().setLanguageTag(tag).build(); - } else { - locale = request.getLocale(); + final Optional<User> userOptional = getUser(request, response); + if (userOptional.isEmpty()) { + return; } - i18n = new I18n( - "fr.soeretempo.sido.gwt.server.resources.messages", locale); + final User user = userOptional.get(); + + final I18n i18n = getI18n(request); if (config != null) { if (user == null) { - LOGGER.trace("1"); - response.setContentType("text/plain"); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, i18n.get("msgSessionExpired")); return; } else { - String fileName = ""; + final String fileName; + final String filePath; if (request.getParameter("idW") != null) { final Workbook work = workbookDao .findBy(Long.valueOf(request.getParameter("idW"))); @@ -160,62 +136,29 @@ public class FileDownloadServlet extends HttpServlet { response.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } - headerName = String.format("attachment; filename=\"%s\"", - fileName); try { // reads input file from an absolute path final File downloadFile = new File(filePath); if (!downloadFile.exists()) { LOGGER.warn("File not found at " + filePath); - response.setContentType("text/plain"); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); response.sendError(HttpServletResponse.SC_NOT_FOUND, i18n.get("msgDowloadFileProblem")); return; } - final FileInputStream inStream = new FileInputStream( - downloadFile); - // if you want to use a relative path to context root: - LOGGER.info("relativePath = " - + getServletContext().getRealPath("")); - // obtains ServletContext - final ServletContext context = getServletContext(); - // gets MIME type of the file - String mimeType = context.getMimeType(filePath); - if (mimeType == null) { - // set to binary type if MIME mapping not found - mimeType = "application/octet-stream"; - } - LOGGER.info("MIME type: " + mimeType); - // modifies response - response.setContentType(mimeType); - response.setContentLengthLong(downloadFile.length()); - // forces download - final String headerKey = "Content-Disposition"; - final String headerValue = headerName; - response.setHeader(headerKey, headerValue); - // obtains response's output stream - final OutputStream outStream = response.getOutputStream(); - final byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = -1; - while ((bytesRead = inStream.read(buffer)) != -1) { - outStream.write(buffer, 0, bytesRead); - } - inStream.close(); - outStream.close(); + writeFile(downloadFile, fileName, response); } catch (final Exception e) { - response.setContentType("text/plain"); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); LOGGER.catching(e); - return; } } } else { - response.setContentType("text/plain"); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); response.sendError(HttpServletResponse.SC_NOT_FOUND, i18n.get("msgConfigPropProblem")); - return; } } diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadmetadata/DownloadMetadataServlet.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadmetadata/DownloadMetadataServlet.java index d9557bdc..ad81f6c8 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadmetadata/DownloadMetadataServlet.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/downloadmetadata/DownloadMetadataServlet.java @@ -1,26 +1,28 @@ package fr.soeretempo.sido.gwt.server.downloadmetadata; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; +import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import fr.soeretempo.sido.gwt.server.SessionAttribute; import fr.soeretempo.sido.gwt.server.SidoConfiguration; +import fr.soeretempo.sido.gwt.server.dao.DatasetDao; import fr.soeretempo.sido.gwt.server.metadata.MetadataHandler; import fr.soeretempo.sido.gwt.server.model.Dataset; +import fr.soeretempo.sido.gwt.server.model.Datasource; import fr.soeretempo.sido.gwt.server.model.User; +import fr.soeretempo.sido.gwt.server.servlet.AbstractServlet; +import fr.soeretempo.sido.gwt.shared.StringUtils; import fr.soeretempo.sido.rs.HttpStatus; import lombok.extern.log4j.Log4j2; @@ -28,7 +30,7 @@ import lombok.extern.log4j.Log4j2; @WebServlet(urlPatterns = { "/SidoGwt/MetadataDownloadServlet" }) @MultipartConfig @Log4j2 -public class DownloadMetadataServlet extends HttpServlet { +public class DownloadMetadataServlet extends AbstractServlet { /** * UID. @@ -40,6 +42,20 @@ public class DownloadMetadataServlet extends HttpServlet { */ public static final int TAILLE_TAMPON = 10240 * 10240; + private static void bufferEmptyMetadataFile(final HttpServletResponse response, + final MetadataHandler metadataHandler) throws IOException { + LOGGER.traceEntry(); + try (InputStream inStream = metadataHandler.getEmptyMetadataFileInputStream()) { + writeFile(inStream, MetadataHandler.EMPTY_METADATA_FILE_NAME, response); + } + } + + /** + * DAO for dataset. + */ + @Inject + private DatasetDao datasetDao; + /** * config.properties. */ @@ -47,98 +63,53 @@ public class DownloadMetadataServlet extends HttpServlet { private SidoConfiguration config; @Override - public final void doGet(final HttpServletRequest request, - final HttpServletResponse response) throws IOException { + public final void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { LOGGER.traceEntry(); - final User user = (User) request.getSession() - .getAttribute(SessionAttribute.USER.name()); - if (user == null) { - response.sendError(HttpStatus.UNAUTHORIZED.value(), - "Session expired"); + final Optional<User> userOptional = getUser(request, response); + if (userOptional.isEmpty()) { return; } + final User user = userOptional.get(); final MetadataHandler metadataHandler = new MetadataHandler(null, config); - final String fileName = request.getParameter("name"); - final String datasetId = request.getParameter("datasetid"); - if (fileName == null || datasetId == null || fileName.isEmpty() || datasetId.isEmpty()) { + final String datasetIdStr = request.getParameter("datasetid"); + final Optional<Long> idOptional = StringUtils.parseLong(datasetIdStr); + if (datasetIdStr == null || datasetIdStr.isEmpty() || idOptional.isEmpty()) { bufferEmptyMetadataFile(response, metadataHandler); return; } - final Dataset dataset = getDataset(user, datasetId, fileName); + final Long datasetId = idOptional.get(); + final Dataset dataset = getDataset(user, datasetId); if (dataset == null) { response.sendError(HttpStatus.UNAUTHORIZED.value(), - "Unauthorized"); + "You're not authorized to download metadata file of dataset #" + datasetId); return; } final File downloadFile = metadataHandler.getMetadataFile(dataset); LOGGER.info("file Path = " + downloadFile.getPath()); if (!downloadFile.exists()) { response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), - "File missing"); + "Metadata file of dataset #" + datasetId + " does not exist."); return; } - // verif du format - if (downloadFile.getName().endsWith(".xlsx")) { - response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); - } else if (downloadFile.getName().endsWith(".xls")) { - response.setContentType("application/vnd.ms-excel"); - } else { - response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), - "Internal error, please contact administrator"); - return; - } - bufferFile(downloadFile, response); + writeFile(downloadFile, downloadFile.getName(), response); } - private void bufferEmptyMetadataFile(final HttpServletResponse response, final MetadataHandler metadataHandler) - throws IOException { - try (InputStream inStream = metadataHandler.getEmptyMetadataFileInputStream(); - OutputStream outStream = response.getOutputStream();) { - response.setHeader("Content-Disposition", - "attachment; filename=\"" - + MetadataHandler.EMPTY_METADATA_FILE_NAME + "\""); - // obtains response's output stream - final byte[] buffer = new byte[TAILLE_TAMPON]; - int bytesRead = -1; - while ((bytesRead = inStream.read(buffer)) != -1) { - outStream.write(buffer, 0, bytesRead); - } - } catch (final Exception e) { - LOGGER.catching(e); - response.setContentType("text/plain"); - response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), - "File missing"); + private Dataset getDataset(final User user, final Long datasetId) { + LOGGER.traceEntry(); + if (Boolean.TRUE.equals(user.getIsAdmin())) { + return datasetDao.findById(datasetId); } - } - - private void bufferFile(final File downloadFile, final HttpServletResponse response) throws IOException { - try (FileInputStream inStream = new FileInputStream(downloadFile); - OutputStream outStream = response.getOutputStream();) { - response.setContentLengthLong(downloadFile.length()); - response.setHeader("Content-Disposition", - "attachment; filename=\"" - + downloadFile.getName() + "\""); - // obtains response's output stream - final byte[] buffer = new byte[TAILLE_TAMPON]; - int bytesRead = -1; - while ((bytesRead = inStream.read(buffer)) != -1) { - outStream.write(buffer, 0, bytesRead); - } - } catch (final Exception e) { - LOGGER.catching(e); - response.setContentType("text/plain"); - response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), - "File missing"); + if (user.getDatasources().isEmpty()) { + LOGGER.info("Strange, no datasource for user {}", user.getUserName()); + return null; } - } - - private Dataset getDataset(final User user, final String datasetId, final String fileName) { final List<Dataset> accessibleDatasets = user.getDatasources().stream() - .map(datasource -> datasource .getDatasets()) - .flatMap(datasetList -> datasetList.stream()).collect(Collectors.toList()); + .map(Datasource::getDatasets) // + .flatMap(Collection<Dataset>::stream) // + .collect(Collectors.toList()); for (final Dataset dataset : accessibleDatasets) { - if (dataset.getId().equals(Long.parseLong(datasetId)) - && dataset.getMetadataFile().equals(fileName)) { + LOGGER.info("Accessible dataset: {}", dataset); + if (dataset.getId().equals(datasetId)) { return dataset; } } diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/filter/IdentificationFilter.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/filter/IdentificationFilter.java index 2256f3b6..71156e85 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/filter/IdentificationFilter.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/filter/IdentificationFilter.java @@ -43,6 +43,7 @@ import fr.soeretempo.sido.gwt.server.dao.UserDao; import fr.soeretempo.sido.gwt.server.model.User; import fr.soeretempo.sido.gwt.server.servlet.CookiesServlet; import fr.soeretempo.sido.rs.HttpStatus; +import lombok.extern.log4j.Log4j2; /** * Filter to identify the user. @@ -53,6 +54,7 @@ import fr.soeretempo.sido.rs.HttpStatus; * * @author melhasnaoui */ +@Log4j2 @WebFilter(urlPatterns = { "/", "/SidoGwt.html", "/SidoGwt/rpc/*" }) public final class IdentificationFilter implements Filter { @@ -131,7 +133,9 @@ public final class IdentificationFilter implements Filter { resp.sendRedirect(config.get(Key.APP_URL) + "/login" + localeTag); return; case "file": + LOGGER.info("Getting user from properties"); user = getUserFromProperties(); + LOGGER.info("Storing user in session: {}", user); storeUserInSession(session, user); chain.doFilter(request, response); break; diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/mail/MailService.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/mail/MailService.java index 1dae6c06..96897551 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/mail/MailService.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/mail/MailService.java @@ -152,6 +152,10 @@ public class MailService { * exception */ public void send(final Mail mail) throws SendMailException { + if (!isAvailable()) { + LOGGER.info("Properties not set, the email will not be sent!"); + return; + } String to; String from; final String subject = mail.getSubject(); @@ -203,8 +207,7 @@ public class MailService { } msg.setSubject(subject); msg.setSentDate(new Date()); - // If the desired charset is known, you can use - // setText(text, charset) + // If the desired charset is known, you can use setText(text, charset) msg.setContent(mail.getMessage(), mail.getFullMimeType()); if (!mail.getAttachements().isEmpty()) { diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/metadata/MetadataHandler.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/metadata/MetadataHandler.java index 2bffced7..1444b7cf 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/metadata/MetadataHandler.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/metadata/MetadataHandler.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Arrays; @@ -46,6 +47,16 @@ public class MetadataHandler { @Inject private MailService mailService; + /** + * DataSet DAO. + */ + private final DatasetDao datasetDao = new DatasetDaoImpl(); + + /** + * config.properties. + */ + private final SidoConfiguration config; + /** * Constructor. * @param setLocale locale used to generate error reports. @@ -56,15 +67,75 @@ public class MetadataHandler { config = sidoConfig; } + private MetadataReport checkMetadataFile(final File metadataFile) { + final MetadataParser parser = new MetadataParser(locale); + parser.parseMetadata(metadataFile, true); + return parser.getMetadataReport(); + } + /** - * DataSet DAO. + * Gets a facade for a deleted / empty dataset in the dataverse. + * @return minimal facade */ - private final DatasetDao datasetDao = new DatasetDaoImpl(); + public DatasetFacade getEmptyFacade() { + return DatasetFacade.builder().geographicBoundingBox(null) + .timePeriodCovered(null) + .title("Deleted").build(); + } /** - * config.properties. + * Retrieve the empty metadata file content. + * @return empty metadata file content from resource folder */ - private final SidoConfiguration config; + public InputStream getEmptyMetadataFileInputStream() { + return this.getClass().getResourceAsStream(EMPTY_METADATA_FILE_NAME); + } + + /** + * Get the MetadataReport with the facade loaded if all set correctly. + * @param datasetId dataset's id in sido + * @return a MetadataReport + */ + public MetadataReport getFacade(final long datasetId) { + LOGGER.traceEntry(); + final Dataset dataset = datasetDao.findById(datasetId); + final MetadataParser parser = new MetadataParser(locale); + parser.parseMetadata(getMetadataFile(dataset), false); + try { + final OutilsVerifXML verifXml = new OutilsVerifXML(config.get(Key.MODEL_DIR) + File.separator + + dataset.getDatasource().getFileParam()); + final Map<String, String[]> mappedColumns = verifXml.getMappedColumns(); + LOGGER.trace("Mapped columns in .xml: " + mappedColumns); + if (parser.getMetadataReport().getDatasetFacade() == null) { + throw new IOException("The DatasetFacade should not be null !"); + } else { + parser.parseAdditionnalMetadata(dataset, mappedColumns); + } + } catch (final JAXBException | IOException e) { + parser.getMetadataReport().addErrors(Arrays.asList("Something went wrong reading the parameter file (.xml)" + + " on the server. Please contact SIDO administration.")); + mailService.errorMail(e, config.get(Key.APP_URL), mailService.getAdditionnalInfos(dataset, null)); + LOGGER.catching(e); + } + LOGGER.traceExit(); + return parser.getMetadataReport(); + } + + /** + * Get the metadata file of a dataset (in sido filesystem). + * @param dataset the dataset object + * @return the file if present (metadata file is valid) null otherwise + */ + public File getMetadataFile(final Dataset dataset) { + final Path path = Paths.get(config.get(Key.INSERTED_DIR), dataset.getId().toString(), + dataset.getMetadataFile()); + final File metadataFile = path.toFile(); + if (metadataFile.exists()) { + return metadataFile; + } else { + return null; + } + } /** * Get the temporary folder for a metadata file for a specific dataset. @@ -125,12 +196,6 @@ public class MetadataHandler { } } - private MetadataReport checkMetadataFile(final File metadataFile) { - final MetadataParser parser = new MetadataParser(locale); - parser.parseMetadata(metadataFile, true); - return parser.getMetadataReport(); - } - /** * Save a metadata file in the temporary directory of the server. * @param filePart @@ -167,67 +232,4 @@ public class MetadataHandler { return null; } - /** - * Get the metadata file of a dataset (in sido filesystem). - * @param dataset the dataset object - * @return the file if present (metadata file is valid) null otherwise - */ - public File getMetadataFile(final Dataset dataset) { - final File metadataFile = - new File(config.get(Key.INSERTED_DIR) + dataset.getId() + "/" + dataset.getMetadataFile()); - if (metadataFile.exists()) { - return metadataFile; - } else { - return null; - } - } - - /** - * Get the MetadataReport with the facade loaded if all set correctly. - * @param datasetId dataset's id in sido - * @return a MetadataReport - */ - public MetadataReport getFacade(final long datasetId) { - LOGGER.traceEntry(); - final Dataset dataset = datasetDao.findById(datasetId); - final MetadataParser parser = new MetadataParser(locale); - parser.parseMetadata(getMetadataFile(dataset), false); - try { - final OutilsVerifXML verifXml = new OutilsVerifXML(config.get(Key.MODEL_DIR) + File.separator - + dataset.getDatasource().getFileParam()); - final Map<String, String[]> mappedColumns = verifXml.getMappedColumns(); - LOGGER.trace("Mapped columns in .xml: " + mappedColumns); - if (parser.getMetadataReport().getDatasetFacade() == null) { - throw new IOException("The DatasetFacade should not be null !"); - } else { - parser.parseAdditionnalMetadata(dataset, mappedColumns); - } - } catch (final JAXBException | IOException e) { - parser.getMetadataReport().addErrors(Arrays.asList("Something went wrong reading the parameter file (.xml)" - + " on the server. Please contact SIDO administration.")); - mailService.errorMail(e, config.get(Key.APP_URL), mailService.getAdditionnalInfos(dataset, null)); - LOGGER.catching(e); - } - LOGGER.traceExit(); - return parser.getMetadataReport(); - } - - /** - * Gets a facade for a deleted / empty dataset in the dataverse. - * @return minimal facade - */ - public DatasetFacade getEmptyFacade() { - return DatasetFacade.builder().geographicBoundingBox(null) - .timePeriodCovered(null) - .title("Deleted").build(); - } - - /** - * Retrieve the empty metadata file content. - * @return empty metadata file content from resource folder - */ - public InputStream getEmptyMetadataFileInputStream() { - return this.getClass().getResourceAsStream(EMPTY_METADATA_FILE_NAME); - } - } diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/servlet/AbstractServlet.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/servlet/AbstractServlet.java new file mode 100644 index 00000000..faad871d --- /dev/null +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/server/servlet/AbstractServlet.java @@ -0,0 +1,127 @@ +package fr.soeretempo.sido.gwt.server.servlet; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Locale; +import java.util.Optional; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import fr.soeretempo.sido.gwt.server.SessionAttribute; +import fr.soeretempo.sido.gwt.server.model.User; +import fr.soeretempo.sido.rs.HttpStatus; +import fr.soeretempo.sido.verification.resources.I18n; +import lombok.extern.log4j.Log4j2; + +/** + * Common methods for servlets. + * + * @author Olivier Maury + */ +@Log4j2 +public class AbstractServlet extends HttpServlet { + + /** + * UID for Serializable. + */ + private static final long serialVersionUID = 6952425792876348L; + + /** + * The content type of the response being sent to + * the client, including character encoding + * specification. + */ + protected static final String CONTENT_TYPE_TEXT_PLAIN = "text/plain;charset=UTF-8"; + + /** + * Write file to response output stream. + * + * @param inStream file to write + * @param fileName file name for the browser + * @param response response + * @exception IOException If an input or output exception occurs while sending + * error + */ + protected static void writeFile(final InputStream inStream, final String fileName, + final HttpServletResponse response) throws IOException { + final int bufferSize = 1048; + try (OutputStream outStream = response.getOutputStream()) { + response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); + final byte[] buffer = new byte[bufferSize]; + int bytesRead = -1; + while ((bytesRead = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, bytesRead); + } + } catch (final Exception e) { + LOGGER.error("Error while writing file to response output stream.", e); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); + response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), + "Error while writing file to response output stream."); + } + } + + /** + * @param request request to get session and locale tag + * @return I18n + */ + protected I18n getI18n(final HttpServletRequest request) { + // I18n. + final String tag = (String) request.getSession().getAttribute(SessionAttribute.LOCALE.name()); + final Locale locale; + if (tag != null) { + locale = new Locale.Builder().setLanguageTag(tag).build(); + } else { + locale = request.getLocale(); + } + return new I18n("fr.soeretempo.sido.gwt.server.resources.messages", locale); + } + + /** + * @param request request to get session + * @param response response to send error + * @return user from session or empty if error was sent to response + * @exception IOException If an input or output exception occurs + */ + protected Optional<User> getUser(final HttpServletRequest request, final HttpServletResponse response) + throws IOException { + final User user = (User) request.getSession().getAttribute(SessionAttribute.USER.name()); + if (user == null) { + final I18n i18n = getI18n(request); + response.setContentType(CONTENT_TYPE_TEXT_PLAIN); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, i18n.get("msgSessionExpired")); + return Optional.empty(); + } + return Optional.of(user); + } + + /** + * Write file to response output stream. + * + * @param file file to write + * @param fileName file name for the browser + * @param response response + * @exception IOException If an input or output exception occurs while sending + * error + */ + protected void writeFile(final File file, final String fileName, final HttpServletResponse response) + throws IOException { + try (FileInputStream inStream = new FileInputStream(file)) { + response.setContentLengthLong(file.length()); + // obtains ServletContext + final ServletContext context = getServletContext(); + // gets MIME type of the file + String mimeType = context.getMimeType(file.getAbsolutePath()); + if (mimeType == null) { + // set to binary type if MIME mapping not found + mimeType = "application/octet-stream"; + } + writeFile(inStream, fileName, response); + } + } +} diff --git a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/shared/StringUtils.java b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/shared/StringUtils.java index 7a9ff1ae..1d741136 100644 --- a/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/shared/StringUtils.java +++ b/sido-gwt/src/main/java/fr/soeretempo/sido/gwt/shared/StringUtils.java @@ -17,6 +17,8 @@ */ package fr.soeretempo.sido.gwt.shared; +import java.util.Optional; + import lombok.NonNull; /** @@ -35,12 +37,6 @@ public final class StringUtils { return path.substring(index + 1); } - /** - * Construct. - */ - private StringUtils() { - } - /** * Accented characters for normalization. */ @@ -59,4 +55,23 @@ public final class StringUtils { return unaccentedResult.toLowerCase(); } + /** + * @param value String to parse + * @return parsed or empty(). + */ + public static Optional<Long> parseLong(final String value) { + try { + final Long parsed = Long.valueOf(value); + return Optional.of(parsed); + } catch (final Exception e) { + + } + return Optional.empty(); + } + + /** + * Construct. + */ + private StringUtils() { + } } diff --git a/sido-gwt/src/test/java/fr/soeretempo/sido/gwt/shared/StringUtilsTest.java b/sido-gwt/src/test/java/fr/soeretempo/sido/gwt/shared/StringUtilsTest.java index d763161c..67afb8af 100644 --- a/sido-gwt/src/test/java/fr/soeretempo/sido/gwt/shared/StringUtilsTest.java +++ b/sido-gwt/src/test/java/fr/soeretempo/sido/gwt/shared/StringUtilsTest.java @@ -17,20 +17,36 @@ */ package fr.soeretempo.sido.gwt.shared; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.Optional; + import org.junit.Test; /** * @author melhasnaoui + * @author Olivier Maury */ public class StringUtilsTest { - @Test() + @Test public void getFileNameFromPathTest() { final String path = "C:\\fakepath\\fichier.extension"; final String result = StringUtils.getFileNameFromPath(path); assertTrue(result.equals("fichier.extension")); } + @Test + public void parseLong() { + assertTrue(StringUtils.parseLong(null).isEmpty()); + assertTrue(StringUtils.parseLong("").isEmpty()); + assertTrue(StringUtils.parseLong("test").isEmpty()); + final String value = "42"; + final Optional<Long> expected = Optional.of(42L); + final Optional<Long> actual = StringUtils.parseLong(value); + final String message = "42 must be found!"; + assertEquals(message, expected, actual); + } + } -- GitLab