mirror of
https://github.com/RoastSlav/quickdrop.git
synced 2025-12-30 19:20:14 -06:00
reformatting
This commit is contained in:
202
pom.xml
202
pom.xml
@@ -1,18 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<project
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>
|
||||
4.0.0
|
||||
</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.4</version>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-parent
|
||||
</artifactId>
|
||||
<version>
|
||||
3.3.4
|
||||
</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>org.rostislav</groupId>
|
||||
<artifactId>quickdrop</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>quickdrop</name>
|
||||
<description>quickdrop</description>
|
||||
<groupId>
|
||||
org.rostislav
|
||||
</groupId>
|
||||
<artifactId>
|
||||
quickdrop
|
||||
</artifactId>
|
||||
<version>
|
||||
0.0.1-SNAPSHOT
|
||||
</version>
|
||||
<name>
|
||||
quickdrop
|
||||
</name>
|
||||
<description>
|
||||
quickdrop
|
||||
</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
@@ -27,84 +47,164 @@
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
<java.target.version>21</java.target.version>
|
||||
<java.version>
|
||||
21
|
||||
</java.version>
|
||||
<java.target.version>
|
||||
21
|
||||
</java.target.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-data-jpa
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-security
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-thymeleaf
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-web
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
||||
<groupId>
|
||||
org.thymeleaf.extras
|
||||
</groupId>
|
||||
<artifactId>
|
||||
thymeleaf-extras-springsecurity6
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-logging
|
||||
</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-starter-test
|
||||
</artifactId>
|
||||
<scope>
|
||||
test
|
||||
</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>
|
||||
junit
|
||||
</groupId>
|
||||
<artifactId>
|
||||
junit
|
||||
</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<groupId>
|
||||
org.springframework.security
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-security-test
|
||||
</artifactId>
|
||||
<scope>
|
||||
test
|
||||
</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.46.0.0</version>
|
||||
<groupId>
|
||||
org.xerial
|
||||
</groupId>
|
||||
<artifactId>
|
||||
sqlite-jdbc
|
||||
</artifactId>
|
||||
<version>
|
||||
3.46.0.0
|
||||
</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-community-dialects</artifactId>
|
||||
<version>6.5.2.Final</version>
|
||||
<groupId>
|
||||
org.hibernate
|
||||
</groupId>
|
||||
<artifactId>
|
||||
hibernate-community-dialects
|
||||
</artifactId>
|
||||
<version>
|
||||
6.5.2.Final
|
||||
</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
<groupId>
|
||||
org.junit.jupiter
|
||||
</groupId>
|
||||
<artifactId>
|
||||
junit-jupiter-engine
|
||||
</artifactId>
|
||||
<version>
|
||||
5.10.0
|
||||
</version>
|
||||
<scope>
|
||||
test
|
||||
</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.10.0</version>
|
||||
<scope>test</scope>
|
||||
<groupId>
|
||||
org.junit.jupiter
|
||||
</groupId>
|
||||
<artifactId>
|
||||
junit-jupiter-api
|
||||
</artifactId>
|
||||
<version>
|
||||
5.10.0
|
||||
</version>
|
||||
<scope>
|
||||
test
|
||||
</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<groupId>
|
||||
org.springframework.boot
|
||||
</groupId>
|
||||
<artifactId>
|
||||
spring-boot-maven-plugin
|
||||
</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>
|
||||
junit
|
||||
</groupId>
|
||||
<artifactId>
|
||||
junit
|
||||
</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.rostislav.quickdrop;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -8,9 +11,6 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class QuickdropApplication {
|
||||
@@ -27,7 +27,8 @@ public class QuickdropApplication {
|
||||
try {
|
||||
Files.createDirectories(Path.of(fileSavePath));
|
||||
logger.info("File save path created: {}", fileSavePath);
|
||||
} catch (Exception e) {
|
||||
} catch (
|
||||
Exception e) {
|
||||
logger.error("Failed to create file save path: {}", fileSavePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package org.rostislav.quickdrop.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.PrePersist;
|
||||
|
||||
@Entity
|
||||
public class FileEntity {
|
||||
@Id
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.rostislav.quickdrop.repository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.rostislav.quickdrop.model.FileEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface FileRepository extends JpaRepository<FileEntity, Long> {
|
||||
@Query("SELECT f FROM FileEntity f WHERE f.uuid = :uuid")
|
||||
Optional<FileEntity> findByUUID(@Param("uuid") String uuid);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.rostislav.quickdrop.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import org.rostislav.quickdrop.model.FileEntity;
|
||||
import org.rostislav.quickdrop.repository.FileRepository;
|
||||
import org.slf4j.Logger;
|
||||
@@ -8,9 +11,6 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class ScheduleService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScheduleService.class);
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package org.rostislav.quickdrop.util;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -14,6 +10,16 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class FileEncryptionUtils {
|
||||
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||
private static final int ITERATION_COUNT = 65536;
|
||||
@@ -37,7 +43,6 @@ public class FileEncryptionUtils {
|
||||
byte[] salt = generateRandomBytes();
|
||||
SecretKey secretKey = generateKeyFromPassword(password, salt);
|
||||
|
||||
|
||||
byte[] iv = generateRandomBytes();
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
|
||||
|
||||
@@ -2,17 +2,27 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Enter Password</title>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/images/favicon.png" rel="icon" type="image/png">
|
||||
<title>
|
||||
Enter
|
||||
Password</title>
|
||||
<meta content="width=device-width, initial-scale=1"
|
||||
name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet">
|
||||
<link href="/images/favicon.png"
|
||||
rel="icon"
|
||||
type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img alt="Website Logo" class="me-2" height="40" src="/images/favicon.png">
|
||||
<a class="navbar-brand d-flex align-items-center"
|
||||
href="/">
|
||||
<img alt="Website Logo"
|
||||
class="me-2"
|
||||
height="40"
|
||||
src="/images/favicon.png">
|
||||
QuickDrop
|
||||
</a>
|
||||
<button
|
||||
@@ -26,13 +36,18 @@
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<div class="collapse navbar-collapse"
|
||||
id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/file/list">View Files</a>
|
||||
<a class="nav-link"
|
||||
href="/file/list">View
|
||||
Files</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/file/upload">Upload File</a>
|
||||
<a class="nav-link"
|
||||
href="/file/upload">Upload
|
||||
File</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -41,14 +56,24 @@
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">Enter Password</h1>
|
||||
<h1 class="text-center mb-4">
|
||||
Enter
|
||||
Password</h1>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<form class="card p-4 shadow" id="passwordForm" method="post" th:action="@{/file/password}">
|
||||
<input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>
|
||||
<input name="uuid" th:value="${uuid}" type="hidden"/>
|
||||
<form class="card p-4 shadow"
|
||||
id="passwordForm"
|
||||
method="post"
|
||||
th:action="@{/file/password}">
|
||||
<input th:name="${_csrf.parameterName}"
|
||||
th:value="${_csrf.token}"
|
||||
type="hidden"/>
|
||||
<input name="uuid"
|
||||
th:value="${uuid}"
|
||||
type="hidden"/>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="password">Password:</label>
|
||||
<label class="form-label"
|
||||
for="password">Password:</label>
|
||||
<input
|
||||
class="form-control"
|
||||
id="password"
|
||||
@@ -57,7 +82,10 @@
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-primary w-100" type="submit">Submit</button>
|
||||
<button class="btn btn-primary w-100"
|
||||
type="submit">
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,17 +2,27 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>File View</title>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/images/favicon.png" rel="icon" type="image/png">
|
||||
<title>
|
||||
File
|
||||
View</title>
|
||||
<meta content="width=device-width, initial-scale=1"
|
||||
name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet">
|
||||
<link href="/images/favicon.png"
|
||||
rel="icon"
|
||||
type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img alt="Website Logo" class="me-2" height="40" src="/images/favicon.png">
|
||||
<a class="navbar-brand d-flex align-items-center"
|
||||
href="/">
|
||||
<img alt="Website Logo"
|
||||
class="me-2"
|
||||
height="40"
|
||||
src="/images/favicon.png">
|
||||
QuickDrop
|
||||
</a>
|
||||
<button
|
||||
@@ -26,13 +36,18 @@
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<div class="collapse navbar-collapse"
|
||||
id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/file/list">View Files</a>
|
||||
<a class="nav-link"
|
||||
href="/file/list">View
|
||||
Files</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/file/upload">Upload File</a>
|
||||
<a class="nav-link"
|
||||
href="/file/upload">Upload
|
||||
File</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -41,34 +56,59 @@
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">File View</h1>
|
||||
<h1 class="text-center mb-4">
|
||||
File
|
||||
View</h1>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-8 col-lg-6">
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title text-center" th:text="${file.name}">File Name</h5>
|
||||
<h5 class="card-title text-center"
|
||||
th:text="${file.name}">
|
||||
File
|
||||
Name</h5>
|
||||
|
||||
<div th:if="${!#strings.isEmpty(file.description)}">
|
||||
<p class="card-text text-center mb-3" th:text="${file.description}"></p>
|
||||
<p class="card-text text-center mb-3"
|
||||
th:text="${file.description}"></p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center border-top pt-3">
|
||||
<h5 class="card-title mb-0">Uploaded/Renewed At:</h5>
|
||||
<p class="card-text mb-0" th:text="${file.uploadDate}"></p>
|
||||
<h5 class="card-title mb-0">
|
||||
Uploaded/Renewed
|
||||
At:</h5>
|
||||
<p class="card-text mb-0"
|
||||
th:text="${file.uploadDate}"></p>
|
||||
</div>
|
||||
<small class="text-muted">Files are kept only for 30 days after this date.</small>
|
||||
<small class="text-muted">Files
|
||||
are
|
||||
kept
|
||||
only
|
||||
for
|
||||
30
|
||||
days
|
||||
after
|
||||
this
|
||||
date.</small>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center pt-3">
|
||||
<h5 class="card-title">Keep Indefinitely:</h5>
|
||||
<p class="card-text" th:text="${file.keepIndefinitely} ? 'Yes' : 'No'"></p>
|
||||
<h5 class="card-title">
|
||||
Keep
|
||||
Indefinitely:</h5>
|
||||
<p class="card-text"
|
||||
th:text="${file.keepIndefinitely} ? 'Yes' : 'No'"></p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title">File Size:</h5>
|
||||
<p class="card-text" th:text="${fileSize}"></p>
|
||||
<h5 class="card-title">
|
||||
File
|
||||
Size:</h5>
|
||||
<p class="card-text"
|
||||
th:text="${fileSize}"></p>
|
||||
</div>
|
||||
|
||||
<h5 class="card-title border-top pt-3">Link</h5>
|
||||
<h5 class="card-title border-top pt-3">
|
||||
Link</h5>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -82,12 +122,23 @@
|
||||
onclick="copyToClipboard()"
|
||||
type="button"
|
||||
>
|
||||
Copy Link
|
||||
Copy
|
||||
Link
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info" id="preparingMessage" style="display: none;">
|
||||
Your file is being prepared for download. Please wait...
|
||||
<div class="alert alert-info"
|
||||
id="preparingMessage"
|
||||
style="display: none;">
|
||||
Your
|
||||
file
|
||||
is
|
||||
being
|
||||
prepared
|
||||
for
|
||||
download.
|
||||
Please
|
||||
wait...
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between mt-3 border-top pt-3">
|
||||
@@ -99,23 +150,34 @@
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
<form method="post" th:action="@{/file/delete/{id}(id=${file.id})}"
|
||||
<form method="post"
|
||||
th:action="@{/file/delete/{id}(id=${file.id})}"
|
||||
th:if="${file.passwordHash != null}">
|
||||
<input
|
||||
th:name="${_csrf.parameterName}"
|
||||
th:value="${_csrf.token}"
|
||||
type="hidden"
|
||||
/>
|
||||
<button class="btn btn-danger" type="submit">Delete File</button>
|
||||
<button class="btn btn-danger"
|
||||
type="submit">
|
||||
Delete
|
||||
File
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" th:action="@{/file/extend/{id}(id=${file.id})}"
|
||||
<form method="post"
|
||||
th:action="@{/file/extend/{id}(id=${file.id})}"
|
||||
th:if="${file.keepIndefinitely == false}">
|
||||
<input
|
||||
th:name="${_csrf.parameterName}"
|
||||
th:value="${_csrf.token}"
|
||||
type="hidden"
|
||||
/>
|
||||
<button class="btn btn-primary" type="submit">Renew File Lifetime</button>
|
||||
<button class="btn btn-primary"
|
||||
type="submit">
|
||||
Renew
|
||||
File
|
||||
Lifetime
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,17 +2,27 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>All Files</title>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/images/favicon.png" rel="icon" type="image/png">
|
||||
<title>
|
||||
All
|
||||
Files</title>
|
||||
<meta content="width=device-width, initial-scale=1"
|
||||
name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet">
|
||||
<link href="/images/favicon.png"
|
||||
rel="icon"
|
||||
type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img alt="Website Logo" class="me-2" height="40" src="/images/favicon.png">
|
||||
<a class="navbar-brand d-flex align-items-center"
|
||||
href="/">
|
||||
<img alt="Website Logo"
|
||||
class="me-2"
|
||||
height="40"
|
||||
src="/images/favicon.png">
|
||||
QuickDrop
|
||||
</a>
|
||||
<button
|
||||
@@ -26,10 +36,13 @@
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<div class="collapse navbar-collapse"
|
||||
id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/file/upload">Upload File</a>
|
||||
<a class="nav-link"
|
||||
href="/file/upload">Upload
|
||||
File</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -38,37 +51,60 @@
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mt-5">
|
||||
<h1 class="text-center mb-4">All Files</h1>
|
||||
<h1 class="text-center mb-4">
|
||||
All
|
||||
Files</h1>
|
||||
<!-- Search Bar Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12 col-md-8 offset-md-2">
|
||||
<form action="/file/search" method="GET">
|
||||
<form action="/file/search"
|
||||
method="GET">
|
||||
<div class="input-group">
|
||||
<input aria-describedby="search-button" aria-label="Search for files" class="form-control"
|
||||
<input aria-describedby="search-button"
|
||||
aria-label="Search for files"
|
||||
class="form-control"
|
||||
name="query"
|
||||
placeholder="Search for files..." type="text">
|
||||
<button class="btn btn-primary" id="search-button" type="submit">Search</button>
|
||||
placeholder="Search for files..."
|
||||
type="text">
|
||||
<button class="btn btn-primary"
|
||||
id="search-button"
|
||||
type="submit">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3 mb-4" th:each="file : ${files}">
|
||||
<div class="col-12 col-sm-6 col-md-4 col-lg-3 mb-4"
|
||||
th:each="file : ${files}">
|
||||
<div class="card h-100 shadow">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title" th:text="${file.name}">File Name</h5>
|
||||
<p class="card-text" th:if="${!#strings.isEmpty(file.description)}"
|
||||
<h5 class="card-title"
|
||||
th:text="${file.name}">
|
||||
File
|
||||
Name</h5>
|
||||
<p class="card-text"
|
||||
th:if="${!#strings.isEmpty(file.description)}"
|
||||
th:text="${file.description}"></p>
|
||||
<p class="card-text border-top pt-3"
|
||||
th:text="'Keep Indefinitely: ' + (${file.keepIndefinitely} ? 'Yes' : 'No')">Keep Indefinitely</p>
|
||||
th:text="'Keep Indefinitely: ' + (${file.keepIndefinitely} ? 'Yes' : 'No')">
|
||||
Keep
|
||||
Indefinitely</p>
|
||||
<p class="card-text"
|
||||
th:text="'Password Protected: ' + (${file.passwordHash != null} ? 'Yes' : 'No')">Password
|
||||
th:text="'Password Protected: ' + (${file.passwordHash != null} ? 'Yes' : 'No')">
|
||||
Password
|
||||
Protected</p>
|
||||
<p class="card-text border-top pt-3" th:text="${file.uploadDate}"></p>
|
||||
<p class="card-text border-top pt-3"
|
||||
th:text="${file.uploadDate}"></p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" th:href="@{/file/{UUID}(UUID=${file.uuid})}">Go to File Page</a>
|
||||
<a class="btn btn-primary w-100"
|
||||
th:href="@{/file/{UUID}(UUID=${file.uuid})}">Go
|
||||
to
|
||||
File
|
||||
Page</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,23 +2,40 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Password Required</title>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/images/favicon.png" rel="icon" type="image/png">
|
||||
<title>
|
||||
Password
|
||||
Required</title>
|
||||
<meta content="width=device-width, initial-scale=1"
|
||||
name="viewport">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet">
|
||||
<link href="/images/favicon.png"
|
||||
rel="icon"
|
||||
type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Main Content -->
|
||||
<div class="container">
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<h2 class="text-center mb-4">Please Enter the Password to Continue</h2>
|
||||
<h2 class="text-center mb-4">
|
||||
Please
|
||||
Enter
|
||||
the
|
||||
Password
|
||||
to
|
||||
Continue</h2>
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<form action="/password/login" id="passwordForm" method="POST">
|
||||
<input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>
|
||||
<form action="/password/login"
|
||||
id="passwordForm"
|
||||
method="POST">
|
||||
<input th:name="${_csrf.parameterName}"
|
||||
th:value="${_csrf.token}"
|
||||
type="hidden"/>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="password">Password:</label>
|
||||
<label class="form-label"
|
||||
for="password">Password:</label>
|
||||
<input
|
||||
class="form-control"
|
||||
id="password"
|
||||
@@ -27,10 +44,14 @@
|
||||
type="password"
|
||||
>
|
||||
</div>
|
||||
<button class="btn btn-primary w-100" type="submit">Submit</button>
|
||||
<button class="btn btn-primary w-100"
|
||||
type="submit">
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
<div th:if="${error}">
|
||||
<p class="text-danger mt-3" th:text="${error}"></p>
|
||||
<p class="text-danger mt-3"
|
||||
th:text="${error}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.rostislav.quickdrop;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -14,14 +16,16 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.rostislav.quickdrop.TestDataContainer.*;
|
||||
import static org.rostislav.quickdrop.TestDataContainer.getEmptyFileUploadRequest;
|
||||
import static org.rostislav.quickdrop.TestDataContainer.getFileEntity;
|
||||
import static org.rostislav.quickdrop.TestDataContainer.getFileUploadRequest;
|
||||
|
||||
@SpringBootTest
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -35,7 +39,6 @@ public class FileServiceTests {
|
||||
@MockBean
|
||||
PasswordEncoder passwordEncoder;
|
||||
|
||||
|
||||
// Successfully saves an unencrypted file when no password is provided
|
||||
@Test
|
||||
void test_save_unencrypted_file_without_password() throws IOException {
|
||||
|
||||
@@ -11,5 +11,4 @@ class QuickdropApplicationTests {
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.rostislav.quickdrop;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.rostislav.quickdrop.model.FileEntity;
|
||||
import org.rostislav.quickdrop.model.FileUploadRequest;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TestDataContainer {
|
||||
|
||||
public static FileEntity getFileEntity() {
|
||||
|
||||
Reference in New Issue
Block a user