0.1 #1

Merged
armin merged 30 commits from 0.1 into master 2020-07-26 00:51:55 +00:00
8 changed files with 119 additions and 59 deletions
Showing only changes of commit e9ad499850 - Show all commits

View file

@ -16,13 +16,30 @@ Content-Type: application/json
{"adminName": "admin", "adminPassword":"123"} {"adminName": "admin", "adminPassword":"123"}
-> run-hook (restclient-set-var ":token" (buffer-substring-no-properties 1 (line-end-position))) -> run-hook (restclient-set-var ":token" (buffer-substring-no-properties 1 (line-end-position)))
:token = Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTUxNzY4OTksImV4cCI6MTU5NTM1Njg5OSwic3ViIjoiYWRtaW4ifQ.uRh_xBCrBiLQEBah9I8bYWM-Zph-V_pzQVdaGSU5Mlc :token = Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTU2NzUxMjAsImV4cCI6MTU5NTg1NTEyMCwic3ViIjoiYWRtaW4ifQ.WzrGTTZTYHYOw8SskHQ2_sob2tzLIF6q8y8_2oyuafs
# Get all flings # Get all flings
GET http://localhost:8080/api/fling GET http://localhost:8080/api/fling
Content-Type: application/json Content-Type: application/json
:token :token
:flingid = 9f7353a3-efaa-41af-9f93-61e02dc5e440
# Put a fling
PUT http://localhost:8080/api/fling/:flingid
Content-Type: application/json
:token
{
"id": "9f7353a3-efaa-41af-9f93-61e02dc5e440",
"name": "Shared Fling from querysheetsdfasfd",
"creationTime": 1595253659362,
"shareId": "WWgTlNZJPZDQ6oowUYfxcQqq",
"directDownload": false,
"allowUpload": false,
"shared": true,
"expirationClicks": 12
}
# Add a new fling # Add a new fling
POST http://localhost:8080/api/fling POST http://localhost:8080/api/fling
Content-Type: application/json Content-Type: application/json

View file

@ -101,11 +101,14 @@ public class FlingController {
public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) throws IOException { public ResponseEntity<Resource> getFlingData(@PathVariable UUID id) throws IOException {
FlingDto flingDto = flingService.getById(id); FlingDto flingDto = flingService.getById(id);
InputStreamResource data = new InputStreamResource(archiveService.getFling(id)); InputStreamResource data = new InputStreamResource(archiveService.getFling(id));
Long length = data.contentLength();
data = new InputStreamResource(archiveService.getFling(id));
return ResponseEntity.ok() return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, .header(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=\"" + flingDto.getName() + ".zip" + "\"") "attachment;filename=\"" + flingDto.getName() + ".zip" + "\"")
.contentLength(200L) // FIXME .contentLength(length)
.contentType(MediaType.APPLICATION_OCTET_STREAM) .contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(data); .body(data);
} }

View file

@ -22,7 +22,6 @@ import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.friedl.fling.model.dto.AdminAuthDto; import net.friedl.fling.model.dto.AdminAuthDto;
import net.friedl.fling.model.dto.FlingDto;
import net.friedl.fling.model.dto.UserAuthDto; import net.friedl.fling.model.dto.UserAuthDto;
import net.friedl.fling.persistence.entities.FlingEntity; import net.friedl.fling.persistence.entities.FlingEntity;
import net.friedl.fling.persistence.entities.TokenEntity; import net.friedl.fling.persistence.entities.TokenEntity;

View file

@ -275,7 +275,11 @@ public class FlingControllerTest {
byte[] testZip = new byte[testZipInt.length]; byte[] testZip = new byte[testZipInt.length];
for (int idx = 0; idx < testZip.length; idx++) testZip[idx] = (byte) testZipInt[idx]; for (int idx = 0; idx < testZip.length; idx++) testZip[idx] = (byte) testZipInt[idx];
when(archiveService.getFling(any())).thenReturn(new ByteArrayInputStream(testZip)); when(archiveService.getFling(any()))
.thenAnswer((invocation) -> {
// need to use thenAnswer here to always return a fresh new (unclosed) input stream
return new ByteArrayInputStream(testZip);
});
mockMvc.perform(get("/api/fling/{id}/data", flingId)) mockMvc.perform(get("/api/fling/{id}/data", flingId))
.andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM)) .andExpect(content().contentType(MediaType.APPLICATION_OCTET_STREAM))

View file

