@@ -44,6 +44,11 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>org.flywaydb</groupId>-->
|
<!-- <groupId>org.flywaydb</groupId>-->
|
||||||
<!-- <artifactId>flyway-core</artifactId>-->
|
<!-- <artifactId>flyway-core</artifactId>-->
|
||||||
|
|||||||
@@ -127,6 +127,15 @@ public class FileSystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean delete(Path path) {
|
||||||
|
try {
|
||||||
|
// TODO does only delete dirs if they are empty - but maybe we want that?
|
||||||
|
return Files.deleteIfExists(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileSystemServiceException("Could not delete file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] get(Path path) {
|
public byte[] get(Path path) {
|
||||||
try {
|
try {
|
||||||
return Files.readAllBytes(path);
|
return Files.readAllBytes(path);
|
||||||
|
|||||||
@@ -67,12 +67,30 @@ public class LocationTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentLocation(String navigateTo) {
|
public void setCurrentLocation(String navigateTo) {
|
||||||
validate(navigateTo);
|
validate_internal(navigateTo);
|
||||||
|
|
||||||
this.currentLocation = this.baseDirPath.resolve(navigateTo);
|
this.currentLocation = this.baseDirPath.resolve(navigateTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validate(String navigateTo) {
|
public void validate(String path) {
|
||||||
|
// Absolut paths are allowed, however, they have to be under baseDir
|
||||||
|
|
||||||
|
if(path == null) {
|
||||||
|
throw new IllegalStateException("Null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(path.contains("..")) {
|
||||||
|
throw new IllegalStateException("Relative path");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Path tmpPath = Path.of(path);
|
||||||
|
|
||||||
|
if(!tmpPath.normalize().startsWith(this.baseDirPath)) {
|
||||||
|
throw new IllegalStateException("Illegal path: " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate_internal(String navigateTo) {
|
||||||
if(navigateTo == null) {
|
if(navigateTo == null) {
|
||||||
throw new IllegalStateException("Null");
|
throw new IllegalStateException("Null");
|
||||||
}
|
}
|
||||||
@@ -97,25 +115,25 @@ public class LocationTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Path resolve(String name) {
|
public Path resolve(String name) {
|
||||||
validate(name);
|
validate_internal(name);
|
||||||
|
|
||||||
return this.currentLocation.resolve(name).normalize();
|
return this.currentLocation.resolve(name).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path resolveToBaseDir(String name) {
|
public Path resolveToBaseDir(String name) {
|
||||||
validate(name);
|
validate_internal(name);
|
||||||
|
|
||||||
return this.baseDirPath.resolve(name).normalize();
|
return this.baseDirPath.resolve(name).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path resolveShare(String shareUuid) {
|
public Path resolveShare(String shareUuid) {
|
||||||
validate(shareUuid);
|
validate_internal(shareUuid);
|
||||||
|
|
||||||
return this.baseDirPath.resolve(this.filesConfig.getSharesName()).resolve(shareUuid);
|
return this.baseDirPath.resolve(this.filesConfig.getSharesName()).resolve(shareUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path resolveTrash(String name) {
|
public Path resolveTrash(String name) {
|
||||||
validate(name);
|
validate_internal(name);
|
||||||
|
|
||||||
return this.baseDirPath.resolve(this.filesConfig.getTrashBinName()).resolve(name);
|
return this.baseDirPath.resolve(this.filesConfig.getTrashBinName()).resolve(name);
|
||||||
}
|
}
|
||||||
|
|||||||
42
files/src/main/java/de/nbscloud/files/Share.java
Normal file
42
files/src/main/java/de/nbscloud/files/Share.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package de.nbscloud.files;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
public class Share {
|
||||||
|
private String uuid;
|
||||||
|
private boolean oneTime;
|
||||||
|
private LocalDate expiryDate;
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
public String getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuid(String uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOneTime() {
|
||||||
|
return oneTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOneTime(boolean oneTime) {
|
||||||
|
this.oneTime = oneTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getExpiryDate() {
|
||||||
|
return expiryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiryDate(LocalDate expiryDate) {
|
||||||
|
this.expiryDate = expiryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
package de.nbscloud.files.controller;
|
package de.nbscloud.files.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import de.nbscloud.files.FileSystemService;
|
import de.nbscloud.files.FileSystemService;
|
||||||
import de.nbscloud.files.LocationTracker;
|
import de.nbscloud.files.LocationTracker;
|
||||||
|
import de.nbscloud.files.Share;
|
||||||
import de.nbscloud.files.config.FilesConfig;
|
import de.nbscloud.files.config.FilesConfig;
|
||||||
import de.nbscloud.files.exception.FileSystemServiceException;
|
import de.nbscloud.files.exception.FileSystemServiceException;
|
||||||
import de.nbscloud.files.form.RenameForm;
|
import de.nbscloud.files.form.RenameForm;
|
||||||
|
import de.nbscloud.files.form.ShareForm;
|
||||||
import de.nbscloud.webcontainer.registry.AppRegistry;
|
import de.nbscloud.webcontainer.registry.AppRegistry;
|
||||||
import de.nbscloud.webcontainer.shared.config.WebContainerSharedConfig;
|
import de.nbscloud.webcontainer.shared.config.WebContainerSharedConfig;
|
||||||
|
import org.apache.commons.io.input.ObservableInputStream;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
@@ -25,15 +30,19 @@ import org.springframework.web.util.UriUtils;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.swing.text.html.Option;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileAlreadyExistsException;
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@@ -51,6 +60,8 @@ public class FilesController implements InitializingBean {
|
|||||||
private FileSystemService fileSystemService;
|
private FileSystemService fileSystemService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private AppRegistry appRegistry;
|
private AppRegistry appRegistry;
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper mapper;
|
||||||
|
|
||||||
// We have to temporarily store messages as we redirect: in the manipulation methods
|
// We have to temporarily store messages as we redirect: in the manipulation methods
|
||||||
// so everything we add to the model will be gone
|
// so everything we add to the model will be gone
|
||||||
@@ -107,6 +118,7 @@ public class FilesController implements InitializingBean {
|
|||||||
model.addAttribute("form", new RenameForm(filename, getCurrentLocation(), filename));
|
model.addAttribute("form", new RenameForm(filename, getCurrentLocation(), filename));
|
||||||
model.addAttribute("targetDirs", this.fileSystemService.collectDirs(filename));
|
model.addAttribute("targetDirs", this.fileSystemService.collectDirs(filename));
|
||||||
model.addAttribute("apps", this.appRegistry.getAll());
|
model.addAttribute("apps", this.appRegistry.getAll());
|
||||||
|
model.addAttribute("filename", filename);
|
||||||
this.webContainerSharedConfig.addDefaults(model);
|
this.webContainerSharedConfig.addDefaults(model);
|
||||||
|
|
||||||
return "files/rename";
|
return "files/rename";
|
||||||
@@ -135,7 +147,7 @@ public class FilesController implements InitializingBean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/files/download")
|
@GetMapping("/files/download")
|
||||||
public ResponseEntity<Resource> downloadFile(String filename) {
|
public ResponseEntity downloadFile(String filename) {
|
||||||
// TODO download of directories via .zip? Also needs to be streaming
|
// TODO download of directories via .zip? Also needs to be streaming
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -147,7 +159,7 @@ public class FilesController implements InitializingBean {
|
|||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
logger.error("Could not get file", e);
|
logger.error("Could not get file", e);
|
||||||
|
|
||||||
return ResponseEntity.internalServerError().body(null);
|
return ResponseEntity.internalServerError().body(":(");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,41 +195,82 @@ public class FilesController implements InitializingBean {
|
|||||||
return "redirect:/files/browse/" + this.locationTracker.getRelativeLocation();
|
return "redirect:/files/browse/" + this.locationTracker.getRelativeLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/files/share")
|
@GetMapping("files/share")
|
||||||
public String share(String filename) {
|
public String share(Model model, String filename) {
|
||||||
|
model.addAttribute("currentLocation", getCurrentLocationPrefixed());
|
||||||
|
model.addAttribute("form", new ShareForm(filename, false, LocalDate.now().plusDays(1)));
|
||||||
|
model.addAttribute("apps", this.appRegistry.getAll());
|
||||||
|
model.addAttribute("filename", filename);
|
||||||
|
this.webContainerSharedConfig.addDefaults(model);
|
||||||
|
|
||||||
|
return "files/share";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/files/doShare")
|
||||||
|
public String doShare(@RequestParam("filename") String filename,
|
||||||
|
@RequestParam(value = "oneTime", defaultValue = "false") boolean oneTime,
|
||||||
|
@RequestParam(value = "expiryDate", required = false) String expiryDateString
|
||||||
|
) {
|
||||||
final Path filePath = this.locationTracker.getRelativeToBaseDir(this.locationTracker.resolve(filename));
|
final Path filePath = this.locationTracker.getRelativeToBaseDir(this.locationTracker.resolve(filename));
|
||||||
final String shareUuid = UUID.randomUUID().toString();
|
final String shareUuid = UUID.randomUUID().toString();
|
||||||
|
final Share share = new Share();
|
||||||
|
// The format is always "yyyy-MM-dd", see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
|
||||||
|
final LocalDate expiryDate = Optional.ofNullable(expiryDateString)
|
||||||
|
.map(ed -> LocalDate.parse(ed, DateTimeFormatter.ofPattern("yyyy-MM-dd")))
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
share.setUuid(shareUuid);
|
||||||
|
share.setPath(filePath.toString());
|
||||||
|
share.setExpiryDate(expiryDate);
|
||||||
|
share.setOneTime(oneTime);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.fileSystemService.createFile(this.locationTracker.resolveShare(shareUuid), filePath.toString().getBytes(StandardCharsets.UTF_8));
|
final String shareJson = mapper.writeValueAsString(share);
|
||||||
|
|
||||||
this.shareInfo.add("/files/shares?shareUuid=" + shareUuid);
|
this.fileSystemService.createFile(this.locationTracker.resolveShare(share.getUuid()), shareJson.getBytes(StandardCharsets.UTF_8));
|
||||||
} catch (RuntimeException e) {
|
|
||||||
|
this.shareInfo.add("/files/shares?shareUuid=" + share.getUuid());
|
||||||
|
} catch (RuntimeException | JsonProcessingException e) {
|
||||||
logger.error("Could not share file", e);
|
logger.error("Could not share file", e);
|
||||||
|
|
||||||
this.errors.add(e.getMessage());
|
this.errors.add(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return "redirect:/files/browse/" + this.locationTracker.getRelativeLocation();
|
return "redirect:/files/browse/" + this.locationTracker.getRelativeLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("files/shares")
|
@GetMapping("files/shares")
|
||||||
public ResponseEntity shares(String shareUuid) {
|
public ResponseEntity shares(String shareUuid) {
|
||||||
try {
|
try {
|
||||||
final String sharedFile = new String(this.fileSystemService.get(this.locationTracker.resolveShare(shareUuid)));
|
final String shareJson = new String(this.fileSystemService.get(this.locationTracker.resolveShare(shareUuid)));
|
||||||
final Path sharedFilePath = this.locationTracker.resolveToBaseDir(sharedFile);
|
final Share share = mapper.readValue(shareJson, Share.class);
|
||||||
|
final Path sharedFilePath = this.locationTracker.resolveToBaseDir(share.getPath());
|
||||||
final String filename = sharedFilePath.getFileName().toString();
|
final String filename = sharedFilePath.getFileName().toString();
|
||||||
|
final Optional<LocalDate> optExpiryDate = Optional.ofNullable(share.getExpiryDate());
|
||||||
|
final boolean expired = optExpiryDate.map(expiryDate -> LocalDate.now().isAfter(expiryDate)).orElse(false);
|
||||||
|
|
||||||
|
if (expired) {
|
||||||
|
fileSystemService.delete(locationTracker.resolveShare(shareUuid));
|
||||||
|
|
||||||
|
return ResponseEntity.status(410).body("Share expired!");
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
||||||
.header(HttpHeaders.CONTENT_TYPE, this.fileSystemService.getMimeType(filename))
|
.header(HttpHeaders.CONTENT_TYPE, this.fileSystemService.getMimeType(filename))
|
||||||
.header(HttpHeaders.CONTENT_LENGTH, String.valueOf(this.fileSystemService.getSize(filename)))
|
.header(HttpHeaders.CONTENT_LENGTH, String.valueOf(this.fileSystemService.getSize(filename)))
|
||||||
.body(new InputStreamResource(this.fileSystemService.stream(filename)));
|
.body(new InputStreamResource(new ObservableInputStream(this.fileSystemService.stream(filename), new ObservableInputStream.Observer() {
|
||||||
} catch (RuntimeException e) {
|
@Override
|
||||||
|
public void closed() throws IOException {
|
||||||
|
if (share.isOneTime()) {
|
||||||
|
fileSystemService.delete(locationTracker.resolveShare(shareUuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
} catch (RuntimeException | JsonProcessingException e) {
|
||||||
logger.error("Could not get shared file", e);
|
logger.error("Could not get shared file", e);
|
||||||
|
|
||||||
return ResponseEntity.internalServerError().body(null);
|
return ResponseEntity.internalServerError().body(":(");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
39
files/src/main/java/de/nbscloud/files/form/ShareForm.java
Normal file
39
files/src/main/java/de/nbscloud/files/form/ShareForm.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package de.nbscloud.files.form;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
public class ShareForm {
|
||||||
|
private String filename;
|
||||||
|
private boolean oneTime;
|
||||||
|
private LocalDate expiryDate;
|
||||||
|
|
||||||
|
public ShareForm(String filename, boolean oneTime, LocalDate expiryDate) {
|
||||||
|
this.filename = filename;
|
||||||
|
this.oneTime = oneTime;
|
||||||
|
this.expiryDate = expiryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilename() {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilename(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOneTime() {
|
||||||
|
return oneTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOneTime(boolean oneTime) {
|
||||||
|
this.oneTime = oneTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getExpiryDate() {
|
||||||
|
return expiryDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiryDate(LocalDate expiryDate) {
|
||||||
|
this.expiryDate = expiryDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,18 +6,22 @@ nbscloud.files.files-content-table.table-header.lastmodified=Last modified
|
|||||||
nbscloud.files.files-content-table.table-header.actions=Actions
|
nbscloud.files.files-content-table.table-header.actions=Actions
|
||||||
|
|
||||||
nbscloud.files-content-table.table.actions.delete=Delete
|
nbscloud.files-content-table.table.actions.delete=Delete
|
||||||
nbscloud.files-content-table.table.actions.rename=Rename/move
|
nbscloud.files-content-table.table.actions.rename=Rename/move...
|
||||||
nbscloud.files-content-table.table.actions.download=Download
|
nbscloud.files-content-table.table.actions.download=Download
|
||||||
nbscloud.files-content-table.table.actions.share=Share
|
nbscloud.files-content-table.table.actions.share=Share...
|
||||||
nbscloud.files-content-table.table.actions.preview=Preview
|
nbscloud.files-content-table.table.actions.preview=Preview
|
||||||
|
|
||||||
nbscloud.files.rename.title=nbscloud - files\: rename/move \u0020
|
nbscloud.files.rename.title=nbscloud - files\: rename/move \u0020
|
||||||
|
|
||||||
nbscloud.files.rename.label.filename=Filename\:
|
nbscloud.files.rename.label.filename=Filename\:
|
||||||
nbscloud.files.rename.label.targetDir=Target directory\:
|
nbscloud.files.rename.label.targetDir=Target directory\:
|
||||||
|
|
||||||
nbscloud.files.rename.submit=Rename/move
|
nbscloud.files.rename.submit=Rename/move
|
||||||
|
|
||||||
|
nbscloud.files.share.title=nbscloud - files\: share \u0020
|
||||||
|
nbscloud.files.share.label.filename=Filename\:
|
||||||
|
nbscloud.files.share.label.onetime=One time\:
|
||||||
|
nbscloud.files.share.label.expirydate=Expiry date\:
|
||||||
|
nbscloud.files.share.submit=Share
|
||||||
|
|
||||||
nbscloud.files.share-message=Shared file\:\u0020
|
nbscloud.files.share-message=Shared file\:\u0020
|
||||||
|
|
||||||
nbscloud.files.delete.success=File deleted
|
nbscloud.files.delete.success=File deleted
|
||||||
|
|||||||
@@ -6,18 +6,22 @@ nbscloud.files.files-content-table.table-header.lastmodified=Zuletzt ge\u00E4nde
|
|||||||
nbscloud.files.files-content-table.table-header.actions=Aktionen
|
nbscloud.files.files-content-table.table-header.actions=Aktionen
|
||||||
|
|
||||||
nbscloud.files-content-table.table.actions.delete=L\u00F6schen
|
nbscloud.files-content-table.table.actions.delete=L\u00F6schen
|
||||||
nbscloud.files-content-table.table.actions.rename=Umbenennen/verschieben
|
nbscloud.files-content-table.table.actions.rename=Umbenennen/verschieben...
|
||||||
nbscloud.files-content-table.table.actions.download=Download
|
nbscloud.files-content-table.table.actions.download=Download
|
||||||
nbscloud.files-content-table.table.actions.share=Teilen
|
nbscloud.files-content-table.table.actions.share=Teilen...
|
||||||
nbscloud.files-content-table.table.actions.preview=Vorschau
|
nbscloud.files-content-table.table.actions.preview=Vorschau
|
||||||
|
|
||||||
nbscloud.files.rename.title=nbscloud - Dateien\: umbenennen/verschieben \u0020
|
nbscloud.files.rename.title=nbscloud - Dateien\: umbenennen/verschieben \u0020
|
||||||
|
|
||||||
nbscloud.files.rename.label.filename=Dateiname\:
|
nbscloud.files.rename.label.filename=Dateiname\:
|
||||||
nbscloud.files.rename.label.targetDir=Zielverzeichnis\:
|
nbscloud.files.rename.label.targetDir=Zielverzeichnis\:
|
||||||
|
|
||||||
nbscloud.files.rename.submit=Umbenennen/verschieben
|
nbscloud.files.rename.submit=Umbenennen/verschieben
|
||||||
|
|
||||||
|
nbscloud.files.share.title=nbscloud - Dateien\: teilen \u0020
|
||||||
|
nbscloud.files.share.label.filename=Dateiname\:
|
||||||
|
nbscloud.files.share.label.onetime=Einmaliger Abruf\:
|
||||||
|
nbscloud.files.share.label.expirydate=Ablaufdatum\:
|
||||||
|
nbscloud.files.share.submit=Teilen
|
||||||
|
|
||||||
nbscloud.files.share-message=Datei geteilt\:\u0020
|
nbscloud.files.share-message=Datei geteilt\:\u0020
|
||||||
|
|
||||||
nbscloud.files.delete.success=Datei gel\u00F6scht
|
nbscloud.files.delete.success=Datei gel\u00F6scht
|
||||||
|
|||||||
@@ -48,12 +48,14 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rename-form {
|
#rename-form,
|
||||||
|
#share-form {
|
||||||
margin-top: 3em;
|
margin-top: 3em;
|
||||||
margin-left: 3em;
|
margin-left: 3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rename-form * {
|
#rename-form *,
|
||||||
|
#share-form * {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -66,7 +68,8 @@
|
|||||||
width: 70em;
|
width: 70em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rename-form > input[type=text] {
|
#rename-form > input[type=text],
|
||||||
|
#share-form > input[type=text] {
|
||||||
width: 70em;
|
width: 70em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
files/src/main/resources/templates/files/share.html
Normal file
28
files/src/main/resources/templates/files/share.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<title th:text="#{nbscloud.files.share.title} + ${filename}"/>
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link th:if="${darkMode}" rel="stylesheet" th:href="@{/css/darkModeColors.css}"/>
|
||||||
|
<link th:if="${!darkMode}" rel="stylesheet" th:href="@{/css/lightModeColors.css}"/>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/main.css}"/>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/files_main.css}"/>
|
||||||
|
<link rel="shortcut icon" th:href="@{/favicon.ico}"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main-container">
|
||||||
|
<div th:replace="includes/header :: header"/>
|
||||||
|
<form id="share-form" action="#" th:action="@{/files/doShare}" th:object="${form}" method="post" enctype="multipart/form-data">
|
||||||
|
<label for="filename" th:text="#{nbscloud.files.share.label.filename}"/>
|
||||||
|
<input type="text" id="filename" th:field="*{filename}" readonly />
|
||||||
|
<label for="oneTime" th:text="#{nbscloud.files.share.label.onetime}"/>
|
||||||
|
<input type="checkbox" id="oneTime" th:field="*{oneTime}" />
|
||||||
|
<label for="expiryDate" th:text="#{nbscloud.files.share.label.expirydate}"/>
|
||||||
|
<input type="date" id="expiryDate" th:field="*{expiryDate}"/>
|
||||||
|
<input type="submit" th:value="#{nbscloud.files.share.submit}" />
|
||||||
|
</form>
|
||||||
|
<div th:replace="includes/footer :: footer"/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user