diff --git a/file.go b/file.go index 09b7bfb..0e297ca 100644 --- a/file.go +++ b/file.go @@ -46,12 +46,21 @@ func (session Session) AddFile(file *File) (err error) { // {{{ fmt.Printf("%#v\n", file) return } // }}} -func (session Session) Files(nodeID int) (files []File, err error) { // {{{ +func (session Session) Files(nodeID, fileID int) (files []File, err error) { // {{{ var rows *sqlx.Rows rows, err = db.Queryx( - `SELECT * FROM file WHERE user_id = $1 AND node_id = $2`, + `SELECT * + FROM file + WHERE + user_id = $1 AND + node_id = $2 AND + CASE $3::int + WHEN 0 THEN true + ELSE id = $3 + END`, session.UserID, nodeID, + fileID, ) if err != nil { return diff --git a/main.go b/main.go index 5138cbf..8e43d10 100644 --- a/main.go +++ b/main.go @@ -20,7 +20,7 @@ import ( _ "embed" ) -const VERSION = "v0.1.2"; +const VERSION = "v0.1.4"; const LISTEN_HOST = "0.0.0.0"; const DB_SCHEMA = 5 @@ -31,7 +31,6 @@ var ( config Config ) - func init() {// {{{ flag.IntVar( &flagPort, @@ -76,6 +75,7 @@ func main() {// {{{ http.HandleFunc("/node/rename", nodeRename) http.HandleFunc("/node/delete", nodeDelete) http.HandleFunc("/node/upload", nodeUpload) + http.HandleFunc("/node/download", nodeDownload) http.HandleFunc("/ws", websocketHandler) http.HandleFunc("/", staticHandler) @@ -443,6 +443,73 @@ func nodeUpload(w http.ResponseWriter, r *http.Request) {// {{{ "File": nodeFile, }) }// }}} +func nodeDownload(w http.ResponseWriter, r *http.Request) {// {{{ + log.Println("/node/download") + var err error + var session Session + var files []File + + if session, _, err = ValidateSession(r, true); err != nil { + responseError(w, err) + return + } + + req := struct { + NodeID int + FileID int + }{} + if err = parseRequest(r, &req); err != nil { + responseError(w, err) + return + } + + files, err = session.Files(req.NodeID, req.FileID) + if err != nil { + responseError(w, err) + return + } + + if len(files) != 1 { + responseError(w, fmt.Errorf("File not found")) + return + } + + var file *os.File + fname := filepath.Join( + config.Application.Directories.Upload, + files[0].MD5[0:1], + files[0].MD5[1:2], + files[0].MD5[2:3], + files[0].MD5, + ) + file, err = os.Open(fname) + if err != nil { + responseError(w, err) + return + } + + var finfo os.FileInfo + finfo, err = file.Stat() + if err != nil { + responseError(w, err) + return + } + + read := 1 + var buf []byte + for read > 0 { + buf = make([]byte, 65536) + read, err = file.Read(buf) + if read > 0 { + w.Write(buf[0:read]) + } + } + + w.Header().Add("Content-Type", files[0].MIME) + w.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, files[0].Filename)) + w.Header().Add("Content-Length", strconv.Itoa(int(finfo.Size()))) + +}// }}} func nodeFiles(w http.ResponseWriter, r *http.Request) {// {{{ var err error var session Session @@ -461,7 +528,7 @@ func nodeFiles(w http.ResponseWriter, r *http.Request) {// {{{ return } - files, err = session.Files(req.NodeID) + files, err = session.Files(req.NodeID, 0) if err != nil { responseError(w, err) return diff --git a/node.go b/node.go index a2b2050..29aad65 100644 --- a/node.go +++ b/node.go @@ -204,7 +204,7 @@ func (session Session) Node(nodeID int) (node Node, err error) {// {{{ } node.Crumbs, err = session.NodeCrumbs(node.ID) - node.Files, err = session.Files(node.ID) + node.Files, err = session.Files(node.ID, 0) return }// }}} diff --git a/static/css/main.css b/static/css/main.css index cf46ba8..0d06d80 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -204,7 +204,7 @@ header .menu { #file-section { justify-self: center; width: 900px; - margin-top: 32px; + margin-top: 16px; padding: 32px; background: #f5f5f5; } @@ -224,6 +224,10 @@ header .menu { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + cursor: pointer; +} +#file-section .files .filename:hover { + text-decoration: underline; } #file-section .files .size { white-space: nowrap; @@ -232,13 +236,17 @@ header .menu { .tree { padding: 16px; } -@media only screen and (max-width: 100ex) { +@media only screen and (max-width: 932px) { .node-content { - width: 100%; + width: calc(100% - 32px); + margin-left: 16px; + padding: 16px; justify-self: start; } #file-section { - width: 100%; + width: calc(100% - 32px); + padding: 16px; + margin-left: 16px; justify-self: start; } } diff --git a/static/js/node.mjs b/static/js/node.mjs index ebb7369..1b711a8 100644 --- a/static/js/node.mjs +++ b/static/js/node.mjs @@ -226,7 +226,7 @@ class NodeFiles extends Component { }) .map(file=> html` -
${file.Filename}
+
node.download(file.ID)}>${file.Filename}
${this.formatSize(file.Size)}
` ) @@ -308,6 +308,37 @@ class Node { .then(callback) .catch(this.app.responseError) }//}}} + download(fileID) {//{{{ + let headers = { + 'Content-Type': 'application/json', + } + + if(this.app.session.UUID !== '') + headers['X-Session-Id'] = this.app.session.UUID + + let fname = "" + fetch("/node/download", { + method: 'POST', + headers, + body: JSON.stringify({ + NodeID: this.ID, + FileID: fileID, + }), + }) + .then(response=>{ + console.log(...response.headers); + return response.blob() + }) + .then(blob=>{ + let url = window.URL.createObjectURL(blob) + let a = document.createElement('a'); + a.href = url; + a.download = "filename.xlsx"; + document.body.appendChild(a); // we need to append the element to the dom -> otherwise it will not work in firefox + a.click(); + a.remove(); //afterwards we remove the element again + }) + }//}}} children(callback) {//{{{ this.app.request('/node/tree', { StartNodeID: this.ID }) .then(res=>{ diff --git a/static/less/main.less b/static/less/main.less index 40b18f7..6cedf73 100644 --- a/static/less/main.less +++ b/static/less/main.less @@ -240,7 +240,7 @@ header { #file-section { justify-self: center; width: 900px; - margin-top: 32px; + margin-top: 16px; padding: 32px; background: #f5f5f5; @@ -261,6 +261,11 @@ header { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + cursor: pointer; + + &:hover { + text-decoration: underline; + } } .size { @@ -274,14 +279,18 @@ header { padding: 16px; } -@media only screen and (max-width: 100ex) { +@media only screen and (max-width: 932px) { .node-content { - width: 100%; + width: calc(100% - 32px); + margin-left: 16px; + padding: 16px; justify-self: start; } #file-section { - width: 100%; + width: calc(100% - 32px); + padding: 16px; + margin-left: 16px; justify-self: start; } }