ticket #57 attempt 1
This commit is contained in:
parent
43c5a948e8
commit
3e12f9b27f
1
.dpc/verify_cache.json
Normal file
1
.dpc/verify_cache.json
Normal file
File diff suppressed because one or more lines are too long
@ -8,6 +8,11 @@ export class CommentManager {
|
|||||||
this.initCommentReply();
|
this.initCommentReply();
|
||||||
this.initCommentEdit();
|
this.initCommentEdit();
|
||||||
this.initCommentDelete();
|
this.initCommentDelete();
|
||||||
|
document.addEventListener("paste", (event) => {
|
||||||
|
const textarea = event.target.closest("form textarea[name='body'], form textarea[name='content']");
|
||||||
|
if (!textarea) return;
|
||||||
|
this._onPaste(event, textarea);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initCommentDelete() {
|
initCommentDelete() {
|
||||||
@ -208,4 +213,41 @@ export class CommentManager {
|
|||||||
if (btn) btn.disabled = true;
|
if (btn) btn.disabled = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onPaste(event, textarea) {
|
||||||
|
const items = event.clipboardData?.items;
|
||||||
|
if (!items) return;
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.kind === "file" && item.type.startsWith("image/")) {
|
||||||
|
event.preventDefault();
|
||||||
|
const file = item.getAsFile();
|
||||||
|
const namedFile = new File([file], file.name || "clipboard.png", { type: file.type });
|
||||||
|
this._uploadImage(namedFile, textarea);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _uploadImage(file, textarea) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file, file.name);
|
||||||
|
try {
|
||||||
|
const response = await fetch("/uploads/upload", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"X-Requested-With": "fetch",
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json().catch(() => ({}));
|
||||||
|
throw new Error(data.error || `Upload failed (${response.status})`);
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
window.TextInput.insertAtCursor(textarea, ``);
|
||||||
|
} catch (err) {
|
||||||
|
Http.notifyError(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,48 @@ export class IssueReporter {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.submit(form);
|
this.submit(form);
|
||||||
});
|
});
|
||||||
|
document.addEventListener("paste", (event) => {
|
||||||
|
const textarea = event.target.closest("form[data-issue-create] [name='description']");
|
||||||
|
if (!textarea) return;
|
||||||
|
this._onPaste(event, textarea);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPaste(event, textarea) {
|
||||||
|
const items = event.clipboardData?.items;
|
||||||
|
if (!items) return;
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.kind === "file" && item.type.startsWith("image/")) {
|
||||||
|
event.preventDefault();
|
||||||
|
const file = item.getAsFile();
|
||||||
|
const namedFile = new File([file], file.name || "clipboard.png", { type: file.type });
|
||||||
|
this._uploadImage(namedFile, textarea);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _uploadImage(file, textarea) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file, file.name);
|
||||||
|
try {
|
||||||
|
const response = await fetch("/uploads/upload", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"X-Requested-With": "fetch",
|
||||||
|
},
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const data = await response.json().catch(() => ({}));
|
||||||
|
throw new Error(data.error || `Upload failed (${response.status})`);
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
window.TextInput.insertAtCursor(textarea, ``);
|
||||||
|
} catch (err) {
|
||||||
|
Http.notifyError(err.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit(form) {
|
async submit(form) {
|
||||||
|
|||||||
@ -240,3 +240,17 @@ def test_delete_own_allowed_other_user_forbidden(app_server):
|
|||||||
bob = _session_uploads()
|
bob = _session_uploads()
|
||||||
assert bob.delete(f"{BASE_URL}/uploads/delete/{uid}").status_code == 403
|
assert bob.delete(f"{BASE_URL}/uploads/delete/{uid}").status_code == 403
|
||||||
assert alice.delete(f"{BASE_URL}/uploads/delete/{uid}").status_code == 200
|
assert alice.delete(f"{BASE_URL}/uploads/delete/{uid}").status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_paste_image_upload_returns_url(app_server):
|
||||||
|
s = _session_uploads()
|
||||||
|
r = s.post(
|
||||||
|
f"{BASE_URL}/uploads/upload",
|
||||||
|
files={"file": ("clipboard.png", _png_bytes_uploads(), "image/png")},
|
||||||
|
)
|
||||||
|
assert r.status_code == 201, r.text
|
||||||
|
data = r.json()
|
||||||
|
assert "url" in data
|
||||||
|
assert data["url"].startswith("/static/uploads/attachments/")
|
||||||
|
assert data["uid"]
|
||||||
|
assert data["is_image"] is True
|
||||||
|
|||||||
1
venv/bin/python
Symbolic link
1
venv/bin/python
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
python3
|
||||||
1
venv/bin/python3
Symbolic link
1
venv/bin/python3
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/usr/bin/python3
|
||||||
1
venv/bin/python3.11
Symbolic link
1
venv/bin/python3.11
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
python3
|
||||||
1
venv/lib64
Symbolic link
1
venv/lib64
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
lib
|
||||||
5
venv/pyvenv.cfg
Normal file
5
venv/pyvenv.cfg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
home = /usr/bin
|
||||||
|
include-system-site-packages = false
|
||||||
|
version = 3.11.2
|
||||||
|
executable = /usr/bin/python3.11
|
||||||
|
command = /usr/bin/python3 -m venv /workspace/repo/venv
|
||||||
Loading…
Reference in New Issue
Block a user