diff --git a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java
index 1e58c2d..8f8fb75 100644
--- a/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java
+++ b/service/fling/src/main/java/net/friedl/fling/service/AuthorizationService.java
@@ -2,6 +2,7 @@ package net.friedl.fling.service;
import java.util.UUID;
import javax.persistence.EntityNotFoundException;
+import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.stereotype.Service;
@@ -13,6 +14,7 @@ import net.friedl.fling.security.authentication.FlingToken;
@Slf4j
@Service
+@Transactional
public class AuthorizationService {
private FlingRepository flingRepository;
@@ -32,7 +34,8 @@ public class AuthorizationService {
return true;
}
- if (!flingRepository.getOne(flingId).getAllowUpload()) {
+ FlingEntity flingEntity = flingRepository.getOne(flingId);
+ if (flingEntity.getAllowUpload() == null || !flingEntity.getAllowUpload()) {
log.debug("Fling[.id={}] does not not allow uploads");
return false;
}
diff --git a/web/fling/src/components/user/FlingUserList.jsx b/web/fling/src/components/user/FlingUserList.jsx
index 8985435..9d213c3 100644
--- a/web/fling/src/components/user/FlingUserList.jsx
+++ b/web/fling/src/components/user/FlingUserList.jsx
@@ -1,380 +1,341 @@
import log from 'loglevel';
-import React, {useState, useEffect, useRef} from 'react';
+import React, { useState, useEffect, useRef } from 'react';
-import {Switch, Route, useLocation, Link} from "react-router-dom";
+import { Switch, Route, useLocation, Link } from "react-router-dom";
-import {flingClient, artifactClient} from '../../util/flingclient';
+import { FlingClient, AuthClient, ArtifactClient, fc } from '../../util/fc';
+import { prettifyTimestamp, prettifyBytes } from '../../util/fn';
import upload from '../resources/upload.svg';
import drop from '../resources/drop.svg';
function Artifacts(props) {
- let [artifacts, setArtifacts] = useState([]);
+ let [artifacts, setArtifacts] = useState([]);
- useEffect(() => {
- if(!props.fling) return;
+ useEffect(() => {
+ if (!props.fling) return;
- artifactClient.getArtifacts(props.fling.id)
- .then((artifacts) => setArtifacts(artifacts));
- }, [props.fling]);
+ let flingClient = new FlingClient();
+ flingClient.getArtifacts(props.fling.id)
+ .then(artifacts => setArtifacts(artifacts));
+ }, [props.fling]);
- function renderArtifact(artifact) {
- function readableBytes(bytes) {
- if(bytes <= 0) return "0 KB";
-
- var i = Math.floor(Math.log(bytes) / Math.log(1024)),
- sizes = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
-
- return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
- }
-
- function localizedDate(t) {
- let d = new Date(t);
- return d.toLocaleDateString();
- }
-
- return(
-
-
-
-
- {artifact.name}
-
-
-
{readableBytes(artifact.size)}
-
-
-
{localizedDate(artifact.uploadTime)}
-
-
-
-
- );
- }
+ function renderArtifact(artifact) {
return (
-
- {artifacts.map(renderArtifact)}
+
+
+
+
+ {artifact.path}
+
+
+
+
{prettifyTimestamp(artifact.creationTime)}
+
+
+
);
+ }
+
+ return (
+
+ {artifacts.map(renderArtifact)}
+
+ );
}
function Upload(props) {
- let fileInputRef = useRef(null);
- let [files, setFiles] = useState([]);
- let [dragging, setDragging] = useState(false);
- let [dragCount, setDragCount] = useState(0);
+ let fileInputRef = useRef(null);
+ let [files, setFiles] = useState([]);
+ let [dragging, setDragging] = useState(false);
+ let [dragCount, setDragCount] = useState(0);
- useEffect(() => {
- // prevent browser from trying to open the file when drag event
- // not recognized properly
- window.addEventListener("dragover",function(e){
- e.preventDefault();
- },false);
- window.addEventListener("drop",function(e){
- e.preventDefault();
- },false);
- });
-
- function fileList() {
- function readableBytes(bytes) {
- if(bytes <= 0) return "0 KB";
-
- var i = Math.floor(Math.log(bytes) / Math.log(1024)),
- sizes = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
-
- return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
- }
-
- let fileList = [];
- files.forEach((file,idx) => {
- if(!file.uploaded) {
- fileList.push(
-
-
-
-
deleteFile(idx)}/>
- {file.name}
- {(new Date(file.lastModified)).toLocaleString()+", "+readableBytes(file.size)}
-
-
-
- );
- }
- });
-
- return fileList;
- }
-
- function deleteFile(idx) {
- let f = [...files];
- f.splice(idx, 1);
- setFiles(f);
- }
-
- function totalSize() {
- function readableBytes(bytes) {
- if(bytes <= 0) return "0 KB";
-
- var i = Math.floor(Math.log(bytes) / Math.log(1024)),
- sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
-
- return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
- }
-
- let totalSize = 0;
- for(let file of files) {
- totalSize += file.size;
- }
-
- return readableBytes(totalSize);
- }
-
- function handleClick(ev) {
- fileInputRef.current.click();
- }
-
- function handleFileInputChange(ev) {
- let fileInputFiles = fileInputRef.current.files;
- if (!fileInputFiles) {
- console.warn("No files selected");
- return;
- }
-
- setFiles([...files, ...fileInputFiles]);
- }
-
- function handleDrop(ev) {
- stopEvent(ev);
- ev.persist();
-
- let evFiles = ev.dataTransfer.files;
-
- if (!evFiles) {
- console.warn("Dropzone triggered without files");
- return;
- }
-
- setFiles([...files, ...fileListToArray(evFiles)]);
- setDragging(false);
- setDragCount(0);
- }
-
- function fileListToArray(fileList) {
- if(fileList === undefined || fileList === null) {
- return [];
- }
-
- let arr = [];
- for (let i=0; i
i.name).join(',')+"]");
- }
-
- function setFileUploaded(idx) {
- let f = [...files];
- f[idx].uploaded = true;
- setFiles(f);
- }
-
- function handleUpload() {
- files.forEach((file, idx) => {
- artifactClient.postArtifact(props.fling.id, file)
- .then(response => {
- setFileUploaded(idx);
- });
- });
- }
-
- function zoneContent(dragging) {
- if(dragging){
- return(
- <>
-
- Drop now!
- >
- );
- }else {
- return(
- <>
-
- Click or Drop
- >
- );
- }
- }
-
- return(
-
- {logFiles()}
-
-
-
-
-
- {zoneContent(dragging)}
+ useEffect(() => {
+ // prevent browser from trying to open the file when drag event
+ // not recognized properly
+ window.addEventListener("dragover", function(e) {
+ e.preventDefault();
+ }, false);
+ window.addEventListener("drop", function(e) {
+ e.preventDefault();
+ }, false);
+ });
+ function fileList() {
+ let fileList = [];
+ files.forEach((file, idx) => {
+ if (!file.uploaded) {
+ fileList.push(
+
+
+
+
deleteFile(idx)} />
+ {file.name}
+ {(new Date(file.lastModified)).toLocaleString() + ", " + prettifyBytes(file.size)}
+
+ );
+ }
+ });
-
-
-
-
-
Total Size: {totalSize()}
-
+ return fileList;
+ }
+
+ function deleteFile(idx) {
+ let f = [...files];
+ f.splice(idx, 1);
+ setFiles(f);
+ }
+
+ function totalSize() {
+ let totalSize = 0;
+ for (let file of files) {
+ totalSize += file.size;
+ }
+
+ return prettifyBytes(totalSize);
+ }
+
+ function handleClick(ev) {
+ fileInputRef.current.click();
+ }
+
+ function handleFileInputChange(ev) {
+ let fileInputFiles = fileInputRef.current.files;
+ if (!fileInputFiles) {
+ console.warn("No files selected");
+ return;
+ }
+
+ setFiles([...files, ...fileInputFiles]);
+ }
+
+ function handleDrop(ev) {
+ stopEvent(ev);
+ ev.persist();
+
+ let evFiles = ev.dataTransfer.files;
+
+ if (!evFiles) {
+ console.warn("Dropzone triggered without files");
+ return;
+ }
+
+ setFiles([...files, ...fileListToArray(evFiles)]);
+ setDragging(false);
+ setDragCount(0);
+ }
+
+ function fileListToArray(fileList) {
+ if (fileList === undefined || fileList === null) {
+ return [];
+ }
+
+ let arr = [];
+ for (let i = 0; i < fileList.length; i++) { arr.push(fileList[i]); }
+
+ return arr;
+ }
+
+ function handleOnDragEnter(ev) {
+ stopEvent(ev);
+ if (dragCount === 0) setDragging(true);
+
+ setDragCount(dragCount + 1);
+ }
+
+ function handleOnDragLeave(ev) {
+ stopEvent(ev);
+ let dc = dragCount;
+
+ dc -= 1;
+ setDragCount(dc);
+
+ if (dc === 0) setDragging(false);
+ }
+
+ function stopEvent(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+
+ function logFiles() {
+ log.info("Files so far: [" + files.map((i) => i.name).join(',') + "]");
+ }
+
+ function setFileUploaded(idx) {
+ let f = [...files];
+ f[idx].uploaded = true;
+ setFiles(f);
+ }
+
+ function handleUpload() {
+ const flingClient = new FlingClient();
+ const artifactClient = new ArtifactClient();
+
+ files.forEach((file, idx) => {
+ let artifact = new fc.Artifact(file.name)
+
+ flingClient.postArtifact(props.fling.id, { artifact: artifact })
+ .then(artifact => {
+ artifactClient.uploadArtifactData(artifact.id, { body: file });
+ setFileUploaded(idx);
+ });
+ });
+ }
+
+ function zoneContent(dragging) {
+ if (dragging) {
+ return (
+ <>
+
+
Drop now!
+ >
+ );
+ } else {
+ return (
+ <>
+
+
Click or Drop
+ >
+ );
+ }
+ }
+
+ return (
+
+ {logFiles()}
+
+
+
+
+
+ {zoneContent(dragging)}
+
+
+
+
+
+
+
+
+ Total Size: {totalSize()}
+
+
- );
+
+
+ );
}
export default function FlingUserList(props) {
- let location = useLocation();
+ let location = useLocation();
- let iframeContainer = useRef(null);
- let [infoText, setInfoText] = useState("");
- let [inProgress, setInProgress] = useState(false);
+ let iframeContainer = useRef(null);
+ let [infoText, setInfoText] = useState("");
+ let [inProgress, setInProgress] = useState(false);
- useEffect((flingId) => {
- if(!flingId) return;
+ useEffect(() => {
+ if (!props.fling.id) return;
- function readableBytes(bytes) {
- if(bytes <= 0) return "0 KB";
+ let flingClient = new FlingClient();
+ flingClient.getArtifacts(props.fling.id)
+ .then((artifacts) => {
+ setInfoText(`${prettifyTimestamp(props.fling.creationTime)} - ${artifacts.length} files`);
+ });
+ }, [props.fling.id, props.fling.creationTime]);
- var i = Math.floor(Math.log(bytes) / Math.log(1024)),
- sizes = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+ function handleDownload(ev) {
+ ev.preventDefault();
- return (bytes / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
- }
+ setInProgress(true);
+ let authClient = new AuthClient();
+ authClient.deriveToken({ singleUse: true })
+ .then(token => {
+ // We need this iframe hack because with a regular href, while
+ // the browser downloads the file fine, it also reloads the page, hence
+ // loosing all logs and state
+ let frame = document.createElement("iframe");
+ 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;
+ setInProgress(false);
+ iframeContainer.current.appendChild(frame);
+ });
+ }
- function localizedDate(t) {
- let d = new Date(t);
- return d.toLocaleDateString();
- }
-
- artifactClient.getArtifacts(flingId)
- .then((artifacts) => {
- let totalSize = 0;
- let countArtifacts = 0;
-
- for(let artifact of artifacts) {
- totalSize += artifact.size;
- countArtifacts++;
- }
-
- setInfoText(`${localizedDate(props.fling.creationTime)} - ${countArtifacts} files - ${readableBytes(totalSize)}`);
- });
- }, [props.fling.id, props.fling.creationTime]);
-
- function handleDownload(ev) {
- ev.preventDefault();
-
- setInProgress(true);
-
- flingClient.packageFling(props.fling.id)
- .then(downloadUrl => {
- // We need this iframe hack because with a regular href, while
- // the browser downloads the file fine, it also reloads the page, hence
- // loosing all logs and state
- let frame = document.createElement("iframe");
- frame.src = downloadUrl;
- iframeContainer.current.appendChild(frame);
- setInProgress(false);
- });
+ function path(tail) {
+ if (props.fling && props.fling.shareId) {
+ return `/f/${props.fling.shareId}/${tail}`;
}
- function path(tail) {
- if(props.fling && props.fling.sharing) {
- return `/f/${props.fling.sharing.shareUrl}/${tail}`;
- }
+ return "";
+ }
- return "";
- }
+ return (
+ <>
+
- return(
- <>
-
+
-
+
{props.fling.name}
+
{infoText}
-
{props.fling.name}
-
{infoText}
+
+
+ -
+ Files
+
+ { props.fling.allowUpload
+ ? -
+ Upload
+
+ : <>>
+ }
-
-
- -
- Files
-
- -
- Upload
-
-
- -
-
- {inProgress
- ?
-
-
+ : Download
+ }
+
+
+
+
- >
- );
+
+
+
+
+
+ >
+ );
}
diff --git a/web/fling/src/components/user/FlingUserUpload.jsx b/web/fling/src/components/user/FlingUserUpload.jsx
deleted file mode 100644
index 6f7c18a..0000000
--- a/web/fling/src/components/user/FlingUserUpload.jsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import log from 'loglevel';
-import React, {useState, useEffect} from 'react';
-
-import {useParams, BrowserRouter} from 'react-router-dom';
-
-import {flingClient} from '../../util/flingclient';
-
-import DirectDownload from './DirectDownload';
-
-export default function FlingUserUpload(props) {
- let { shareId } = useParams();
- let [fling, setFling] = useState({});
-
- useEffect(() => {
- flingClient.getFlingByShareId(shareId)
- .then(f => setFling(f));
- }, [shareId]);
-
- return(
-
- {fling.sharing && fling.sharing.directDownload ? : ""}
-
- );
-}
-