diff --git a/copyparty/__main__.py b/copyparty/__main__.py
index b1170478..80fe68a4 100644
--- a/copyparty/__main__.py
+++ b/copyparty/__main__.py
@@ -1817,6 +1817,7 @@ def add_db_metadata(ap):
def add_txt(ap):
ap2 = ap.add_argument_group("textfile options")
+ ap2.add_argument("--rw-edit", metavar="T,T", type=u, default="md", help="comma-sep. list of file-extensions to allow editing with permissions read+write; all others require read+write+delete (volflag=rw_edit)")
ap2.add_argument("--md-no-br", action="store_true", help="markdown: disable newline-is-newline; will only render a newline into the html given two trailing spaces or a double-newline (volflag=md_no_br)")
ap2.add_argument("--md-hist", metavar="TXT", type=u, default="s", help="where to store old version of markdown files; [\033[32ms\033[0m]=subfolder, [\033[32mv\033[0m]=volume-histpath, [\033[32mn\033[0m]=nope/disabled (volflag=md_hist)")
ap2.add_argument("--txt-eol", metavar="TYPE", type=u, default="", help="enable EOL conversion when writing documents; supported: CRLF, LF (volflag=txt_eol)")
diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py
index 48f161a3..924fed38 100644
--- a/copyparty/authsrv.py
+++ b/copyparty/authsrv.py
@@ -3177,6 +3177,7 @@ class AuthSrv(object):
"unlist": vf.get("unlist") or "",
"sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
+ "rw_edit": vf["rw_edit"],
}
if "ufavico_h" in vf:
vn.js_ls["ufavico"] = vf["ufavico_h"]
@@ -3202,6 +3203,7 @@ class AuthSrv(object):
"sb_md": vn.js_ls["sb_md"],
"sba_md": vf.get("md_sba") or "",
"sba_lg": vf.get("lg_sba") or "",
+ "rw_edit": vf["rw_edit"],
"txt_ext": self.args.textfiles.replace(",", " "),
"def_hcols": list(vf.get("mth") or []),
"unlist0": vf.get("unlist") or "",
diff --git a/copyparty/cfg.py b/copyparty/cfg.py
index 29c05990..b24947d0 100644
--- a/copyparty/cfg.py
+++ b/copyparty/cfg.py
@@ -139,6 +139,7 @@ def vf_vmap() -> dict[str, str]:
"rss_sort",
"rss_fmt_t",
"rss_fmt_d",
+ "rw_edit",
"shr_who",
"sort",
"tail_fd",
@@ -389,6 +390,7 @@ flagcats = {
"opds_exts": "file formats to list in OPDS feeds; leave empty to show everything",
},
"textfiles": {
+ "rw_edit=md,txt": "only require read+write to edit .md and .txt",
"md_no_br": "newline only on double-newline or two tailing spaces",
"md_hist": "where to put markdown backups; s=subfolder, v=volHist, n=nope",
"exp": "enable textfile expansion; see --help-exp",
diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py
index 3b1aaa74..2e29d015 100644
--- a/copyparty/httpcli.py
+++ b/copyparty/httpcli.py
@@ -3532,9 +3532,12 @@ class HttpCli(object):
vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True)
self._assert_safe_rem(rem)
- if not self.can_delete and not new_file.lower().endswith(".md"):
- t = "you can only create .md files because you don't have the delete-permission"
- raise Pebkac(400, t)
+ if not self.can_delete and (
+ "." not in new_file
+ or new_file.rsplit(".", 1)[1].lower() not in self.args.rw_edit_set
+ ):
+ t = "you can only create %s files because you don't have the delete-permission"
+ raise Pebkac(400, t % (self.args.rw_edit.replace(",", "/")))
sanitized = sanitize_fn(new_file)
fdir = vfs.canonical(rem)
@@ -4051,8 +4054,11 @@ class HttpCli(object):
rem = "{}/{}".format(rp, fn).strip("/")
dbv, vrem = vfs.get_dbv(rem)
- if not rem.lower().endswith(".md") and not self.can_delete:
- raise Pebkac(400, "only markdown pls")
+ if not self.can_delete and (
+ "." not in rem or rem.rsplit(".", 1)[1].lower() not in self.args.rw_edit_set
+ ):
+ t = "you can only edit %s files because you don't have the delete-permission"
+ raise Pebkac(400, t % (self.args.rw_edit.replace(",", "/")))
if nullwrite:
response = json.dumps({"ok": True, "lastmod": 0})
diff --git a/copyparty/svchub.py b/copyparty/svchub.py
index e872b595..fdef83c4 100644
--- a/copyparty/svchub.py
+++ b/copyparty/svchub.py
@@ -1116,7 +1116,7 @@ class SvcHub(object):
vs = os.path.expandvars(os.path.expanduser(vs))
setattr(al, k, vs)
- for k in "idp_adm stats_u".split(" "):
+ for k in "idp_adm rw_edit stats_u".split(" "):
vs = getattr(al, k)
vsa = [x.strip() for x in vs.split(",")]
vsa = [x.lower() for x in vsa if x]
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index eae68df2..15d75169 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -2,7 +2,8 @@
var J_BRW = 1;
-if (!window.drcm) alert('FATAL ERROR: receiving stale data from the server; this may be due to a broken reverse-proxy (stuck cache). Try restarting copyparty and press CTRL-SHIFT-R in the browser');
+if (window.rw_edit === undefined)
+ alert('FATAL ERROR: receiving stale data from the server; this may be due to a broken reverse-proxy (stuck cache). Try restarting copyparty and press CTRL-SHIFT-R in the browser');
var XHR = XMLHttpRequest,
img_re = /\.(a?png|avif|bmp|gif|heif|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov)(\?|$)/i;
@@ -462,7 +463,7 @@ if (1)
"mk_noname": "type a name into the text field on the left before you do that :p",
"nmd_i1": "also add the file extension you want, for example .md",
- "nmd_i2": "you can only create .md files because you don't have the delete-permission",
+ "nmd_i2": "you can only create .{0} files because you don't have the delete-permission",
"tv_load": "Loading text document:\n\n{0}\n\n{1}% ({2} of {3} MiB loaded)",
"tv_xe1": "could not load textfile:\n\nerror ",
@@ -7589,7 +7590,7 @@ var treectl = (function () {
reload_tree();
reload_browser();
tree_scrollto();
- if (res.acct) {
+ if (res.cfg) {
acct = res.acct;
have_up2k_idx = res.idx;
have_tags_idx = res.itag;
@@ -7978,7 +7979,10 @@ function apply_perms(res) {
if (up2k)
up2k.set_fsearch();
- ebi('new_mdi').innerHTML = has(perms, "delete") ? L.nmd_i1 : L.nmd_i2;
+ if (res.cfg)
+ rw_edit = res.rw_edit;
+ window.re_rw_edit = new RegExp('\.(' + rw_edit.replace(/,/g, '|') + ')$', 'i');
+ ebi('new_mdi').innerHTML = has(perms, "delete") ? L.nmd_i1 : L.nmd_i2.format(rw_edit.replace(/,/g, '/'));
widget.setvis();
thegrid.setvis();
@@ -8784,7 +8788,7 @@ var msel = (function () {
tb = QS('#op_new_md input[name="name"]');
form.onsubmit = function (e) {
- if (!has(perms, "delete") && !/\.md$/.test(tb.value)) {
+ if (!has(perms, "delete") && !re_rw_edit.test(tb.value)) {
ev(e);
toast.err(10, L.nmd_i2);
return false;
diff --git a/copyparty/web/tl/chi.js b/copyparty/web/tl/chi.js
index 3992ddef..1734af92 100644
--- a/copyparty/web/tl/chi.js
+++ b/copyparty/web/tl/chi.js
@@ -448,7 +448,7 @@ Ls.chi = {
"mk_noname": "在左侧文本框中输入名称,然后再执行此操作 :p",
"nmd_i1": "还可以添加需要的文件扩展名,例如 .md", //m
- "nmd_i2": "由于没有删除权限,你只能创建 .md 文件", //m
+ "nmd_i2": "由于没有删除权限,你只能创建 .{0} 文件", //m
"tv_load": "加载文本文件:\n\n{0}\n\n{1}% ({2} 的 {3} MiB 已加载)",
"tv_xe1": "无法加载文本文件:\n\n错误 ",
diff --git a/copyparty/web/tl/cze.js b/copyparty/web/tl/cze.js
index a1c8c088..af2cf42b 100644
--- a/copyparty/web/tl/cze.js
+++ b/copyparty/web/tl/cze.js
@@ -452,7 +452,7 @@ Ls.cze = {
"mk_noname": "napište název do textového pole vlevo předtím než to uděláte :p",
"nmd_i1": "můžeš také přidat příponu souboru, například .md", //m
- "nmd_i2": "můžeš vytvářet pouze .md soubory, protože nemáš oprávnění mazat", //m
+ "nmd_i2": "můžeš vytvářet pouze .{0} soubory, protože nemáš oprávnění mazat", //m
"tv_load": "Načítání textového dokumentu:\n\n{0}\n\n{1}% ({2} z {3} MiB načteno)",
"tv_xe1": "nelze načíst textový soubor:\n\nchyba ",
diff --git a/copyparty/web/tl/deu.js b/copyparty/web/tl/deu.js
index c9e35b3e..6a9bc3df 100644
--- a/copyparty/web/tl/deu.js
+++ b/copyparty/web/tl/deu.js
@@ -448,7 +448,7 @@ Ls.deu = {
"mk_noname": "Tipp' mal vorher lieber einen Namen in das Textfeld links, bevor du das machst :p",
"nmd_i1": "Füge auch die Dateiendung hinzu, z.B. .md",
- "nmd_i2": "Du kannst nur .md-Dateien erstellen, da dir Lösch-Rechte fehlen",
+ "nmd_i2": "Du kannst nur .{0}-Dateien erstellen, da dir Lösch-Rechte fehlen",
"tv_load": "Textdatei wird geladen:\n\n{0}\n\n{1}% ({2} von {3} MiB geladen)",
"tv_xe1": "Konnte Textdatei nicht laden:\n\nFehler ",
diff --git a/copyparty/web/tl/epo.js b/copyparty/web/tl/epo.js
index c55ba251..0d3a967e 100644
--- a/copyparty/web/tl/epo.js
+++ b/copyparty/web/tl/epo.js
@@ -448,7 +448,7 @@ Ls.epo = {
"mk_noname": "tajpu nomon en tekstokampo maldekstre antaŭ vi faras ĉi tion :p",
"nmd_i1": "vi povas aldoni la deziratan sufikson, ekzemple .md", //m
- "nmd_i2": "vi povas krei nur .md-dosierojn ĉar vi ne havas forigan permeson", //m
+ "nmd_i2": "vi povas krei nur .{0}-dosierojn ĉar vi ne havas forigan permeson", //m
"tv_load": "Ŝargado de teksto-dokumento:\n\n{0}\n\n{1}% ({2} da {3} MiB ŝargita)",
"tv_xe1": "ne povas ŝargi teksto-dosieron:\n\neraro ",
diff --git a/copyparty/web/tl/fin.js b/copyparty/web/tl/fin.js
index 4ca9ed41..cb751e88 100644
--- a/copyparty/web/tl/fin.js
+++ b/copyparty/web/tl/fin.js
@@ -448,7 +448,7 @@ Ls.fin = {
"mk_noname": "kirjoita nimi vasemmalla olevaan tekstikenttään ennen kuin teet tuon :p",
"nmd_i1": "voit myös lisätä haluamasi tiedostopäätteen, esimerkiksi .md", //m
- "nmd_i2": "voit luoda vain .md-tiedostoja, koska sinulla ei ole poistolupaa", //m
+ "nmd_i2": "voit luoda vain .{0}-tiedostoja, koska sinulla ei ole poistolupaa", //m
"tv_load": "Ladataan tekstidokumenttia:\n\n{0}\n\n{1}% ({2} / {3} Mt ladattu)",
"tv_xe1": "tekstitiedoston lataaminen epäonnistui:\n\nvirhe ",
diff --git a/copyparty/web/tl/fra.js b/copyparty/web/tl/fra.js
index aeb5b09a..25e4cced 100644
--- a/copyparty/web/tl/fra.js
+++ b/copyparty/web/tl/fra.js
@@ -448,7 +448,7 @@ Ls.fra = {
"mk_noname": "entrez un nom dans le champ de texte à gauche avant de faire ça :p",
"nmd_i1": "ajoutez aussi l’extension souhaitée, par exemple .md", //m
- "nmd_i2": "vous ne pouvez créer que des fichiers .md car vous n’avez pas la permission d’effacer", //m
+ "nmd_i2": "vous ne pouvez créer que des fichiers .{0} car vous n’avez pas la permission d’effacer", //m
"tv_load": "Chargement du document texte:\n\n{0}\n\n{1}% ({2} de {3} MiB chargés)",
"tv_xe1": "impossible de charger le fichier texte:\n\nerreur",
diff --git a/copyparty/web/tl/grc.js b/copyparty/web/tl/grc.js
index e2308479..16fd8cce 100644
--- a/copyparty/web/tl/grc.js
+++ b/copyparty/web/tl/grc.js
@@ -448,7 +448,7 @@ Ls.grc = {
"mk_noname": "γράψε ένα όνομα στο πεδίο κειμένου αριστερά πριν το κάνεις :p",
"nmd_i1": "μπορείτε επίσης να προσθέσετε την κατάληξη που θέλετε, όπως .md", //m
- "nmd_i2": "μπορείτε να δημιουργήσετε μόνο αρχεία .md επειδή δεν έχετε δικαίωμα διαγραφής", //m
+ "nmd_i2": "μπορείτε να δημιουργήσετε μόνο αρχεία .{0} επειδή δεν έχετε δικαίωμα διαγραφής", //m
"tv_load": "Φόρτωση αρχείου κειμένου:\n\n{0}\n\n{1}% ({2} από {3} MiB φορτωμένα)",
"tv_xe1": "αδυναμία φόρτωσης αρχείου κειμένου:\n\nσφάλμα ",
diff --git a/copyparty/web/tl/ita.js b/copyparty/web/tl/ita.js
index b4b108b5..406db05a 100644
--- a/copyparty/web/tl/ita.js
+++ b/copyparty/web/tl/ita.js
@@ -448,7 +448,7 @@ Ls.ita = {
"mk_noname": "scrivi un nome nel campo di testo a sinistra prima di farlo :p",
"nmd_i1": "puoi anche aggiungere l’estensione che vuoi, per esempio .md", //m
- "nmd_i2": "puoi creare solo file .md perché non hai il permesso di eliminare", //m
+ "nmd_i2": "puoi creare solo file .{0} perché non hai il permesso di eliminare", //m
"tv_load": "Caricando documento di testo:\n\n{0}\n\n{1}% ({2} di {3} MiB caricati)",
"tv_xe1": "impossibile caricare file di testo:\n\nerrore ",
diff --git a/copyparty/web/tl/jpn.js b/copyparty/web/tl/jpn.js
index 807cd861..338b4a90 100644
--- a/copyparty/web/tl/jpn.js
+++ b/copyparty/web/tl/jpn.js
@@ -448,7 +448,7 @@ Ls.jpn = {
"mk_noname": "それをする前に左側のテキストフィールドに名前を入力してください :p",
"nmd_i1": "必要なファイル拡張子も追加します。例: .md",
- "nmd_i2": "削除権限がないため、.md ファイルのみを作成できます",
+ "nmd_i2": "削除権限がないため、.{0} ファイルのみを作成できます",
"tv_load": "テキストドキュメントの読み込み中:\n\n{0}\n\n{1}%({2} / {3} MiB ロード済み)",
"tv_xe1": "テキストファイルを読み込めませんでした:\n\nエラー ",
diff --git a/copyparty/web/tl/kor.js b/copyparty/web/tl/kor.js
index 3f71eb19..d2c7618e 100644
--- a/copyparty/web/tl/kor.js
+++ b/copyparty/web/tl/kor.js
@@ -448,7 +448,7 @@ Ls.kor = {
"mk_noname": "왼쪽 텍스트 필드에 이름을 먼저 입력해주세요 :p",
"nmd_i1": "원하는 파일 확장자를 추가할 수 있습니다. 예: .md", //m
- "nmd_i2": "삭제 권한이 없어서 .md 파일만 만들 수 있습니다", //m
+ "nmd_i2": "삭제 권한이 없어서 .{0} 파일만 만들 수 있습니다", //m
"tv_load": "텍스트 문서 불러오는 중:\n\n{0}\n\n{1}% ({3} MiB 중 {2} MiB 로드됨)",
"tv_xe1": "텍스트 파일을 불러올 수 없습니다:\n\n오류 ",
diff --git a/copyparty/web/tl/nld.js b/copyparty/web/tl/nld.js
index a5b38095..3c129df7 100644
--- a/copyparty/web/tl/nld.js
+++ b/copyparty/web/tl/nld.js
@@ -448,7 +448,7 @@ Ls.nld = {
"mk_noname": "Voer een naam in het tekstveld aan de linkerkant voordat je verder gaat :p",
"nmd_i1": "Voeg ook de gewenste extensie toe, bijvoorbeeld .md", //m
- "nmd_i2": "Je kunt alleen .md-bestanden maken omdat je geen verwijderrechten hebt", //m
+ "nmd_i2": "Je kunt alleen .{0}-bestanden maken omdat je geen verwijderrechten hebt", //m
"tv_load": "Tekstdocument laden:\n\n{0}\n\n{1}% ({2} van de {3} MiB geladen)",
"tv_xe1": "Kon tekstbestand niet laden:\n\nfout ",
diff --git a/copyparty/web/tl/nno.js b/copyparty/web/tl/nno.js
index 45b3afd2..bc2a3b60 100644
--- a/copyparty/web/tl/nno.js
+++ b/copyparty/web/tl/nno.js
@@ -445,7 +445,7 @@ Ls.nno = {
"mk_noname": "skriv inn eit namn i tekstboksa åt venstre først :p",
"nmd_i1": "leggja også til filendinga du vil, til dømes .md", //m
- "nmd_i2": "du kan berre laga .md-filer fordi du ikkje har delete-tilgang", //m
+ "nmd_i2": "du kan berre laga .{0}-filer fordi du ikkje har delete-tilgang", //m
"tv_load": "Lastar inn tekstfil:\n\n{0}\n\n{1}% ({2} av {3} MiB lasta ned)",
"tv_xe1": "kunne ikkje laste tekstfil:\n\nfeil ",
diff --git a/copyparty/web/tl/nor.js b/copyparty/web/tl/nor.js
index 0f75ddc7..68588fe4 100644
--- a/copyparty/web/tl/nor.js
+++ b/copyparty/web/tl/nor.js
@@ -445,7 +445,7 @@ Ls.nor = {
"mk_noname": "skriv inn et navn i tekstboksen til venstre først :p",
"nmd_i1": "legg også til ønsket filtype, for eksempel .md", //m
- "nmd_i2": "du kan bare lage .md-filer fordi du ikke har delete-tilgang", //m
+ "nmd_i2": "du kan bare lage .{0}-filer fordi du ikke har delete-tilgang", //m
"tv_load": "Laster inn tekstfil:\n\n{0}\n\n{1}% ({2} av {3} MiB lastet ned)",
"tv_xe1": "kunne ikke laste tekstfil:\n\nfeil ",
diff --git a/copyparty/web/tl/pol.js b/copyparty/web/tl/pol.js
index 76046af6..de8ea71b 100644
--- a/copyparty/web/tl/pol.js
+++ b/copyparty/web/tl/pol.js
@@ -451,7 +451,7 @@ Ls.pol = {
"mk_noname": "wpisz nazwę do pola po lewej zanim to zrobisz :p",
"nmd_i1": "możesz też dodać wybrane rozszerzenie, np. .md", //m
- "nmd_i2": "możesz tworzyć tylko pliki .md, ponieważ nie masz uprawnień do usuwania", //m
+ "nmd_i2": "możesz tworzyć tylko pliki .{0}, ponieważ nie masz uprawnień do usuwania", //m
"tv_load": "Wczytywanie pliku tekstowego:\n\n{0}\n\n{1}% (wczytano {2} z {3} MiB)",
"tv_xe1": "nie udało się wczytać pliku:\n\nbłąd ",
diff --git a/copyparty/web/tl/por.js b/copyparty/web/tl/por.js
index 6fd11845..19bae4d6 100644
--- a/copyparty/web/tl/por.js
+++ b/copyparty/web/tl/por.js
@@ -448,7 +448,7 @@ Ls.por = {
"mk_noname": "digite um nome no campo de texto à esquerda antes de fazer isso :p",
"nmd_i1": "também adicione a extensão desejada, por exemplo .md",
- "nmd_i2": "só pode criar arquivos .md porque não tem permissão para apagar",
+ "nmd_i2": "só pode criar arquivos .{0} porque não tem permissão para apagar",
"tv_load": "Carregando documento de texto:\n\n{0}\n\n{1}% ({2} de {3} MiB carregados)",
"tv_xe1": "não foi possível carregar o arquivo de texto:\n\nerro ",
diff --git a/copyparty/web/tl/rus.js b/copyparty/web/tl/rus.js
index 4c48ae1a..6c4db859 100644
--- a/copyparty/web/tl/rus.js
+++ b/copyparty/web/tl/rus.js
@@ -448,7 +448,7 @@ Ls.rus = {
"mk_noname": "введите имя в текстовое поле слева перед тем, как это делать :p",
"nmd_i1": "вы также можете указать нужное расширение, например .md", //m
- "nmd_i2": "вы можете создавать только файлы .md, так как у вас нет разрешения на удаление", //m
+ "nmd_i2": "вы можете создавать только файлы .{0}, так как у вас нет разрешения на удаление", //m
"tv_load": "Загружаю текстовый документ:\n\n{0}\n\n{1}% ({2} из {3} МиБ загружено)",
"tv_xe1": "не удалось загрузить текстовый файл:\n\nошибка ",
diff --git a/copyparty/web/tl/spa.js b/copyparty/web/tl/spa.js
index 508a639f..3aca36b5 100644
--- a/copyparty/web/tl/spa.js
+++ b/copyparty/web/tl/spa.js
@@ -447,7 +447,7 @@ Ls.spa = {
"mk_noname": "escribe un nombre en el campo de texto de la izquierda antes de hacer eso :p",
"nmd_i1": "también puedes añadir la extensión que quieras, por ejemplo .md", //m
- "nmd_i2": "solo puedes crear archivos .md porque no tienes permiso para borrar", //m
+ "nmd_i2": "solo puedes crear archivos .{0} porque no tienes permiso para borrar", //m
"tv_load": "Cargando documento de texto:\n\n{0}\n\n{1}% ({2} de {3} MiB cargados)",
"tv_xe1": "no se pudo cargar el archivo de texto:\n\nerror ",
diff --git a/copyparty/web/tl/swe.js b/copyparty/web/tl/swe.js
index 6f5e9b0b..30f662a0 100644
--- a/copyparty/web/tl/swe.js
+++ b/copyparty/web/tl/swe.js
@@ -448,7 +448,7 @@ Ls.swe = {
"mk_noname": "skriv ett namn i fältet till vänster först :p",
"nmd_i1": "lägg också till filändelsen du vill ha, till exempel .md", //m
- "nmd_i2": "du kan bara skapa .md-filer eftersom du inte har borttagningsbehörighet", //m
+ "nmd_i2": "du kan bara skapa .{0}-filer eftersom du inte har borttagningsbehörighet", //m
"tv_load": "Laddar textfil:\n\n{0}\n\n{1}% ({2} av {3} MiB laddat)",
"tv_xe1": "kunde ej ladda textfil:\n\nfel ",
diff --git a/copyparty/web/tl/tur.js b/copyparty/web/tl/tur.js
index 0efaa2d5..172ebc6d 100644
--- a/copyparty/web/tl/tur.js
+++ b/copyparty/web/tl/tur.js
@@ -448,7 +448,7 @@ Ls.tur = {
"mk_noname": "bunu yapmadan önce soldaki boşluğa bir şeyler yazsana :p",
"nmd_i1": "ayrıca istediğin dosya uzantısını ekleyebilirsin, örneğin .md", //m
- "nmd_i2": "silme iznin olmadığı için yalnızca .md dosyaları oluşturabilirsin", //m
+ "nmd_i2": "silme iznin olmadığı için yalnızca .{0} dosyaları oluşturabilirsin", //m
"tv_load": "Metin belgesi yükleniyor:\n\n{0}\n\n{1}% ({2} of {3} MiB yüklendi)",
"tv_xe1": "metin dosyası yüklenemedi:\n\nhata ",
diff --git a/copyparty/web/tl/ukr.js b/copyparty/web/tl/ukr.js
index 2265c2ec..93d4069b 100644
--- a/copyparty/web/tl/ukr.js
+++ b/copyparty/web/tl/ukr.js
@@ -448,7 +448,7 @@ Ls.ukr = {
"mk_noname": "введіть ім'я в текстове поле зліва перед тим, як робити це :p",
"nmd_i1": "ви також можете додати потрібне розширення, наприклад .md", //m
- "nmd_i2": "ви можете створювати тільки файли .md, оскільки не маєте дозволу на видалення", //m
+ "nmd_i2": "ви можете створювати тільки файли .{0}, оскільки не маєте дозволу на видалення", //m
"tv_load": "Завантаження текстового документа:\n\n{0}\n\n{1}% ({2} з {3} MiB завантажено)",
"tv_xe1": "не вдалося завантажити текстовий файл:\n\nпомилка ",
diff --git a/copyparty/web/tl/vie.js b/copyparty/web/tl/vie.js
index 4805c0ef..f2baa92e 100644
--- a/copyparty/web/tl/vie.js
+++ b/copyparty/web/tl/vie.js
@@ -457,7 +457,7 @@ Ls.vie = {
"mk_noname": "hãy nhập tên vào ô bên trái trước khi thực hiện :p",
"nmd_i1": "hãy thêm cả phần mở rộng tệp bạn muốn, ví dụ .md",
- "nmd_i2": "bạn chỉ có thể tạo tệp .md vì bạn không có quyền xóa",
+ "nmd_i2": "bạn chỉ có thể tạo tệp .{0} vì bạn không có quyền xóa",
"tv_load": "Đang tải tài liệu văn bản:\n\n{0}\n\n{1}% ({2} / {3} MiB)",
"tv_xe1": "không thể tải tệp văn bản:\n\nlỗi ",
diff --git a/tests/util.py b/tests/util.py
index bab194d3..4346eae9 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -212,6 +212,7 @@ class Cfg(Namespace):
rm_retry="0/0",
rotf_tz="UTC",
rss_sort="m",
+ rw_edit="md",
s_rd_sz=256 * 1024,
s_wr_sz=256 * 1024,
shr_who="auth",