diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/UserDao.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/UserDao.java index 972593a0..a0d20c1c 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/UserDao.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/UserDao.java @@ -228,7 +228,7 @@ public class UserDao { Map parameterMap = new HashMap(); List criteriaList = new ArrayList(); - StringBuilder sb = new StringBuilder("select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3"); + StringBuilder sb = new StringBuilder("select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3, u.USE_STORAGECURRENT_N as c4, u.USE_STORAGEQUOTA_N as c5"); sb.append(" from T_USER u "); // Add search criterias @@ -257,6 +257,8 @@ public class UserDao { userDto.setUsername((String) o[i++]); userDto.setEmail((String) o[i++]); userDto.setCreateTimestamp(((Timestamp) o[i++]).getTime()); + userDto.setStorageCurrent(((Number) o[i++]).longValue()); + userDto.setStorageQuota(((Number) o[i++]).longValue()); userDtoList.add(userDto); } paginatedList.setResultList(userDtoList); diff --git a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/UserDto.java b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/UserDto.java index 956d0c90..2dda296e 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/UserDto.java +++ b/docs-core/src/main/java/com/sismics/docs/core/dao/jpa/dto/UserDto.java @@ -1,5 +1,6 @@ package com.sismics.docs.core.dao.jpa.dto; + /** * User DTO. * @@ -26,6 +27,16 @@ public class UserDto { */ private Long createTimestamp; + /** + * Storage quota. + */ + private Long storageQuota; + + /** + * Storage current usage. + */ + private Long storageCurrent; + /** * Getter of id. * @@ -88,6 +99,22 @@ public class UserDto { public Long getCreateTimestamp() { return createTimestamp; } + + public Long getStorageQuota() { + return storageQuota; + } + + public void setStorageQuota(Long storageQuota) { + this.storageQuota = storageQuota; + } + + public Long getStorageCurrent() { + return storageCurrent; + } + + public void setStorageCurrent(Long storageCurrent) { + this.storageCurrent = storageCurrent; + } /** * Setter of createTimestamp. diff --git a/docs-core/src/main/java/com/sismics/docs/core/service/IndexingService.java b/docs-core/src/main/java/com/sismics/docs/core/service/IndexingService.java index d5988d3c..3efd055b 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/service/IndexingService.java +++ b/docs-core/src/main/java/com/sismics/docs/core/service/IndexingService.java @@ -1,7 +1,7 @@ package com.sismics.docs.core.service; -import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.concurrent.TimeUnit; import org.apache.lucene.index.DirectoryReader; @@ -56,10 +56,10 @@ public class IndexingService extends AbstractScheduledService { directory = new RAMDirectory(); log.info("Using RAM Lucene storage"); } else if (luceneStorageConfig.equals(Constants.LUCENE_DIRECTORY_STORAGE_FILE)) { - File luceneDirectory = DirectoryUtil.getLuceneDirectory(); + Path luceneDirectory = DirectoryUtil.getLuceneDirectory(); log.info("Using file Lucene storage: {}", luceneDirectory); try { - directory = new SimpleFSDirectory(luceneDirectory, new SimpleFSLockFactory()); + directory = new SimpleFSDirectory(luceneDirectory.toFile(), new SimpleFSLockFactory()); } catch (IOException e) { log.error("Error initializing Lucene index", e); } diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java b/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java index dfbab290..7f947157 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java +++ b/docs-core/src/main/java/com/sismics/docs/core/util/DirectoryUtil.java @@ -1,6 +1,9 @@ package com.sismics.docs.core.util; -import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.apache.commons.lang.StringUtils; @@ -17,27 +20,31 @@ public class DirectoryUtil { * * @return Base data directory */ - public static File getBaseDataDirectory() { - File baseDataDir = null; + public static Path getBaseDataDirectory() { + Path baseDataDir = null; if (StringUtils.isNotBlank(EnvironmentUtil.getDocsHome())) { // If the docs.home property is set then use it - baseDataDir = new File(EnvironmentUtil.getDocsHome()); + baseDataDir = Paths.get(EnvironmentUtil.getDocsHome()); } else if (EnvironmentUtil.isUnitTest()) { // For unit testing, use a temporary directory - baseDataDir = new File(System.getProperty("java.io.tmpdir")); + baseDataDir = Paths.get(System.getProperty("java.io.tmpdir")); } else { // We are in a webapp environment and nothing is specified, use the default directory for this OS if (EnvironmentUtil.isUnix()) { - baseDataDir = new File("/var/docs"); + baseDataDir = Paths.get("/var/docs"); } if (EnvironmentUtil.isWindows()) { - baseDataDir = new File(EnvironmentUtil.getWindowsAppData() + "\\Sismics\\Docs"); + baseDataDir = Paths.get(EnvironmentUtil.getWindowsAppData() + "\\Sismics\\Docs"); } else if (EnvironmentUtil.isMacOs()) { - baseDataDir = new File(EnvironmentUtil.getMacOsUserHome() + "/Library/Sismics/Docs"); + baseDataDir = Paths.get(EnvironmentUtil.getMacOsUserHome() + "/Library/Sismics/Docs"); } } - if (baseDataDir != null && !baseDataDir.isDirectory()) { - baseDataDir.mkdirs(); + if (baseDataDir != null && !Files.isDirectory(baseDataDir)) { + try { + Files.createDirectories(baseDataDir); + } catch (IOException e) { + throw new RuntimeException(e); + } } return baseDataDir; @@ -48,7 +55,7 @@ public class DirectoryUtil { * * @return Database directory. */ - public static File getDbDirectory() { + public static Path getDbDirectory() { return getDataSubDirectory("db"); } @@ -57,7 +64,7 @@ public class DirectoryUtil { * * @return Lucene indexes directory. */ - public static File getLuceneDirectory() { + public static Path getLuceneDirectory() { return getDataSubDirectory("lucene"); } @@ -66,7 +73,7 @@ public class DirectoryUtil { * * @return Storage directory. */ - public static File getStorageDirectory() { + public static Path getStorageDirectory() { return getDataSubDirectory("storage"); } @@ -75,7 +82,7 @@ public class DirectoryUtil { * * @return Log directory. */ - public static File getLogDirectory() { + public static Path getLogDirectory() { return getDataSubDirectory("log"); } @@ -84,11 +91,15 @@ public class DirectoryUtil { * * @return Subdirectory */ - private static File getDataSubDirectory(String subdirectory) { - File baseDataDir = getBaseDataDirectory(); - File directory = new File(baseDataDir.getPath() + File.separator + subdirectory); - if (!directory.isDirectory()) { - directory.mkdirs(); + private static Path getDataSubDirectory(String subdirectory) { + Path baseDataDir = getBaseDataDirectory(); + Path directory = baseDataDir.resolve(subdirectory); + if (!Files.isDirectory(directory)) { + try { + Files.createDirectories(directory); + } catch (IOException e) { + throw new RuntimeException(e); + } } return directory; } diff --git a/docs-core/src/main/java/com/sismics/docs/core/util/FileUtil.java b/docs-core/src/main/java/com/sismics/docs/core/util/FileUtil.java index 40e04e15..d836e94b 100644 --- a/docs-core/src/main/java/com/sismics/docs/core/util/FileUtil.java +++ b/docs-core/src/main/java/com/sismics/docs/core/util/FileUtil.java @@ -1,13 +1,11 @@ package com.sismics.docs.core.util; import java.awt.image.BufferedImage; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; @@ -132,7 +130,7 @@ public class FileUtil { */ public static void save(InputStream inputStream, File file, String privateKey) throws Exception { Cipher cipher = EncryptionUtil.getEncryptionCipher(privateKey); - Path path = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId()); + Path path = DirectoryUtil.getStorageDirectory().resolve(file.getId()); Files.copy(new CipherInputStream(inputStream, cipher), path); // Generate file variations @@ -172,21 +170,15 @@ public class FileUtil { image.flush(); // Write "web" encrypted image - java.io.File outputFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId() + "_web").toFile(); - OutputStream outputStream = new CipherOutputStream(new FileOutputStream(outputFile), cipher); - try { + Path outputFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_web"); + try (OutputStream outputStream = new CipherOutputStream(Files.newOutputStream(outputFile), cipher)) { ImageUtil.writeJpeg(web, outputStream); - } finally { - outputStream.close(); } // Write "thumb" encrypted image - outputFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId() + "_thumb").toFile(); - outputStream = new CipherOutputStream(new FileOutputStream(outputFile), cipher); - try { + outputFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_thumb"); + try (OutputStream outputStream = new CipherOutputStream(Files.newOutputStream(outputFile), cipher)) { ImageUtil.writeJpeg(thumbnail, outputStream); - } finally { - outputStream.close(); } } } @@ -195,20 +187,21 @@ public class FileUtil { * Remove a file from the storage filesystem. * * @param file File to delete + * @throws IOException */ - public static void delete(File file) { - java.io.File storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId()).toFile(); - java.io.File webFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId() + "_web").toFile(); - java.io.File thumbnailFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId() + "_thumb").toFile(); + public static void delete(File file) throws IOException { + Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file.getId()); + Path webFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_web"); + Path thumbnailFile = DirectoryUtil.getStorageDirectory().resolve(file.getId() + "_thumb"); - if (storedFile.exists()) { - storedFile.delete(); + if (Files.exists(storedFile)) { + Files.delete(storedFile); } - if (webFile.exists()) { - webFile.delete(); + if (Files.exists(webFile)) { + Files.delete(webFile); } - if (thumbnailFile.exists()) { - thumbnailFile.delete(); + if (Files.exists(thumbnailFile)) { + Files.delete(thumbnailFile); } } } diff --git a/docs-core/src/main/java/com/sismics/util/jpa/EMF.java b/docs-core/src/main/java/com/sismics/util/jpa/EMF.java index 7dbc8746..01287b9e 100644 --- a/docs-core/src/main/java/com/sismics/util/jpa/EMF.java +++ b/docs-core/src/main/java/com/sismics/util/jpa/EMF.java @@ -1,6 +1,16 @@ package com.sismics.util.jpa; -import com.sismics.docs.core.util.DirectoryUtil; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + import org.hibernate.cfg.Environment; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.ServiceRegistry; @@ -8,15 +18,7 @@ import org.hibernate.service.ServiceRegistryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.persistence.EntityManagerFactory; -import javax.persistence.Persistence; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; +import com.sismics.docs.core.util.DirectoryUtil; /** * Entity manager factory. @@ -79,8 +81,8 @@ public final class EMF { log.info("Configuring EntityManager from environment parameters"); Map props = new HashMap(); props.put("hibernate.connection.driver_class", "org.h2.Driver"); - File dbDirectory = DirectoryUtil.getDbDirectory(); - String dbFile = dbDirectory.getAbsoluteFile() + File.separator + "docs"; + Path dbDirectory = DirectoryUtil.getDbDirectory(); + String dbFile = dbDirectory.resolve("docs").toAbsolutePath().toString(); props.put("hibernate.connection.url", "jdbc:h2:file:" + dbFile + ";CACHE_SIZE=65536"); props.put("hibernate.connection.username", "sa"); props.put("hibernate.hbm2ddl.auto", "none"); diff --git a/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java b/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java index 68e53793..f3eff148 100644 --- a/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java +++ b/docs-web-common/src/main/java/com/sismics/util/filter/RequestContextFilter.java @@ -1,6 +1,5 @@ package com.sismics.util.filter; -import java.io.File; import java.io.IOException; import java.text.MessageFormat; @@ -44,20 +43,19 @@ public class RequestContextFilter implements Filter { if (!filterConfig.getServletContext().getServerInfo().startsWith("Grizzly")) { EnvironmentUtil.setWebappContext(true); } - File baseDataDirectory = null; try { - baseDataDirectory = DirectoryUtil.getBaseDataDirectory(); + if (log.isInfoEnabled()) { + log.info(MessageFormat.format("Using base data directory: {0}", DirectoryUtil.getBaseDataDirectory())); + } } catch (Exception e) { log.error("Error initializing base data directory", e); } - if (log.isInfoEnabled()) { - log.info(MessageFormat.format("Using base data directory: {0}", baseDataDirectory.toString())); - } + // Initialize file logger RollingFileAppender fileAppender = new RollingFileAppender(); fileAppender.setName("FILE"); - fileAppender.setFile(DirectoryUtil.getLogDirectory() + File.separator + "docs.log"); + fileAppender.setFile(DirectoryUtil.getLogDirectory().resolve("docs.log").toString()); fileAppender.setLayout(new PatternLayout("%d{DATE} %p %l %m %n")); fileAppender.setThreshold(Level.INFO); fileAppender.setAppend(true); diff --git a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java index 80fc4fb9..283a76a6 100644 --- a/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java +++ b/docs-web-common/src/test/java/com/sismics/docs/rest/BaseJerseyTest.java @@ -1,8 +1,6 @@ package com.sismics.docs.rest; -import java.io.File; import java.net.URI; -import java.net.URLDecoder; import javax.ws.rs.core.Application; import javax.ws.rs.core.UriBuilder; @@ -63,8 +61,7 @@ public abstract class BaseJerseyTest extends JerseyTest { clientUtil = new ClientUtil(target()); - String httpRoot = URLDecoder.decode(new File(getClass().getResource("/").getFile()).getAbsolutePath(), "utf-8"); - httpServer = HttpServer.createSimpleServer(httpRoot, "localhost", getPort()); + httpServer = HttpServer.createSimpleServer(getClass().getResource("/").getFile(), "localhost", getPort()); WebappContext context = new WebappContext("GrizzlyContext", "/docs"); context.addFilter("requestContextFilter", RequestContextFilter.class) .addMappingForUrlPatterns(null, "/*"); diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java index b8992d37..d433dfd4 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/AppResource.java @@ -1,5 +1,8 @@ package com.sismics.docs.rest.resource; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -165,13 +168,16 @@ public class AppResource extends BaseResource { } // Check if each stored file is valid - java.io.File[] storedFileList = DirectoryUtil.getStorageDirectory().listFiles(); - for (java.io.File storedFile : storedFileList) { - String fileName = storedFile.getName(); - String[] fileNameArray = fileName.split("_"); - if (!fileMap.containsKey(fileNameArray[0])) { - storedFile.delete(); + try (DirectoryStream storedFileList = Files.newDirectoryStream(DirectoryUtil.getStorageDirectory())) { + for (java.nio.file.Path storedFile : storedFileList) { + String fileName = storedFile.getFileName().toString(); + String[] fileNameArray = fileName.split("_"); + if (!fileMap.containsKey(fileNameArray[0])) { + Files.delete(storedFile); + } } + } catch (IOException e) { + throw new ServerException("FileError", "Error deleting orphan files", e); } // Always return OK diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java index ffdec588..694ed8f8 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/FileResource.java @@ -1,10 +1,10 @@ package com.sismics.docs.rest.resource; import java.io.ByteArrayInputStream; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; import java.nio.file.Paths; import java.text.MessageFormat; import java.text.SimpleDateFormat; @@ -123,6 +123,11 @@ public class FileResource extends BaseResource { throw new ClientException("InvalidFileType", "File type not recognized"); } + // Validate quota + if (user.getStorageCurrent() + fileData.length > user.getStorageQuota()) { + throw new ClientException("QuotaReached", "Quota limit reached"); + } + try { // Get files of this document FileDao fileDao = new FileDao(); @@ -144,6 +149,10 @@ public class FileResource extends BaseResource { // Save the file FileUtil.save(fileInputStream, file, user.getPrivateKey()); + // Update the user quota + user.setStorageCurrent(user.getStorageCurrent() + fileData.length); + userDao.update(user); + // Raise a new file created event if we have a document if (documentId != null) { FileCreatedAsyncEvent fileCreatedAsyncEvent = new FileCreatedAsyncEvent(); @@ -206,8 +215,8 @@ public class FileResource extends BaseResource { // Raise a new file created event (it wasn't sent during file creation) try { - java.io.File storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), id).toFile(); - InputStream fileInputStream = new FileInputStream(storedfile); + java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(id); + InputStream fileInputStream = Files.newInputStream(storedFile); final InputStream responseInputStream = EncryptionUtil.decryptInputStream(fileInputStream, user.getPrivateKey()); FileCreatedAsyncEvent fileCreatedAsyncEvent = new FileCreatedAsyncEvent(); fileCreatedAsyncEvent.setDocument(document); @@ -341,6 +350,17 @@ public class FileResource extends BaseResource { // Delete the file fileDao.delete(file.getId()); + // Update the user quota + UserDao userDao = new UserDao(); + User user = userDao.getById(principal.getId()); + java.nio.file.Path storedFile = DirectoryUtil.getStorageDirectory().resolve(id); + try { + user.setStorageCurrent(user.getStorageCurrent() - Files.size(storedFile)); + userDao.update(user); + } catch (IOException e) { + // The file doesn't exists on disk, which is weird, but not fatal + } + // Raise a new file deleted event FileDeletedAsyncEvent fileDeletedAsyncEvent = new FileDeletedAsyncEvent(); fileDeletedAsyncEvent.setFile(file); @@ -396,30 +416,33 @@ public class FileResource extends BaseResource { // Get the stored file - java.io.File storedfile; + java.nio.file.Path storedFile; String mimeType; boolean decrypt = false; if (size != null) { - storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), fileId + "_" + size).toFile(); + storedFile = DirectoryUtil.getStorageDirectory().resolve(fileId + "_" + size); mimeType = MimeType.IMAGE_JPEG; // Thumbnails are JPEG decrypt = true; // Thumbnails are encrypted - if (!storedfile.exists()) { - storedfile = new java.io.File(getClass().getResource("/image/file.png").getFile()); + if (!Files.exists(storedFile)) { + storedFile = Paths.get(getClass().getResource("/image/file.png").getFile()); mimeType = MimeType.IMAGE_PNG; decrypt = false; } } else { - storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), fileId).toFile(); + storedFile = DirectoryUtil.getStorageDirectory().resolve(fileId); mimeType = file.getMimeType(); decrypt = true; // Original files are encrypted } // Stream the output and decrypt it if necessary StreamingOutput stream; + // A file is always encrypted by the creator of it User user = userDao.getById(file.getUserId()); + + // Write the decrypted file to the output try { - InputStream fileInputStream = new FileInputStream(storedfile); + InputStream fileInputStream = Files.newInputStream(storedFile); final InputStream responseInputStream = decrypt ? EncryptionUtil.decryptInputStream(fileInputStream, user.getPrivateKey()) : fileInputStream; @@ -484,8 +507,8 @@ public class FileResource extends BaseResource { // Add each file to the ZIP stream int index = 0; for (File file : fileList) { - java.io.File storedfile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file.getId()).toFile(); - InputStream fileInputStream = new FileInputStream(storedfile); + java.nio.file.Path storedfile = DirectoryUtil.getStorageDirectory().resolve(file.getId()); + InputStream fileInputStream = Files.newInputStream(storedfile); // Add the decrypted file to the ZIP stream // Files are encrypted by the creator of them diff --git a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java index 741283bc..a4da17bb 100644 --- a/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java +++ b/docs-web/src/main/java/com/sismics/docs/rest/resource/UserResource.java @@ -489,6 +489,8 @@ public class UserResource extends BaseResource { .add("id", userDto.getId()) .add("username", userDto.getUsername()) .add("email", userDto.getEmail()) + .add("storage_quota", userDto.getStorageQuota()) + .add("storage_current", userDto.getStorageCurrent()) .add("create_date", userDto.getCreateTimestamp())); } diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java index e73cdcf8..3f1433fb 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestDocumentResource.java @@ -1,7 +1,6 @@ package com.sismics.docs.rest; import java.io.InputStream; -import java.nio.file.Paths; import java.util.Date; import javax.json.JsonArray; @@ -237,9 +236,9 @@ public class TestDocumentResource extends BaseJerseyTest { Assert.assertEquals("ok", json.getString("status")); // Check that the associated files are deleted from FS - java.io.File storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id).toFile(); - java.io.File webFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id + "_web").toFile(); - java.io.File thumbnailFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id + "_thumb").toFile(); + java.io.File storedFile = DirectoryUtil.getStorageDirectory().resolve(file1Id).toFile(); + java.io.File webFile = DirectoryUtil.getStorageDirectory().resolve(file1Id + "_web").toFile(); + java.io.File thumbnailFile = DirectoryUtil.getStorageDirectory().resolve(file1Id + "_thumb").toFile(); Assert.assertFalse(storedFile.exists()); Assert.assertFalse(webFile.exists()); Assert.assertFalse(thumbnailFile.exists()); diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java index 1fa8f03f..9d48fe41 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestFileResource.java @@ -1,9 +1,9 @@ package com.sismics.docs.rest; import java.io.BufferedInputStream; -import java.io.FileInputStream; import java.io.InputStream; -import java.nio.file.Paths; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Date; import javax.json.JsonArray; @@ -121,8 +121,8 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertTrue(fileBytes.length > 0); // Check that the files are not readable directly from FS - java.io.File storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id).toFile(); - try (InputStream storedFileInputStream = new BufferedInputStream(new FileInputStream(storedFile))) { + Path storedFile = DirectoryUtil.getStorageDirectory().resolve(file1Id); + try (InputStream storedFileInputStream = new BufferedInputStream(Files.newInputStream(storedFile))) { Assert.assertNull(MimeTypeUtil.guessMimeType(storedFileInputStream)); } @@ -179,12 +179,12 @@ public class TestFileResource extends BaseJerseyTest { Assert.assertEquals(Status.NOT_FOUND, Status.fromStatusCode(response.getStatus())); // Check that files are deleted from FS - storedFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id).toFile(); - java.io.File webFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id + "_web").toFile(); - java.io.File thumbnailFile = Paths.get(DirectoryUtil.getStorageDirectory().getPath(), file1Id + "_thumb").toFile(); - Assert.assertFalse(storedFile.exists()); - Assert.assertFalse(webFile.exists()); - Assert.assertFalse(thumbnailFile.exists()); + storedFile = DirectoryUtil.getStorageDirectory().resolve(file1Id); + Path webFile = DirectoryUtil.getStorageDirectory().resolve(file1Id + "_web"); + Path thumbnailFile = DirectoryUtil.getStorageDirectory().resolve(file1Id + "_thumb"); + Assert.assertFalse(Files.exists(storedFile)); + Assert.assertFalse(Files.exists(webFile)); + Assert.assertFalse(Files.exists(thumbnailFile)); // Get all files from a document json = target().path("/file/list") @@ -198,7 +198,7 @@ public class TestFileResource extends BaseJerseyTest { @Test public void testOrphanFile() throws Exception { - // Login file1 + // Login file2 clientUtil.createUser("file2"); String file2AuthenticationToken = clientUtil.login("file2"); @@ -280,4 +280,97 @@ public class TestFileResource extends BaseJerseyTest { .delete(JsonObject.class); Assert.assertEquals("ok", json.getString("status")); } + + @Test + public void testQuota() throws Exception { + // Login file_quota + clientUtil.createUser("file_quota"); + String fileQuotaAuthenticationToken = clientUtil.login("file_quota"); + + // Add a file (292641 bytes large) + String file1Id = null; + try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { + StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); + try (FormDataMultiPart multiPart = new FormDataMultiPart()) { + JsonObject json = target() + .register(MultiPartFeature.class) + .path("/file").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), + MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); + file1Id = json.getString("id"); + Assert.assertNotNull(file1Id); + } + } + + // Check current quota + JsonObject json = target().path("/user").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .get(JsonObject.class); + Assert.assertEquals(292641l, json.getJsonNumber("storage_current").longValue()); + + // Add a file (292641 bytes large) + try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { + StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); + try (FormDataMultiPart multiPart = new FormDataMultiPart()) { + target() + .register(MultiPartFeature.class) + .path("/file").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), + MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); + } + } + + // Check current quota + json = target().path("/user").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .get(JsonObject.class); + Assert.assertEquals(585282l, json.getJsonNumber("storage_current").longValue()); + + // Add a file (292641 bytes large) + try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { + StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); + try (FormDataMultiPart multiPart = new FormDataMultiPart()) { + target() + .register(MultiPartFeature.class) + .path("/file").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), + MediaType.MULTIPART_FORM_DATA_TYPE), JsonObject.class); + } + } + + // Check current quota + json = target().path("/user").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .get(JsonObject.class); + Assert.assertEquals(877923l, json.getJsonNumber("storage_current").longValue()); + + // Add a file (292641 bytes large) + try (InputStream is = Resources.getResource("file/Einstein-Roosevelt-letter.png").openStream()) { + StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart("file", is, "Einstein-Roosevelt-letter.png"); + try (FormDataMultiPart multiPart = new FormDataMultiPart()) { + Response response = target() + .register(MultiPartFeature.class) + .path("/file").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .put(Entity.entity(multiPart.bodyPart(streamDataBodyPart), + MediaType.MULTIPART_FORM_DATA_TYPE)); + Assert.assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + } + } + + // Deletes a file + json = target().path("/file/" + file1Id).request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .delete(JsonObject.class); + Assert.assertEquals("ok", json.getString("status")); + + // Check current quota + json = target().path("/user").request() + .cookie(TokenBasedSecurityFilter.COOKIE_NAME, fileQuotaAuthenticationToken) + .get(JsonObject.class); + Assert.assertEquals(585282l, json.getJsonNumber("storage_current").longValue()); + } } \ No newline at end of file diff --git a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java index bf8f6328..a67ce500 100644 --- a/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java +++ b/docs-web/src/test/java/com/sismics/docs/rest/TestUserResource.java @@ -48,6 +48,13 @@ public class TestUserResource extends BaseJerseyTest { .get(JsonObject.class); JsonArray users = json.getJsonArray("users"); Assert.assertTrue(users.size() > 0); + JsonObject user = users.getJsonObject(0); + Assert.assertNotNull(user.getString("id")); + Assert.assertNotNull(user.getString("username")); + Assert.assertNotNull(user.getString("email")); + Assert.assertNotNull(user.getJsonNumber("storage_quota")); + Assert.assertNotNull(user.getJsonNumber("storage_current")); + Assert.assertNotNull(user.getJsonNumber("create_date")); // Create a user KO (login length validation) Response response = target().path("/user").request()