feat: Unarchive destination select (#26)

* feat: Unarchive destination select

* fix: Check file conflict on unarchive
pull/3756/head
Laurynas Gadliauskas 2021-10-28 13:05:58 +03:00 committed by GitHub
parent aa8ca032f5
commit 1879a62423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 128 additions and 59 deletions

View File

@ -180,7 +180,7 @@ export async function archive(url, name, format, ...files) {
}
export async function unarchive(path, name, override) {
const to = encodeURIComponent(removePrefix(name));
const to = removePrefix(name);
const action = `unarchive`;
const url = `${path}?action=${action}&destination=${to}&override=${override}`;
return resourceAction(url, "PATCH");

View File

@ -5,14 +5,21 @@
</div>
<div class="card-content">
<p>{{ $t("prompts.unarchiveMessage") }}</p>
<input
class="input input--block"
v-focus
type="text"
@keyup.enter="submit"
v-model.trim="name"
/>
<form ref="unarchiveForm">
<p>{{ $t("prompts.unarchiveFolderNameMessage") }}</p>
<input
class="input input--block"
v-focus
type="text"
@keyup.enter="submit"
v-model.trim="name"
required
/>
</form>
<p>{{ $t("prompts.unarchiveDestinationLocationMessage") }}</p>
<file-list @update:selected="(val) => (dest = val)"></file-list>
<p v-if="overwriteAvailable">
<input type="checkbox" v-model="overwriteExisting" />
{{ $t("prompts.unarchiveOverwriteExisting") }}
@ -43,14 +50,17 @@
<script>
import { mapState, mapGetters } from "vuex";
import FileList from "./FileList";
import { files as api } from "@/api";
import buttons from "@/utils/buttons";
export default {
name: "rename",
components: { FileList },
data: function () {
return {
overwriteExisting: false,
dest: null,
name: "",
};
},
@ -76,10 +86,12 @@ export default {
this.$store.commit("closeHovers");
},
submit: async function () {
if (!this.$refs.unarchiveForm.reportValidity()) {
return;
}
let item = this.req.items[this.selected[0]];
let uri = this.isFiles ? this.$route.path + "/" : "/";
let dst = uri + this.name;
dst = dst.replace("//", "/");
let dst = this.dest + encodeURIComponent(this.name);
try {
buttons.loading("unarchive");

View File

@ -170,6 +170,8 @@
"size": "الحجم",
"skipTrashMessage": "تخطى سلة المهملات واحذف فورا",
"unarchive": "حذف من الأرشيف",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "اختر اسم المجلد الوجهة:",
"unarchiveOverwriteExisting": "الكتابة فوق الملفات الموجودة",
"unsavedChanges": "قد لا يتم حفظ التغييرات التي قمت بها. هل تريد مغادرة الصفحة؟",

View File

@ -170,6 +170,8 @@
"size": "Size",
"skipTrashMessage": "Skip trash bin and delete immediately",
"unarchive": "Unarchive",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Choose the destination folder name:",
"unarchiveOverwriteExisting": "Overwrite existing files",
"unsavedChanges": "Changes that you made may not be saved. Leave page?",

View File

@ -170,6 +170,8 @@
"size": "Tamaño",
"skipTrashMessage": "Omitir papelera y eliminar inmediatamente",
"unarchive": "Desarchiva",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Elige el nombre de la carpeta de destino:",
"unarchiveOverwriteExisting": "Sobrescribir archivos existentes",
"unsavedChanges": "Los cambios que realizaste podrían no guardarse. ¿Abandonar página?",
@ -282,7 +284,7 @@
"settings": "Ajustes",
"signup": "Registrate",
"siteSettings": "Ajustes del sitio",
"tmpDir": "Temporary folder",
"tmpDir": "Carpeta temporal",
"trashBin": "Papelera"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Tamaño",
"skipTrashMessage": "Omitir papelera y eliminar inmediatamente",
"unarchive": "Desarchiva",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Elige el nombre de la carpeta de destino:",
"unarchiveOverwriteExisting": "Sobrescribir archivos existentes",
"unsavedChanges": "Los cambios que realizaste podrían no guardarse. ¿Abandonar página?",
@ -282,7 +284,7 @@
"settings": "Ajustes",
"signup": "Registrate",
"siteSettings": "Ajustes del sitio",
"tmpDir": "Temporary folder",
"tmpDir": "Carpeta temporal",
"trashBin": "Papelera"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Tamaño",
"skipTrashMessage": "Omitir papelera y eliminar inmediatamente",
"unarchive": "Desarchiva",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Elige el nombre de la carpeta de destino:",
"unarchiveOverwriteExisting": "Sobrescribir archivos existentes",
"unsavedChanges": "Los cambios que realizaste podrían no guardarse. ¿Abandonar página?",
@ -282,7 +284,7 @@
"settings": "Ajustes",
"signup": "Registrate",
"siteSettings": "Ajustes del sitio",
"tmpDir": "Temporary folder",
"tmpDir": "Carpeta temporal",
"trashBin": "Papelera"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Tamaño",
"skipTrashMessage": "Omitir papelera y eliminar inmediatamente",
"unarchive": "Desarchiva",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Elige el nombre de la carpeta de destino:",
"unarchiveOverwriteExisting": "Sobrescribir archivos existentes",
"unsavedChanges": "Los cambios que realizaste podrían no guardarse. ¿Abandonar página?",
@ -282,7 +284,7 @@
"settings": "Ajustes",
"signup": "Registrate",
"siteSettings": "Ajustes del sitio",
"tmpDir": "Temporary folder",
"tmpDir": "Carpeta temporal",
"trashBin": "Papelera"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Taille",
"skipTrashMessage": "Ignorer la corbeille et supprimer immédiatement",
"unarchive": "Extraire",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Choisissez le nom du dossier de destination :",
"unarchiveOverwriteExisting": "Écraser les fichiers existants",
"unsavedChanges": "Les modifications que vous avez apportées peuvent ne pas être enregistrées. Quitter la page ?",

View File

@ -170,6 +170,8 @@
"size": "Ukuran",
"skipTrashMessage": "Lewati keranjang sampah dan langsung hapus saja",
"unarchive": "Buka arsip",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Pilih nama folder tujuan:",
"unarchiveOverwriteExisting": "Timpa file yang sudah ada",
"unsavedChanges": "Perubahan yang Anda buat mungkin tidak tersimpan. Tinggalkan halaman?",

View File

@ -10,8 +10,8 @@
"delete": "Ištrinti",
"directorySizes": "Skaičiuoti katalogų dydžius",
"download": "Atsisiųsti",
"file": "File",
"folder": "Folder",
"file": "Failas",
"folder": "Aplankas",
"hideDotfiles": "Paslėpti konfigūracijos failus",
"info": "Informacija",
"more": "Daugiau",
@ -170,6 +170,8 @@
"size": "Dydis",
"skipTrashMessage": "Ištrinti visam laikui",
"unarchive": "Išarchyvuoti",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Pasirinkite aplanko pavadinimą:",
"unarchiveOverwriteExisting": "Perrašyti esamus failus",
"unsavedChanges": "Atlikti pakeitimai gali būti neišsaugoti. Norite išeiti iš puslapio?",
@ -244,7 +246,7 @@
"rules": "Taisyklės",
"rulesHelp": "Čia galite apibrėžti konkrečiam naudotojui taikomų leidimų ir draudimų taisyklių rinkinį. Užblokuoti failai nebus rodomi sąrašuose ir nebus prieinami naudotojui.",
"scope": "Apimtis",
"setDateFormat": "Set exact date format",
"setDateFormat": "Nustatyti datos formatą",
"settingsUpdated": "Nustaytmai atnaujinti!",
"shareDeleted": "Dalijimasis nutrauktas!",
"shareDuration": "Dalijimosi trukmė",
@ -282,7 +284,7 @@
"settings": "Nustatymai",
"signup": "Užsiregistruoti",
"siteSettings": "Svetainės nustatymai",
"tmpDir": "Temporary folder",
"tmpDir": "Laikinas aplankas",
"trashBin": "Šiukšlių dėžė"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Tamanho",
"skipTrashMessage": "Pular lixeira e deletar imediatamente",
"unarchive": "Desarquivar",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Escolha o nome da pasta de destino:",
"unarchiveOverwriteExisting": "Sobrescrever arquivos existentes",
"unsavedChanges": "As alterações que você fez podem não ser salvas. Sair da página?",

View File

@ -170,6 +170,8 @@
"size": "Tamanho",
"skipTrashMessage": "Saltar o caixote do lixo e apagar imediatamente",
"unarchive": "Desarquivar",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Escolha o nome da pasta de destino:",
"unarchiveOverwriteExisting": "Sobrepor os ficheiros existentes",
"unsavedChanges": "As alterações que fez poderão não ser guardadas. Deixar a página?",
@ -282,7 +284,7 @@
"settings": "Configurações",
"signup": "Registar",
"siteSettings": "Configurações do site",
"tmpDir": "Temporary folder",
"tmpDir": "Pasta temporária",
"trashBin": "Caixote do lixo"
},
"success": {

View File

@ -170,6 +170,8 @@
"size": "Размер",
"skipTrashMessage": "Удалить, не сохраняя в корзину",
"unarchive": "Разархивирование",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Выберите имя папки назначения:",
"unarchiveOverwriteExisting": "Перезаписать существующие файлы",
"unsavedChanges": "Невозможно сохранить внесённые изменения. Покинуть страницу?",

View File

@ -170,6 +170,8 @@
"size": "Boyut",
"skipTrashMessage": "Çöp kutusunu atlayıp hemen sil",
"unarchive": "Arşivden çıkar",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Hedef klasör adını seçin:",
"unarchiveOverwriteExisting": "Mevcut dosyaların üzerine yaz",
"unsavedChanges": "Yaptığınız değişiklikler kaydedilmeyecek. Çıkılsın mı?",

View File

@ -170,6 +170,8 @@
"size": "Розмір",
"skipTrashMessage": "Видалити без збереження в кошик",
"unarchive": "Розархівування",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "Виберіть назву папки призначення:",
"unarchiveOverwriteExisting": "Перезаписати наявні файли",
"unsavedChanges": "Неможливо зберегти внесені зміни. Покинути сторінку?",

View File

@ -170,6 +170,8 @@
"size": "大小",
"skipTrashMessage": "跳过回收站并立即删除",
"unarchive": "解压缩",
"unarchiveDestinationLocationMessage": "Select the destination:",
"unarchiveFolderNameMessage": "Choose folder name:",
"unarchiveMessage": "选择目标文件夹名字:",
"unarchiveOverwriteExisting": "覆盖现有文件",
"unsavedChanges": "您所做的修改将不会被保存, 丢弃更改吗?",

View File

@ -277,7 +277,8 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
override := r.URL.Query().Get("override") == "true"
rename := r.URL.Query().Get("rename") == "true"
if !override && !rename {
unarchive := action == "unarchive"
if !override && !rename && !unarchive {
if _, err = d.user.Fs.Stat(dst); err == nil {
return http.StatusConflict, nil
}
@ -292,7 +293,11 @@ func resourcePatchHandler(fileCache FileCache) handleFunc {
}
err = d.RunHook(func() error {
return patchAction(r.Context(), action, src, dst, d, fileCache)
if unarchive {
return unarchiveAction(src, dst, d, override)
} else {
return patchAction(r.Context(), action, src, dst, d, fileCache)
}
}, action, src, dst, d.user)
return errToStatus(err), err
@ -441,53 +446,75 @@ func patchAction(ctx context.Context, action, src, dst string, d *data, fileCach
}
return fileutils.MoveFile(d.user.Fs, src, dst)
case "unarchive":
if !d.user.Perm.Create {
return errors.ErrPermissionDenied
}
default:
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
}
}
src = d.user.FullPath(path.Clean("/" + src))
dst = d.user.FullPath(path.Clean("/" + dst))
func unarchiveAction(src, dst string, d *data, overwrite bool) error {
if !d.user.Perm.Create {
return errors.ErrPermissionDenied
}
arch, err := archiver.ByExtension(src)
if err != nil {
return err
}
src = d.user.FullPath(path.Clean("/" + src))
dst = d.user.FullPath(path.Clean("/" + dst))
// if we reach this place when overwrite is needed,
// it means that override was selected
switch a := arch.(type) {
case *archiver.Rar:
a.OverwriteExisting = true
case *archiver.Tar:
a.OverwriteExisting = true
case *archiver.TarBz2:
a.OverwriteExisting = true
case *archiver.TarGz:
a.OverwriteExisting = true
case *archiver.TarLz4:
a.OverwriteExisting = true
case *archiver.TarSz:
a.OverwriteExisting = true
case *archiver.TarXz:
a.OverwriteExisting = true
case *archiver.Zip:
a.OverwriteExisting = true
}
arch, err := archiver.ByExtension(src)
if err != nil {
return err
}
unarchiver, ok := arch.(archiver.Unarchiver)
if !ok {
return errors.ErrInvalidRequestParams
}
switch a := arch.(type) {
case *archiver.Rar:
a.OverwriteExisting = overwrite
case *archiver.Tar:
a.OverwriteExisting = overwrite
case *archiver.TarBz2:
a.OverwriteExisting = overwrite
case *archiver.TarGz:
a.OverwriteExisting = overwrite
case *archiver.TarLz4:
a.OverwriteExisting = overwrite
case *archiver.TarSz:
a.OverwriteExisting = overwrite
case *archiver.TarXz:
a.OverwriteExisting = overwrite
case *archiver.Zip:
a.OverwriteExisting = overwrite
}
unarchiver, ok := arch.(archiver.Unarchiver)
if ok {
err = unarchiver.Unarchive(src, dst)
if err != nil {
return errors.ErrInvalidRequestParams
}
return nil
default:
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
}
decompressor, ok := arch.(archiver.Decompressor)
if ok {
reader, err := os.Open(src)
if err != nil {
return err
}
dst, err := os.OpenFile(dst, os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0644)
if err != nil {
return err
}
err = decompressor.Decompress(reader, dst)
if err != nil {
fmt.Println(err)
return errors.ErrInvalidRequestParams
}
return nil
}
return errors.ErrInvalidRequestParams
}
func archiveHandler(r *http.Request, d *data) (int, error) {