Added file details display
- Added password generator logic to backend - Added UI for file details
This commit is contained in:
parent
58e3dd0af5
commit
43e0eb1766
@ -59,43 +59,51 @@
|
||||
|
||||
<h3 class="text-lg font-semibold mt-3">File uploaded successfully!</h3>
|
||||
|
||||
<div class="flex flex-wrap mt-5 mb-5">
|
||||
<div class="flex flex-wrap mt-5 mb-5" *ngIf="uploadData && fileUrls">
|
||||
<div class="w-full px-4">
|
||||
<div class="grid grid-cols-2 gap-4 items-center">
|
||||
<div class="text-gray-600 text-right">File Name:</div>
|
||||
<div>{{uploadData.fileName}}</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Is password protected:</div>
|
||||
<label class="flex items-center space-x-2">
|
||||
<!-- Use property binding to set checked based on uploadData.passwordProtected -->
|
||||
<input type="checkbox" class="checkbox checkbox-primary" [checked]="uploadData.passwordProtected" (click)="$event.preventDefault()"/>
|
||||
<span>{{uploadData.passwordProtected ? 'Yes' : 'No'}}</span>
|
||||
</label>
|
||||
|
||||
<div class="text-gray-600 text-right">Is single download:</div>
|
||||
<label class="flex items-center space-x-2">
|
||||
<!-- Use property binding to set checked based on uploadData.singleDownload -->
|
||||
<input type="checkbox" class="checkbox checkbox-primary" [checked]="uploadData.singleDownload" (click)="$event.preventDefault()"/>
|
||||
<span>{{uploadData.singleDownload ? 'Yes' : 'No'}}</span>
|
||||
</label>
|
||||
|
||||
<div class="text-gray-600 text-right">Download Password:</div>
|
||||
<div>{{uploadData.password || 'N/A'}}</div>
|
||||
|
||||
<div class="text-gray-600 text-right">File ID:</div>
|
||||
<div>166554</div>
|
||||
<div>{{uploadData.fileId}}</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Material:</div>
|
||||
<div>Aluminum & Plastic</div>
|
||||
<!-- Assuming you have properties for downloadURL and statusURL -->
|
||||
<div class="text-gray-600 text-right">Download URL:</div>
|
||||
<div><a href="{{fileUrls.downloadUrl}}" target="_blank">{{fileUrls.downloadUrl}}</a></div>
|
||||
|
||||
<div class="text-gray-600 text-right">Color:</div>
|
||||
<div>Black/Silver</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Dimensions:</div>
|
||||
<div>15 x 15 x 25 cm</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Weight:</div>
|
||||
<div>1.2 kg</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Power:</div>
|
||||
<div>10W LED (included)</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Brightness:</div>
|
||||
<div>700 lumens</div>
|
||||
|
||||
<div class="text-gray-600 text-right">Warranty:</div>
|
||||
<div>2 years</div>
|
||||
<div class="text-gray-600 text-right">File Status URL:</div>
|
||||
<div><a href="{{fileUrls.statusUrl}}" target="_blank">{{fileUrls.statusUrl}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<p class="text-sm text-gray-500 mt-1">Your file is now securely stored on our servers.</p>
|
||||
|
||||
<div class="mt-4 flex flex-col w-full items-center">
|
||||
<button class="btn btn-primary w-full max-w-xs">Upload Another File</button>
|
||||
<button class="btn btn-outline btn-secondary mt-2 w-full max-w-xs">Download a file</button>
|
||||
<button class="btn btn-success w-full max-w-xs text-white">Copy URL</button>
|
||||
<button class="btn btn-primary mt-2 w-full max-w-xs">Upload Another File</button>
|
||||
<button class="btn btn-outline btn-secondary mt-2 w-full max-w-xs">Delete this file</button>
|
||||
</div>
|
||||
<a href="#" class="link link-primary mt-4">Manage your uploads</a>
|
||||
</div>
|
||||
|
@ -27,7 +27,6 @@ export class UploadComponent {
|
||||
singleDownload: boolean = false;
|
||||
fileDescription: string = '';
|
||||
passwordProtected: boolean = false;
|
||||
password: string = ''; // Generated by the server for only this file
|
||||
|
||||
uploadStarted: boolean = false;
|
||||
uploadProgress = 0; // Real progress
|
||||
@ -35,6 +34,8 @@ export class UploadComponent {
|
||||
uploadFinished = false;
|
||||
uploadSpeedBps: number = 0;
|
||||
|
||||
uploadData: FileDetails | null = null;
|
||||
fileUrls: { downloadUrl: string, statusUrl: string, deleteUrl: string } | null = null;
|
||||
|
||||
|
||||
constructor(private developmentStore: DevelopmentStore) {
|
||||
@ -98,6 +99,8 @@ export class UploadComponent {
|
||||
.then(response => {
|
||||
console.log('Upload completed successfully!');
|
||||
console.log(response.data);
|
||||
this.fileUrls = this.buildFileUrls(response.data);
|
||||
this.uploadData = response.data;
|
||||
this.uploadFinished = true;
|
||||
})
|
||||
.catch(error => {
|
||||
@ -106,13 +109,26 @@ export class UploadComponent {
|
||||
}
|
||||
}
|
||||
|
||||
buildFileUrls(fileDetails: FileDetails) {
|
||||
const baseUrl = this.developmentStore.getBaseUrl();
|
||||
const fileId = fileDetails.fileId;
|
||||
const downloadUrl = `${baseUrl}download?fileId=${fileId}`;
|
||||
const deleteUrl = `${baseUrl}api/v1/deletefile?fileId=${fileId}`;
|
||||
const statusUrl = `${baseUrl}status?fileId=${fileId}`;
|
||||
return {
|
||||
downloadUrl,
|
||||
statusUrl,
|
||||
deleteUrl,
|
||||
}; }
|
||||
|
||||
buildFormDataObject(): FormData {
|
||||
const formData = new FormData();
|
||||
formData.append('file', this.fileToUpload as Blob);
|
||||
formData.append('password', this.passwordProtected ? this.password : '');
|
||||
formData.append('passwordProtected', this.passwordProtected ? 'true' : 'false');
|
||||
formData.append('singleDownload', this.singleDownload.toString());
|
||||
formData.append('shortStorage', this.shortStorage.toString());
|
||||
formData.append('fileDescription', this.fileDescription);
|
||||
console.log(formData.get("passwordProtected"));
|
||||
return formData;
|
||||
}
|
||||
|
||||
@ -169,3 +185,12 @@ export class UploadComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
interface FileDetails {
|
||||
fileId: string;
|
||||
fileName: string;
|
||||
message: string;
|
||||
passwordProtected: boolean;
|
||||
singleDownload: boolean;
|
||||
uploadDate: string;
|
||||
password: string;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class Upload extends ApiRestController {
|
||||
// Currently testing
|
||||
@PostMapping("/upload")
|
||||
public ResponseEntity<String> getUpload(@RequestParam("file") MultipartFile file, HttpServletRequest request,
|
||||
@RequestParam(value = "password", required = false) String password,
|
||||
@RequestParam(value = "passwordProtected", required = false) Boolean passwordProtected,
|
||||
@RequestParam(value = "singleDownload", defaultValue = "false") boolean singleDownload,
|
||||
@RequestParam(value = "fileDescription", required = false) String fileDescription) {
|
||||
|
||||
@ -40,15 +40,17 @@ public class Upload extends ApiRestController {
|
||||
return new ResponseEntity<>("Please select a file to upload.", HttpStatus.NOT_ACCEPTABLE);
|
||||
}
|
||||
|
||||
FileUpload fileUpload = fileService.processUploadedFile(file, request.getRemoteAddr(), password, singleDownload, fileDescription);
|
||||
FileUpload fileUpload = fileService.processUploadedFile(file, request.getRemoteAddr(), passwordProtected, singleDownload, fileDescription);
|
||||
log.debug("User uploaded file " + file.getOriginalFilename() + " from IP " + request.getRemoteAddr() + " successfully.");
|
||||
|
||||
JsonObject response = new JsonObject();
|
||||
response.addProperty("fileId", fileUpload.getFileId());
|
||||
response.addProperty("fileName", fileUpload.getFileName());
|
||||
response.addProperty("message", "File " + file.getOriginalFilename() + " uploaded successfully!");
|
||||
response.addProperty("passwordProtected", fileUpload.isPasswordProtected());
|
||||
response.addProperty("singleDownload", fileUpload.isSingleDownload());
|
||||
response.addProperty("uploadDate", fileUpload.getUploadDate().toString());
|
||||
response.addProperty("password", fileUpload.getDownloadPassword());
|
||||
|
||||
return new ResponseEntity<>(response.toString(), HttpStatus.OK);
|
||||
}
|
||||
|
@ -3,14 +3,20 @@ package de.w665.sharepulse.service;
|
||||
import de.w665.sharepulse.exception.NoDownloadPermissionException;
|
||||
import de.w665.sharepulse.model.FileUpload;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Random;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileSecurityService {
|
||||
|
||||
@Value("${sharepulse.filepassword-length}")
|
||||
private int passwordLength;
|
||||
@Value("${sharepulse.filepassword-charset}")
|
||||
private String passwordCharset;
|
||||
private final Random random = new Random();
|
||||
|
||||
public boolean verifyDownloadPermission(FileUpload file, String password) throws NoDownloadPermissionException {
|
||||
|
||||
|
||||
@ -34,4 +40,16 @@ public class FileSecurityService {
|
||||
throw new NoDownloadPermissionException("Password protected file can only be downloaded with correct password.");
|
||||
|
||||
}
|
||||
|
||||
public String generateFilePassword() {
|
||||
StringBuilder password = new StringBuilder(passwordLength);
|
||||
|
||||
for (int i = 0; i < passwordLength; i++) {
|
||||
int randomIndex = random.nextInt(passwordCharset.length());
|
||||
char randomChar = passwordCharset.charAt(randomIndex);
|
||||
password.append(randomChar);
|
||||
}
|
||||
|
||||
return password.toString();
|
||||
}
|
||||
}
|
||||
|
@ -23,15 +23,16 @@ import java.util.Date;
|
||||
public class FileService {
|
||||
|
||||
private final FileIdService fileIdService;
|
||||
|
||||
private final FileSecurityService fileSecurityService;
|
||||
private final FileUploadRepository fileUploadRepository;
|
||||
|
||||
@Value("${sharepulse.temp-filestore-path}")
|
||||
private String tempDirPath;
|
||||
|
||||
@Autowired
|
||||
public FileService(FileIdService fileIdService, FileUploadRepository fileUploadRepository) {
|
||||
public FileService(FileIdService fileIdService, FileSecurityService fileSecurityService, FileUploadRepository fileUploadRepository) {
|
||||
this.fileIdService = fileIdService;
|
||||
this.fileSecurityService = fileSecurityService;
|
||||
this.fileUploadRepository = fileUploadRepository;
|
||||
}
|
||||
|
||||
@ -53,10 +54,12 @@ public class FileService {
|
||||
}
|
||||
}
|
||||
|
||||
public FileUpload processUploadedFile(MultipartFile file, String uploaderIp, String password, boolean singleDownload, String fileDescription) {
|
||||
public FileUpload processUploadedFile(MultipartFile file, String uploaderIp, boolean passwordProtected, boolean singleDownload, String fileDescription) {
|
||||
|
||||
String fileId = fileIdService.generateNewUniqueId();
|
||||
|
||||
String password = fileSecurityService.generateFilePassword(); // TODO: generate password
|
||||
|
||||
FileUpload fileUpload = FileUpload.builder()
|
||||
.fileId(fileId)
|
||||
.fileName(file.getOriginalFilename())
|
||||
@ -66,7 +69,7 @@ public class FileService {
|
||||
.uploadedByIpAddress(uploaderIp)
|
||||
.downloadCount(0)
|
||||
.fileDescription(fileDescription)
|
||||
.passwordProtected(password != null && !password.isEmpty())
|
||||
.passwordProtected(passwordProtected)
|
||||
.downloadPassword(password)
|
||||
.build();
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Application config
|
||||
sharepulse.temp-filestore-path=/temp-filestore
|
||||
sharepulse.filepassword-length=6
|
||||
sharepulse.filepassword-charset=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
|
||||
|
||||
# Static path
|
||||
spring.web.resources.static-locations=classpath:/static/browser/
|
||||
@ -11,9 +13,6 @@ spring.data.rest.base-path=/api/v1
|
||||
spring.servlet.multipart.max-file-size=1GB
|
||||
spring.servlet.multipart.max-request-size=1GB
|
||||
|
||||
# Logging
|
||||
logging.level.de.w665.sharepulse=DEBUG
|
||||
|
||||
# Database
|
||||
rethinkdb.host=localhost
|
||||
rethinkdb.port=28015
|
||||
@ -24,4 +23,7 @@ server.port=80
|
||||
spring.application.name=sharepulse
|
||||
|
||||
# Spring profiles (Options: development, production) (Controls cors)
|
||||
spring.profiles.active=development
|
||||
spring.profiles.active=development
|
||||
|
||||
# Logging
|
||||
logging.level.de.w665.sharepulse=DEBUG
|
Loading…
x
Reference in New Issue
Block a user