ctrl + v when file modal is open and drag file to instantly upload

This commit is contained in:
spitkov 2024-09-15 17:03:38 -04:00
parent fa373d6b46
commit 29e26aa647
6 changed files with 278 additions and 44 deletions

12
app.py
View File

@ -668,17 +668,23 @@ def shorten_url():
return jsonify({'success': False, 'error': 'URL is required'}), 400 return jsonify({'success': False, 'error': 'URL is required'}), 400
long_url = data['url'] long_url = data['url']
password = data.get('password') # Get the password if provided
vanity = shortuuid.uuid()[:8] vanity = shortuuid.uuid()[:8]
user_id = current_user.id if current_user.is_authenticated else None user_id = current_user.id if current_user.is_authenticated else None
db = get_db() db = get_db()
cursor = db.cursor() cursor = db.cursor()
cursor.execute("INSERT INTO content (vanity, type, data, created_at, user_id) VALUES (?, ?, ?, ?, ?)",
(vanity, 'url', long_url, datetime.now(), user_id)) is_private = 1 if password else 0
cursor.execute("""
INSERT INTO content (vanity, type, data, created_at, user_id, is_private, password)
VALUES (?, ?, ?, ?, ?, ?, ?)
""", (vanity, 'url', long_url, datetime.now(), user_id, is_private, password))
db.commit() db.commit()
# Return only the vanity code, not the full URL
return jsonify({'success': True, 'vanity': vanity}), 200 return jsonify({'success': True, 'vanity': vanity}), 200
except Exception as e: except Exception as e:
print("Exception occurred:", str(e)) print("Exception occurred:", str(e))

View File

