mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
verify markdown saves with a full roundtrip
This commit is contained in:
parent
da1094db84
commit
6e43ee7cc7
|
@ -8,7 +8,6 @@ import time
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import calendar
|
import calendar
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from .__init__ import E, PY2, WINDOWS
|
from .__init__ import E, PY2, WINDOWS
|
||||||
from .util import * # noqa # pylint: disable=unused-wildcard-import
|
from .util import * # noqa # pylint: disable=unused-wildcard-import
|
||||||
|
@ -526,7 +525,7 @@ class HttpCli(object):
|
||||||
except Pebkac as ex:
|
except Pebkac as ex:
|
||||||
errmsg = str(ex)
|
errmsg = str(ex)
|
||||||
|
|
||||||
td = time.time() - t0
|
td = max(0.1, time.time() - t0)
|
||||||
sz_total = sum(x[0] for x in files)
|
sz_total = sum(x[0] for x in files)
|
||||||
spd = (sz_total / td) / (1024 * 1024)
|
spd = (sz_total / td) / (1024 * 1024)
|
||||||
|
|
||||||
|
@ -665,6 +664,7 @@ class HttpCli(object):
|
||||||
return file_lastmod, int(file_ts) > int(cli_ts)
|
return file_lastmod, int(file_ts) > int(cli_ts)
|
||||||
except:
|
except:
|
||||||
self.log("bad lastmod format: {}".format(cli_lastmod))
|
self.log("bad lastmod format: {}".format(cli_lastmod))
|
||||||
|
self.log(" expected format: {}".format(file_lastmod))
|
||||||
return file_lastmod, file_lastmod != cli_lastmod
|
return file_lastmod, file_lastmod != cli_lastmod
|
||||||
|
|
||||||
return file_lastmod, True
|
return file_lastmod, True
|
||||||
|
@ -789,7 +789,7 @@ class HttpCli(object):
|
||||||
self.send_headers(
|
self.send_headers(
|
||||||
length=upper - lower,
|
length=upper - lower,
|
||||||
status=status,
|
status=status,
|
||||||
mime=mimetypes.guess_type(req_path)[0] or "application/octet-stream",
|
mime=guess_mime(req_path)[0] or "application/octet-stream",
|
||||||
)
|
)
|
||||||
|
|
||||||
logmsg += str(status) + logtail
|
logmsg += str(status) + logtail
|
||||||
|
|
|
@ -8,6 +8,7 @@ import struct
|
||||||
import hashlib
|
import hashlib
|
||||||
import platform
|
import platform
|
||||||
import threading
|
import threading
|
||||||
|
import mimetypes
|
||||||
import subprocess as sp # nosec
|
import subprocess as sp # nosec
|
||||||
|
|
||||||
from .__init__ import PY2, WINDOWS
|
from .__init__ import PY2, WINDOWS
|
||||||
|
@ -474,6 +475,13 @@ def unescape_cookie(orig):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def guess_mime(url):
|
||||||
|
if url.endswith(".md"):
|
||||||
|
return ["text/plain; charset=UTF-8"]
|
||||||
|
|
||||||
|
return mimetypes.guess_type(url)
|
||||||
|
|
||||||
|
|
||||||
def runcmd(*argv):
|
def runcmd(*argv):
|
||||||
p = sp.Popen(argv, stdout=sp.PIPE, stderr=sp.PIPE)
|
p = sp.Popen(argv, stdout=sp.PIPE, stderr=sp.PIPE)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = p.communicate()
|
||||||
|
|
|
@ -47,6 +47,9 @@ var dom_md = document.getElementById('mt');
|
||||||
gfm: true
|
gfm: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
shortcuts: {
|
||||||
|
"save": "Ctrl-S"
|
||||||
|
},
|
||||||
insertTexts: ["[](", ")"],
|
insertTexts: ["[](", ")"],
|
||||||
tabSize: 4,
|
tabSize: 4,
|
||||||
toolbar: tbar,
|
toolbar: tbar,
|
||||||
|
@ -85,10 +88,12 @@ function save(mde) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var txt = mde.value();
|
||||||
|
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append("act", "tput");
|
fd.append("act", "tput");
|
||||||
fd.append("lastmod", (force ? -1 : last_modified));
|
fd.append("lastmod", (force ? -1 : last_modified));
|
||||||
fd.append("body", mde.value());
|
fd.append("body", txt);
|
||||||
|
|
||||||
var url = (document.location + '').split('?')[0] + '?raw';
|
var url = (document.location + '').split('?')[0] + '?raw';
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
|
@ -97,6 +102,7 @@ function save(mde) {
|
||||||
xhr.onreadystatechange = save_cb;
|
xhr.onreadystatechange = save_cb;
|
||||||
xhr.btn = save_btn;
|
xhr.btn = save_btn;
|
||||||
xhr.mde = mde;
|
xhr.mde = mde;
|
||||||
|
xhr.txt = txt;
|
||||||
xhr.send(fd);
|
xhr.send(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +144,55 @@ function save_cb() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_modified = r.lastmod;
|
|
||||||
this.btn.classList.remove('force-save');
|
this.btn.classList.remove('force-save');
|
||||||
alert('save OK -- wrote ' + r.size + ' bytes.\n\nsha512: ' + r.sha512);
|
//alert('save OK -- wrote ' + r.size + ' bytes.\n\nsha512: ' + r.sha512);
|
||||||
md_changed(this.mde, true);
|
|
||||||
|
// download the saved doc from the server and compare
|
||||||
|
var url = (document.location + '').split('?')[0] + '?raw';
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.responseType = 'text';
|
||||||
|
xhr.onreadystatechange = save_chk;
|
||||||
|
xhr.btn = this.save_btn;
|
||||||
|
xhr.mde = this.mde;
|
||||||
|
xhr.txt = this.txt;
|
||||||
|
xhr.lastmod = r.lastmod;
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_chk() {
|
||||||
|
if (this.readyState != XMLHttpRequest.DONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.status !== 200) {
|
||||||
|
alert('Error! The file was NOT saved.\n\n' + this.status + ": " + (this.responseText + '').replace(/^<pre>/, ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var doc1 = this.txt.replace(/\r/g, "");
|
||||||
|
var doc2 = this.responseText.replace(/\r/g, "");
|
||||||
|
if (doc1 != doc2) {
|
||||||
|
alert(
|
||||||
|
'Error! The document on the server does not appear to have saved correctly (your editor contents and the server copy is not identical). Place the document on your clipboard for now and check the server logs for hints\n\n' +
|
||||||
|
'Length: yours=' + doc1.length + ', server=' + doc2.length
|
||||||
|
);
|
||||||
|
alert('yours, ' + doc1.length + ' byte:\n[' + doc1 + ']');
|
||||||
|
alert('server, ' + doc2.length + ' byte:\n[' + doc2 + ']');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_modified = this.lastmod;
|
||||||
|
md_changed(this.mde, true);
|
||||||
|
|
||||||
|
var ok = document.createElement('div');
|
||||||
|
ok.setAttribute('style', 'font-size:6em;font-family:serif;font-weight:bold;color:#cf6;background:#444;border-radius:.3em;padding:.6em 0;position:fixed;top:30%;left:calc(50% - 2em);width:4em;text-align:center;z-index:9001;transition:opacity 0.2s ease-in-out;opacity:1');
|
||||||
|
ok.innerHTML = 'OK✔️';
|
||||||
|
var parent = document.getElementById('m');
|
||||||
|
document.documentElement.appendChild(ok);
|
||||||
|
setTimeout(function () {
|
||||||
|
ok.style.opacity = 0;
|
||||||
|
}, 500);
|
||||||
|
setTimeout(function () {
|
||||||
|
ok.parentNode.removeChild(ok);
|
||||||
|
}, 750);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="op_new_md" class="opview opbox act">
|
<div id="op_new_md" class="opview opbox">
|
||||||
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="/{{ vdir }}">
|
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="/{{ vdir }}">
|
||||||
<input type="hidden" name="act" value="new_md" />
|
<input type="hidden" name="act" value="new_md" />
|
||||||
<input type="text" name="name" size="30">
|
<input type="text" name="name" size="30">
|
||||||
|
|
Loading…
Reference in a new issue