diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index c658edef..e4f3d961 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -1560,8 +1560,8 @@ class HttpCli(object): raise Pebkac(403, "disabled by argv") # full path of new loc (incl filename) - dst = self.uparam.get("to") - if dst is None: + dst = self.uparam.get("move") + if not dst: raise Pebkac(400, "need dst vpath") x = self.conn.hsrv.broker.put( diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 98b5646b..737c7274 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -1302,9 +1302,12 @@ class Up2k(object): # dbv, vrem = dbv.get_dbv(vrem) _ = dbv.get(vrem, uname, *permsets[0]) with self.mutex: - ptop = dbv.realpath - cur, wark = self._find_from_vpath(ptop, vrem) - self._forget_file(ptop, vpath, cur, wark) + try: + ptop = dbv.realpath + cur, wark = self._find_from_vpath(ptop, vrem) + self._forget_file(ptop, vpath, cur, wark) + finally: + cur.connection.commit() bos.unlink(abspath) @@ -1318,7 +1321,7 @@ class Up2k(object): return "deleted {} files (and {}/{} folders)".format(n_files, n_dirs, len(dirs)) - def _handle_mv(self, uname, svp, dvp): + def handle_mv(self, uname, svp, dvp): svn, srem = self.asrv.vfs.get(svp, uname, True, False, True) dvn, drem = self.asrv.vfs.get(dvp, uname, False, True) sabs = svn.canonical(srem) @@ -1335,15 +1338,16 @@ class Up2k(object): c2 = self.cur.get(dvn.realpath) if c1 and c2: q = "select rd, fn from up where substr(w,1,16)=? and w=?" - hit = c2.execute(q, (w[:16], w)).fetchone() - if hit: - # found in dest vol, just need a symlink - rd, fn = hit + for rd, fn in c2.execute(q, (w[:16], w)): if rd.startswith("//") or fn.startswith("//"): rd, fn = s3dec(rd, fn) - slabs = "{}/{}".join(rd, fn).strip("/") + slabs = "{}/{}".format(rd, fn).strip("/") slabs = absreal(os.path.join(dvn.realpath, slabs)) + if slabs == sabs: + # hit is src + continue + if bos.path.exists(slabs): self.log("mv: quick relink, nice") self._symlink(slabs, dabs) @@ -1355,6 +1359,8 @@ class Up2k(object): bos.rename(sabs, slabs) self._forget_file(svn.realpath, srem, c1, w) + c1.connection.commit() + c2.connection.commit() return "k" # not found in dst db; copy info @@ -1366,9 +1372,11 @@ class Up2k(object): if c1: self._forget_file(svn.realpath, srem, c1, w) + c1.connection.commit() if c2: self.db_add(c2, w, drd, dfn, st.st_mtime, st.st_size) + c2.connection.commit() bos.rename(sabs, dabs) return "k" @@ -1402,14 +1410,12 @@ class Up2k(object): def _forget_file(self, ptop, vrem, cur, wark): """forgets file in db, fixes symlinks, does not delete""" - fn = vrem.split("/")[-1] - wark = None + srd, sfn = vsplit(vrem) dupes = [] self.log("forgetting {}".format(vrem)) if wark: # found in db; find dupes - wark = wark[0] self.log("found {} in db".format(wark)) q = "select rd, fn from up where substr(w,1,16)=? and w=?" @@ -1425,10 +1431,11 @@ class Up2k(object): if dupes: # fix symlinks self._relink(ptop, dupes, vrem, None) - else: - # drop tags + elif wark: + # thus cur; drop tags q = "delete from mt where w=?" cur.execute(q, (wark[:16],)) + self.db_rm(cur, srd, sfn) reg = self.registry.get(ptop) if reg: diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index 34055a6c..6d5ca600 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -1546,7 +1546,7 @@ var fileman = (function () { r.paste = function (e) { ev(e); if (!r.clip.length) - return alert('first cut some items to paste\n\nnote: you can cut/paste across different tabs'); + return alert('first cut some items to paste\n\nnote: you can cut/paste across different browser tabs'); var req = [], exists = [], @@ -1574,6 +1574,36 @@ var fileman = (function () { if (!confirm('paste these ' + req.length + ' items here?\n\n' + req.join('\n'))) return; + function paster() { + var xhr = new XMLHttpRequest(), + vp = req.shift(); + + if (!vp) { + toast.show('paste OK', 2000); + treectl.goto(get_evpath()); + return; + } + toast.show('pasting ' + (req.length + 1) + ' items

' + vp, 2000); + + var dst = get_evpath() + vp.split('/').slice(-1)[0]; + + xhr.open('GET', vp + '?move=' + dst, true); + xhr.onreadystatechange = paste_cb; + xhr.send(); + } + function paste_cb() { + if (this.readyState != XMLHttpRequest.DONE) + return; + + if (this.status !== 200) { + var msg = this.responseText; + toast.show('paste failed:
' + msg, 2000); + return; + } + paster(); + } + paster(); + jwrite('fman_clip', []); r.tx(); };