@ -26,7 +26,7 @@ function FlingArtifactControl(props) {
log.trace(`Generated download url: ${url}`); log.trace(`Generated download url: ${url}`);
frame.src = url; frame.src = url;
iframeContainer.current.appendChild(frame); iframeContainer.current.appendChild(frame);
}) });
} }
return ( return (

View file

@ -1,27 +1,38 @@
import React, {useRef, useState, useEffect} from 'react'; import log from 'loglevel';
import React, { useRef, useState, useEffect } from 'react';
import {flingClient} from '../../util/flingclient'; import { AuthClient } from '../../util/fc';
export default function FlingUser(props) { export default function FlingUser(props) {
let iframeContainer = useRef(null); let iframeContainer = useRef(null);
let [packaging, setPackaging] = useState(true); let [packaging, setPackaging] = useState(true);
let [done, setDone] = useState(false);
let [waitingMessage, setWaitingMessage] = useState(""); let [waitingMessage, setWaitingMessage] = useState("");
let [downloadUrl, setDownloadUrl] = useState(""); let [downloadUrl, setDownloadUrl] = useState("");
useEffect(handleDownload, []); useEffect(handleDownload, []);
function handleDownload() { function handleDownload() {
flingClient.packageFling(props.fling.id) let authClient = new AuthClient();
.then(downloadUrl => { authClient.deriveToken({ singleUse: true })
.then(token => {
let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
log.trace(`Generated download url for link: ${url}`);
setDownloadUrl(url);
})
.then(
authClient.deriveToken({ singleUse: true })
.then(token => {
setPackaging(false); setPackaging(false);
// We need this iframe hack because with a regular href, while // We need this iframe hack because with a regular href, while
// the browser downloads the file fine, it also reloads the page, hence // the browser downloads the file fine, it also reloads the page, hence
// loosing all logs and state // loosing all logs and state
let frame = document.createElement("iframe"); let frame = document.createElement("iframe");
frame.src = downloadUrl; let url = `${process.env.REACT_APP_API.replace(/\/+$/, '')}/api/fling/${props.fling.id}/data?derivedToken=${token}`;
log.trace(`Generated download url: ${url}`);
frame.src = url;
iframeContainer.current.appendChild(frame); iframeContainer.current.appendChild(frame);
setDownloadUrl(downloadUrl); }));
});
let randMsg = ["Please stay patient...", let randMsg = ["Please stay patient...",
"Your download will be ready soon...", "Your download will be ready soon...",
@ -30,19 +41,36 @@ export default function FlingUser(props) {
setInterval(() => setWaitingMessage(randMsg[Math.floor(Math.random() * randMsg.length)]), 10000); setInterval(() => setWaitingMessage(randMsg[Math.floor(Math.random() * randMsg.length)]), 10000);
} }
return( function invalidateLink(ev) {
setDone(true);
window.location.href = downloadUrl;
}
function reloadPage(ev) {
window.location.reload();
}
return (
<div> <div>
<div className="container-center"> <div className="container-center">
<div className="card direct-download-card"> <div className="card direct-download-card">
<div className="card-body "> <div className="card-body ">
{packaging {packaging
? <><div className="loading loading-lg" /> ? <><div className="loading loading-lg" />
{waitingMessage ? waitingMessage: "Packaging up your files..."} {waitingMessage ? waitingMessage : "Packaging up your files..."}
</>
: !done
? <>
<h5>Your download is <span className="text-primary">ready!</span></h5>
<i className="icon icon-check icon-2x text-primary" /><br />
<span className="text-dark">Download doesn't start? <br />
<button className="btn btn-link" onClick={invalidateLink}>Click here</button></span>
</> </>
: <> : <>
<h5>Your download is <span className="text-primary">ready!</span></h5> <h5>Thanks for <span className="text-primary">downloading!</span></h5>
<i className="icon icon-check icon-2x text-primary" /><br/> <i className="icon icon-check icon-2x text-primary" /><br />
<span className="text-dark">Download doesn't start? <br/><a href={downloadUrl}>Click here</a></span> <span className="text-dark">Want to download again? <br />
<button className="btn btn-link" onClick={reloadPage}>Reload page</button></span>
</> </>
} }
</div> </div>

View file

@ -10,18 +10,27 @@ import FlingUserList from './FlingUserList';
export default function FlingUser() { export default function FlingUser() {
let { shareId } = useParams(); let { shareId } = useParams();
let [fling, setFling] = useState({}); let [fling, setFling] = useState({});
let [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
let flingClient = new FlingClient(); let flingClient = new FlingClient();
flingClient.getFlingByShareId(shareId) flingClient.getFlingByShareId(shareId)
.then(f => setFling(f)); .then(f => {
setFling(f);
setLoading(false);
});
}, [shareId]); }, [shareId]);
return ( return (
<div> <>
{fling.sharing && fling.sharing.directDownload {loading
? <div></div>
: <div>
{fling.shared && fling.directDownload
? <DirectDownload fling={fling} /> ? <DirectDownload fling={fling} />
: <FlingUserList fling={fling} />} : <FlingUserList fling={fling} />}
</div> </div>
}
</>
); );
} }

View file

@ -12,7 +12,7 @@ export default function Unlock() {
useEffect(() => { useEffect(() => {
let authClient = new AuthClient(); let authClient = new AuthClient();
let userAuth = new fc.UserAuth(location.state.shareId, "") let userAuth = new fc.UserAuth(location.state.shareId, "");
authClient.authenticateUser({ 'userAuth': userAuth }) authClient.authenticateUser({ 'userAuth': userAuth })
.then(response => { .then(response => {
@ -20,7 +20,7 @@ export default function Unlock() {
sessionStorage.setItem('token', response); sessionStorage.setItem('token', response);
history.replace(location.state.from); history.replace(location.state.from);
}).catch(error => { }).catch(error => {
log.info("Fling protected. Could not unlock without code.") log.info("Fling protected. Could not unlock without code.");
}); });
}, [location, history]); }, [location, history]);
@ -46,7 +46,7 @@ export default function Unlock() {
function handleSubmit(ev) { function handleSubmit(ev) {
ev.preventDefault(); ev.preventDefault();
let authClient = new AuthClient(); let authClient = new AuthClient();
let userAuth = new fc.UserAuth(shareId, authCode) let userAuth = new fc.UserAuth(shareId, authCode);
authClient.authenticateUser({ 'userAuth': userAuth }) authClient.authenticateUser({ 'userAuth': userAuth })
.then(response => { .then(response => {