@ -66,7 +66,13 @@
</br> </br>
</br> </br>
</br> </br>
<p>Source code on: </p><a href="https://github.com/realcgcristi/aCloud" target="_blank">GitHub</a> | <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> <div class="footer">
<p>
Source code on: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -258,6 +258,40 @@
.other-links.show { .other-links.show {
display: block; display: block;
} }
.global-drop-area {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}
.global-drop-box {
border: 3px dashed #4CAF50;
border-radius: 20px;
padding: 50px;
text-align: center;
background-color: rgba(0, 0, 0, 0.7);
color: white;
}
.instant-upload-result {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #2a2a2a;
padding: 20px;
border-radius: 10px;
z-index: 10000;
display: none;
}
</style> </style>
</head> </head>
<body> <body>
@ -329,15 +363,37 @@
<span class="close" onclick="closeModal('urlModal')">&times;</span> <span class="close" onclick="closeModal('urlModal')">&times;</span>
<h2>Shorten URL</h2> <h2>Shorten URL</h2>
<input type="text" id="urlInput" placeholder="Enter URL here..."> <input type="text" id="urlInput" placeholder="Enter URL here...">
<div>
<input type="checkbox" id="urlIsPrivate" name="urlIsPrivate">
<label for="urlIsPrivate">Add password protection</label>
</div>
<div id="urlPasswordField" style="display: none;">
<input type="password" id="urlPassword" placeholder="Enter password">
</div>
<button onclick="shortenUrl()">Shorten URL</button> <button onclick="shortenUrl()">Shorten URL</button>
<div id="urlResult"></div> <div id="urlResult"></div>
</div> </div>
</div> </div>
<div class="global-drop-area">
<div class="global-drop-box">
<h2>Drop file to instantly upload</h2>
</div>
</div>
<div class="instant-upload-result">
<h3>File Uploaded</h3>
<p>Direct download URL: <a id="directDownloadUrl" href="#" target="_blank"></a></p>
<p>Normal URL: <a id="normalUrl" href="#" target="_blank"></a></p>
<button onclick="closeInstantUploadResult()">Close</button>
</div>
<footer class="footer"> <footer class="footer">
<p>Source code available on: <p>Source code available on:
<a href="https://github.com/realcgcristi/order" target="_blank">GitHub (not up-to-date)</a> |
<a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git (main)</a> <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git (main)</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p> </p>
</footer> </footer>
@ -433,6 +489,10 @@
document.getElementById('filePasswordField').style.display = this.checked ? 'block' : 'none'; document.getElementById('filePasswordField').style.display = this.checked ? 'block' : 'none';
}); });
document.getElementById('urlIsPrivate').addEventListener('change', function() {
document.getElementById('urlPasswordField').style.display = this.checked ? 'block' : 'none';
});
function uploadText() { function uploadText() {
const content = document.getElementById('textContent').value; const content = document.getElementById('textContent').value;
const isPrivate = document.getElementById('isPrivate').checked; const isPrivate = document.getElementById('isPrivate').checked;
@ -608,13 +668,20 @@
function shortenUrl() { function shortenUrl() {
const url = document.getElementById('urlInput').value; const url = document.getElementById('urlInput').value;
const isPrivate = document.getElementById('urlIsPrivate').checked;
const password = isPrivate ? document.getElementById('urlPassword').value : null;
const data = {
url: url,
password: password
};
fetch('/shorten', { fetch('/shorten', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ url: url }), body: JSON.stringify(data),
}) })
.then(response => { .then(response => {
if (!response.ok) { if (!response.ok) {
@ -625,7 +692,11 @@
.then(data => { .then(data => {
if (data.success) { if (data.success) {
const shortUrl = `${window.location.origin}/${data.vanity}`; const shortUrl = `${window.location.origin}/${data.vanity}`;
document.getElementById('urlResult').innerHTML = `URL shortened. Access it <a href="${shortUrl}" target="_blank">${shortUrl}</a>`; let resultHtml = `URL shortened. Access it <a href="${shortUrl}" target="_blank">${shortUrl}</a>`;
if (isPrivate) {
resultHtml += `<br>Password-protected link: <a href="${shortUrl}/${password}" target="_blank">${shortUrl}/${password}</a>`;
}
document.getElementById('urlResult').innerHTML = resultHtml;
} else { } else {
document.getElementById('urlResult').innerHTML = `Error: ${data.error}`; document.getElementById('urlResult').innerHTML = `Error: ${data.error}`;
} }
@ -635,6 +706,70 @@
document.getElementById('urlResult').innerHTML = `An error occurred: ${error.message}`; document.getElementById('urlResult').innerHTML = `An error occurred: ${error.message}`;
}); });
} }
// Global drag and drop
document.addEventListener('dragover', function(e) {
e.preventDefault();
document.querySelector('.global-drop-area').style.display = 'flex';
});
document.addEventListener('dragleave', function(e) {
if (e.clientX === 0 || e.clientY === 0) {
document.querySelector('.global-drop-area').style.display = 'none';
}
});
document.addEventListener('drop', function(e) {
e.preventDefault();
document.querySelector('.global-drop-area').style.display = 'none';
if (e.dataTransfer.files.length > 0) {
instantUploadFile(e.dataTransfer.files[0]);
}
});
function instantUploadFile(file) {
const formData = new FormData();
formData.append('file', file);
fetch('/upload/file', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('directDownloadUrl').href = data.download_url;
document.getElementById('directDownloadUrl').textContent = data.download_url;
document.getElementById('normalUrl').href = data.url;
document.getElementById('normalUrl').textContent = data.url;
document.querySelector('.instant-upload-result').style.display = 'block';
} else {
alert('Error uploading file: ' + data.error);
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred while uploading the file');
});
}
function closeInstantUploadResult() {
document.querySelector('.instant-upload-result').style.display = 'none';
}
// Paste functionality for file upload
document.addEventListener('paste', function(e) {
if (document.getElementById('fileModal').style.display === 'block') {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].kind === 'file') {
const file = items[i].getAsFile();
filesToUpload.push(file);
updateSelectedFilesList();
}
}
}
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -11,12 +11,17 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
display: flex; display: flex;
justify-content: center; flex-direction: column;
align-items: center;
min-height: 100vh; min-height: 100vh;
background-color: #1a1a1a; background-color: #1a1a1a;
color: #f0f0f0; color: #f0f0f0;
} }
.content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.container { .container {
background-color: #2a2a2a; background-color: #2a2a2a;
padding: 20px; padding: 20px;
@ -75,27 +80,54 @@
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
.back-button {
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: #4CAF50;
text-decoration: none;
}
.back-button:hover {
color: #45a049;
}
.footer {
text-align: center;
padding: 10px;
background-color: #2a2a2a;
color: #f0f0f0;
}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <a href="/" class="back-button">&#8592;</a>
<h2>Login</h2> <div class="content">
<form method="POST"> <div class="container">
<div> <h2>Login</h2>
<label for="username">Username:</label> <form method="POST">
<input type="text" id="username" name="username" required> <div>
</div> <label for="username">Username:</label>
<div> <input type="text" id="username" name="username" required>
<label for="password">Password:</label> </div>
<input type="password" id="password" name="password" required> <div>
</div> <label for="password">Password:</label>
<div class="remember-me"> <input type="password" id="password" name="password" required>
<input type="checkbox" id="remember" name="remember"> </div>
<label for="remember">Remember me</label> <div class="remember-me">
</div> <input type="checkbox" id="remember" name="remember">
<button type="submit">Login</button> <label for="remember">Remember me</label>
</form> </div>
<p>Don't have an account? <a href="{{ url_for('register') }}">Register here</a></p> <button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="{{ url_for('register') }}">Register here</a></p>
</div>
</div> </div>
<footer class="footer">
<p>
Source code: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</footer>
</body> </body>
</html> </html>

View File

@ -185,10 +185,25 @@
color: white; color: white;
} }
.home-button {
position: fixed;
top: 20px;
left: 20px;
font-size: 24px;
color: var(--text-color);
text-decoration: none;
z-index: 1001;
}
.home-button:hover {
color: #4CAF50;
}
{{ css|safe }} {{ css|safe }}
</style> </style>
</head> </head>
<body> <body>
<a href="/" class="home-button">&#8962;</a>
<div class="container"> <div class="container">
<h2>Content</h2> <h2>Content</h2>
<p>Uploaded by: {{ content.username }}</p> <p>Uploaded by: {{ content.username }}</p>
@ -229,6 +244,14 @@
</div> </div>
</div> </div>
<footer style="text-align: center; margin-top: 20px; padding: 10px; background-color: #2a2a2a; color: #f0f0f0;">
<p>
Source code: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</footer>
<script> <script>
const rawContent = {{ raw_content|tojson }}; const rawContent = {{ raw_content|tojson }};

View File

@ -11,12 +11,17 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
display: flex; display: flex;
justify-content: center; flex-direction: column;
align-items: center;
min-height: 100vh; min-height: 100vh;
background-color: #1a1a1a; background-color: #1a1a1a;
color: #f0f0f0; color: #f0f0f0;
} }
.content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.container { .container {
background-color: #2a2a2a; background-color: #2a2a2a;
padding: 20px; padding: 20px;
@ -67,23 +72,50 @@
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
.back-button {
position: absolute;
top: 20px;
left: 20px;
font-size: 24px;
color: #4CAF50;
text-decoration: none;
}
.back-button:hover {
color: #45a049;
}
.footer {
text-align: center;
padding: 10px;
background-color: #2a2a2a;
color: #f0f0f0;
}
</style> </style>
</head> </head>
<body> <body>
<div class="container"> <a href="/" class="back-button">&#8592;</a>
<h2>Register</h2> <div class="content">
<form method="POST"> <div class="container">
<div> <h2>Register</h2>
<label for="username">Username:</label> <form method="POST">
<input type="text" id="username" name="username" required> <div>
</div> <label for="username">Username:</label>
<div> <input type="text" id="username" name="username" required>
<label for="password">Password:</label> </div>
<input type="password" id="password" name="password" required> <div>
</div> <label for="password">Password:</label>
<button type="submit">Register</button> <input type="password" id="password" name="password" required>
</form> </div>
<p>Already have an account? <a href="{{ url_for('login') }}">Login here</a></p> <button type="submit">Register</button>
</form>
<p>Already have an account? <a href="{{ url_for('login') }}">Login here</a></p>
</div>
</div> </div>
<footer class="footer">
<p>
Source code: <a href="https://git.spitkov.hu/cgcristi/aCloud" target="_blank">Spitkov's Git</a> |
<a href="https://office.bence.lol/form/#/2/form/view/z5Cf3CL6tZtPjzKsbcEPync6JE3iyMl22h6thUQg1a4/" target="_blank">Suggestions & Bugs</a> |
<a href="https://office.bence.lol/kanban/#/2/kanban/view/hx6RTcpN0pR7hc1HHkMzG4awMoMdHjR2zbHjG7Xh+wU/embed/" target="_blank">Todo List</a>
</p>
</footer>
</body> </body>
</html> </html>