Folder can not be deleted if the folder contains files or folders #1145

This commit is contained in:
karel.picman@lbcfree.net 2020-08-20 15:20:16 +02:00
parent aa1350ccf9
commit c28741c1a5
26 changed files with 96 additions and 65 deletions

View File

@ -135,7 +135,7 @@ class DmsfFile < ActiveRecord::Base
''
end
def delete(commit)
def delete(commit = false)
if locked_for_user? && (!User.current.allowed_to?(:force_file_unlock, project))
Rails.logger.info l(:error_file_is_locked)
if lock.reverse[0].user

View File

@ -127,25 +127,25 @@ class DmsfFolder < ActiveRecord::Base
end
end
def delete(commit)
def delete(commit = false)
if locked?
errors[:base] << l(:error_folder_is_locked)
return false
elsif !empty?
errors[:base] << l(:error_folder_is_not_empty)
return false
end
if commit
destroy
else
self.deleted = STATUS_DELETED
self.deleted_by_user = User.current
save!
delete_recursively
end
end
def empty?
!(dmsf_folders.visible.exists? || dmsf_files.visible.exists? || dmsf_links.visible.exists?)
def delete_recursively
self.deleted = STATUS_DELETED
self.deleted_by_user = User.current
save!
self.dmsf_files.each(&:delete)
self.dmsf_links.each(&:delete)
self.dmsf_folders.each(&:delete_recursively)
end
def deleted?
@ -153,13 +153,20 @@ class DmsfFolder < ActiveRecord::Base
end
def restore
if dmsf_folder_id && (nil? || dmsf_folder.deleted?)
if dmsf_folder&.deleted?
errors[:base] << l(:error_parent_folder)
return false
end
restore_recursively
end
def restore_recursively
self.deleted = STATUS_ACTIVE
self.deleted_by_user = nil
save
save!
self.dmsf_files.each(&:restore)
self.dmsf_links.each(&:restore)
self.dmsf_folders.each(&:restore_recursively)
end
def dmsf_path
@ -180,7 +187,7 @@ class DmsfFolder < ActiveRecord::Base
def notify?
return true if notification
return true if dmsf_folder && dmsf_folder.notify?
return true if dmsf_folder&.notify?
return true if !dmsf_folder && project.dmsf_notification
false
end

View File

@ -193,8 +193,12 @@ class DmsfQuery < Query
'folder' AS type,
dmsf_folders.deleted AS deleted,
0 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_folders.user_id = users.id').
visible(!deleted)
joins('LEFT JOIN users ON dmsf_folders.user_id = users.id')
if deleted
scope = scope.deleted
else
scope = scope.visible
end
if dmsf_folder_id
scope.where dmsf_folders: { dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else

View File

@ -67,5 +67,5 @@
<%= context_menu_link l(:button_delete),
dmsf_link ? dmsf_link_path(dmsf_link) : delete_dmsf_path(id: project, folder_id: dmsf_folder),
data: { confirm: l(:text_are_you_sure) }, method: :delete, class: 'icon icon-del', id: 'dmsf-cm-delete',
disabled: !allowed || locked || (dmsf_link ? false : !dmsf_folder.empty?) %>
disabled: !allowed || locked %>
</li>

View File

@ -23,11 +23,11 @@
<li>
<%= context_menu_link l(:title_restore),
dmsf_link ? restore_dmsf_link_path(id: dmsf_link) : restore_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-cancel', disabled: !allowed %>
class: 'icon icon-cancel', disabled: !allowed_restore %>
</li>
<li>
<%= context_menu_link l(:button_delete),
dmsf_link ? dmsf_link_path(id: dmsf_link, commit: 'yes') : delete_dmsf_path(id: project, folder_id: dmsf_folder, commit: 'yes'),
data: { confirm: l(:text_are_you_sure) }, method: :delete, class: 'icon icon-del',
id: 'dmsf-cm-delete', disabled: !allowed %>
id: 'dmsf-cm-delete', disabled: !allowed_delete %>
</li>

View File

@ -27,7 +27,8 @@
allowed_restore: @allowed_restore }) %>
<% elsif @dmsf_folder %>
<%= render(partial: 'folder_trash', locals: { project: @project, folder: @folder, dmsf_folder: @dmsf_folder,
dmsf_link: @dmsf_link, allowed: @allowed }) %>
dmsf_link: @dmsf_link, allowed_delete: @allowed_delete,
allowed_restore: @allowed_restore }) %>
<% else %>
<%= render(partial: 'multiple_trash', locals: { project: @project, folder: @folder, allowed_delete: @allowed_delete,
allowed_restore: @allowed_restore }) %>

View File

@ -40,7 +40,6 @@ cs:
error_folder_creation_failed: Vytváření složky selhalo
error_folder_title_must_be_entered: Musí být zadán název
notice_folder_deleted: Složka byla smazána
error_folder_is_not_empty: Složka není prázdná
error_folder_title_is_already_used: Název již existuje
notice_folder_details_were_saved: Detaily složky byly uloženy
error_folder_is_locked: Složka je zamčena

View File

@ -40,7 +40,6 @@ de:
error_folder_creation_failed: Ordnererstellung fehlgeschlagen
error_folder_title_must_be_entered: Es muss ein Titel angegeben werden
notice_folder_deleted: Ordner gelöscht
error_folder_is_not_empty: Ordner ist nicht leer
error_folder_title_is_already_used: Titel wird schon benutzt. Denk dir was Neues aus.
notice_folder_details_were_saved: Ordnerdetails wurden gespeichert
error_folder_is_locked: Ordner ist gesperrt

View File

@ -40,7 +40,6 @@ en:
error_folder_creation_failed: Folder creation failed
error_folder_title_must_be_entered: Title must be entered
notice_folder_deleted: Folder deleted
error_folder_is_not_empty: Folder is not empty
error_folder_title_is_already_used: Title is already used
notice_folder_details_were_saved: Folder details were saved
error_folder_is_locked: Folder is locked

View File

@ -40,7 +40,6 @@ es:
error_folder_creation_failed: La creacion de la carpeta ha fallado
error_folder_title_must_be_entered: Debe ingresar un título
notice_folder_deleted: Carpeta borrada
error_folder_is_not_empty: La carpeta no está vacía
error_folder_title_is_already_used: El título ingresado ya está siendo usado por otro documento
notice_folder_details_were_saved: Los detalles de la carpeta fueron grabados correctamente
error_folder_is_locked: Carpeta bloqueado

View File

@ -40,7 +40,6 @@ fr:
error_folder_creation_failed: Erreur de création du dossier
error_folder_title_must_be_entered: Le titre du document est requis
notice_folder_deleted: Dossier supprimé
error_folder_is_not_empty: "Le dossier n'est pas vide"
error_folder_title_is_already_used: Le titre du fichier est déjà utilisé
notice_folder_details_were_saved: Les détails du dossier ont été enregistrés
error_folder_is_locked: Le dossier est verrouillé

View File

@ -40,7 +40,6 @@ hu:
error_folder_creation_failed: Mappa létrehozása nem sikerült
error_folder_title_must_be_entered: Cím beírása kötelező
notice_folder_deleted: Mappa törlésre került
error_folder_is_not_empty: Mappa nem üres
error_folder_title_is_already_used: A címet már használják
notice_folder_details_were_saved: Mappa részleteit mentésre kerültek
error_folder_is_locked: Mappa zárolva

View File

@ -40,7 +40,6 @@ it: # Italian strings thx 2 Matteo Arceci!
error_folder_creation_failed: Creazione cartella fallita
error_folder_title_must_be_entered: Deve essere inserito il titolo
notice_folder_deleted: Cartella cancellata
error_folder_is_not_empty: La cartella non è vuota
error_folder_title_is_already_used: Il titolo è già in uso
notice_folder_details_were_saved: I dettagli della cartella sono stati salvati
error_folder_is_locked: La cartella è bloccata

View File

@ -40,7 +40,6 @@ ja:
error_folder_creation_failed: フォルダを作成できません
error_folder_title_must_be_entered: タイトルが必要です
notice_folder_deleted: フォルダを削除しました
error_folder_is_not_empty: フォルダが空ではありません
error_folder_title_is_already_used: タイトルは既に使われています
notice_folder_details_were_saved: フォルダの詳細を保存しました
error_folder_is_locked: フォルダはロックされています

View File

@ -40,7 +40,6 @@ ko:
error_folder_creation_failed: 폴더 생성 실패
error_folder_title_must_be_entered: 제목을 입력해야 합니다
notice_folder_deleted: 폴더 삭제됨
error_folder_is_not_empty: 폴더가 비어있지 않습니다
error_folder_title_is_already_used: 이미 사용 중인 제목입니다
notice_folder_details_were_saved: 폴더 상세 정보가 저장되었습니다
error_folder_is_locked: 폴더가 잠겨있습니다

View File

@ -40,7 +40,6 @@ nl:
error_folder_creation_failed: Map aanmaken mislukt
error_folder_title_must_be_entered: Titel moet worden ingevoerd
notice_folder_deleted: Map verwijderd
error_folder_is_not_empty: Map is niet leeg
error_folder_title_is_already_used: Titel is al in gebruik
notice_folder_details_were_saved: Gegevens map zijn opgeslagen
error_folder_is_locked: Map is vergrendeld

View File

@ -40,7 +40,6 @@ pl:
error_folder_creation_failed: Błąd podczas tworzenia folderu
error_folder_title_must_be_entered: Musisz podać tytuł
notice_folder_deleted: Folder został usunięty
error_folder_is_not_empty: Folder zawiera pliki
error_folder_title_is_already_used: Podany tytuł jest już w użyciu
notice_folder_details_were_saved: Szczegóły folderu zostały zapisane
error_folder_is_locked: Folder jest zablokowany

View File

@ -40,7 +40,6 @@ pt-BR:
error_folder_creation_failed: Erro na criação da pasta
error_folder_title_must_be_entered: Título deve ser digitado
notice_folder_deleted: Pasta deletada
error_folder_is_not_empty: Pasta não está vazia
error_folder_title_is_already_used: Título já utilizado
notice_folder_details_were_saved: Pasta atualizada
error_folder_is_locked: Pasta está bloqueada

View File

@ -40,7 +40,6 @@ ru:
error_folder_creation_failed: Папку не удалось создать
error_folder_title_must_be_entered: Нужно указать название папки
notice_folder_deleted: Папка удалена
error_folder_is_not_empty: Папка не пустая
error_folder_title_is_already_used: Название папки уже используется
notice_folder_details_were_saved: Описание папки было сохранено
error_folder_is_locked: Папка заблокированa

View File

@ -40,7 +40,6 @@ sl:
error_folder_creation_failed: Mape ne morem kreirati
error_folder_title_must_be_entered: Naslov mora biti vnešen
notice_folder_deleted: Mapa izbrisana
error_folder_is_not_empty: Mapa ni prazna
error_folder_title_is_already_used: Naslov je že uporabljen
notice_folder_details_were_saved: Podatki o mapi so shranjeni
error_folder_is_locked: Папка заблокированa

View File

@ -40,7 +40,6 @@ zh-TW:
error_folder_creation_failed: 資料夾建立失敗
error_folder_title_must_be_entered: 請輸入標題
notice_folder_deleted: 資料夾己刪除
error_folder_is_not_empty: 資料夾尚未清空
error_folder_title_is_already_used: 標題己經被使用了
notice_folder_details_were_saved: 資料夾描述己儲存
error_folder_is_locked: 資料夾己經鎖定

View File

@ -40,7 +40,6 @@ zh:
error_folder_creation_failed: 文件夹创建失败
error_folder_title_must_be_entered: 请输入主题
notice_folder_deleted: 文件夹已删除
error_folder_is_not_empty: 非空文件夹
error_folder_title_is_already_used: 标题已经被使用
notice_folder_details_were_saved: 文件夹详细信息已保存
error_folder_is_locked: 資料夾己經鎖定

View File

@ -169,12 +169,6 @@ class DmsfContextMenusControllerTest < RedmineDmsf::Test::TestCase
assert_select 'a.icon-email', text: l(:field_mail)
end
def test_dmsf_folder_not_empty
get :dmsf, params: { id: @folder1.project.id, ids: ["folder-#{@folder1.id}"] }
assert_response :success
assert_select 'a.icon-del.disabled', text: l(:button_delete)
end
def test_dmsf_folder_locked
assert @folder5.locked?
get :dmsf, params: { id: @folder5.project.id, ids: ["folder-#{@folder5.id}"] }
@ -232,7 +226,7 @@ class DmsfContextMenusControllerTest < RedmineDmsf::Test::TestCase
assert_select 'a.icon-edit', text: l(:button_edit)
assert_select 'a.icon-lock', text: l(:button_lock)
assert_select 'a.icon-email-add', text: l(:label_notifications_on)
assert_select 'a.icon-del.disabled', text: l(:button_delete)
assert_select 'a.icon-del', text: l(:button_delete)
assert_select 'a.icon-download', text: l(:button_download)
assert_select 'a.icon-email', text: l(:field_mail)
end

View File

@ -23,17 +23,19 @@ require File.expand_path('../../test_helper', __FILE__)
class DmsfControllerTest < RedmineDmsf::Test::TestCase
include Redmine::I18n
include Rails.application.routes.url_helpers
fixtures :custom_fields, :custom_values, :dmsf_links, :dmsf_folder_permissions, :dmsf_locks
def setup
super
@file_link2 = DmsfLink.find 4
@folder_link1 = DmsfLink.find 1
@link2 = DmsfLink.find 2
@link1 = DmsfLink.find 1
@custom_field = CustomField.find 21
@custom_value = CustomValue.find 21
User.current = nil
@request.session[:user_id] = @jsmith.id
default_url_options[:host] = 'http://example.com'
end
def test_edit_folder_forbidden
@ -78,6 +80,16 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
assert_select 'h2', { text: l(:link_trash_bin) }
end
def test_trash
@folder1.delete false
get :trash, params: { id: @project1 }
assert_response :success
assert_select 'a', href: dmsf_folder_path(id: @folder1.project.id, folder_id: @folder1.id)
assert_select 'a', href: dmsf_folder_path(id: @folder2.project.id, folder_id: @folder2.id)
assert_select 'a', href: url_for(controller: :dmsf_files, action: 'view', id: @file4.id, only_path: true)
assert_select 'a', href: url_for(controller: :dmsf_files, action: 'view', id: @link2.target_id, only_path: true)
end
def test_delete_forbidden
# Missing permissions
@role_manager.remove_permission! :folder_manipulation
@ -85,13 +97,6 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
assert_response :forbidden
end
def test_delete_with_parmission_but_not_empty
# Permissions OK but the folder is not empty
get :delete, params: { id: @project1, folder_id: @folder1.id, commit: false}
assert_response :redirect
assert_include l(:error_folder_is_not_empty), flash[:error]
end
def test_delete_locked
# Permissions OK but the folder is locked
@request.env['HTTP_REFERER'] = dmsf_folder_path(id: @project1.id, folder_id: @folder2.id)
@ -129,25 +134,16 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
# Missing permissions
@role_manager.remove_permission! :folder_manipulation
get :entries_operation, params: { id: @project1, delete_entries: 'Delete',
ids: ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"] }
ids: ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@link1.id}", "file-link-#{@link2.id}"] }
assert_response :forbidden
end
def test_delete_not_empty
# Permissions OK but the folder is not empty
@request.env['HTTP_REFERER'] = dmsf_folder_path(id: @project1.id)
get :entries_operation, params: { id: @project1, delete_entries: 'Delete',
ids: ["folder-#{@folder1.id}", "file-#{@file1.id}", "folder-link-#{@folder_link1.id}", "file-link-#{@file_link2.id}"]}
assert_response :redirect
assert_equal flash[:error].to_s, l(:error_folder_is_not_empty)
end
def test_delete_entries_ok
# Permissions OK
@request.env['HTTP_REFERER'] = dmsf_folder_path(id: @project1.id)
flash[:error] = nil
get :entries_operation, params: { id: @project1, delete_entries: 'Delete',
ids: ["folder-#{@folder7.id}", "file-#{@file1.id}", "file-link-#{@file_link2.id}"]}
ids: ["folder-#{@folder7.id}", "file-#{@file1.id}", "file-link-#{@link2.id}"]}
assert_response :redirect
assert_nil flash[:error]
end
@ -157,7 +153,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
@request.env['HTTP_REFERER'] = trash_dmsf_path(id: @project1.id)
flash[:error] = nil
get :entries_operation, params: { id: @project1, restore_entries: 'Restore',
ids: ["file-#{@file1.id}", "file-link-#{@file_link2.id}"]}
ids: ["file-#{@file1.id}", "file-link-#{@link2.id}"]}
assert_response :redirect
assert_nil flash[:error]
end

View File

@ -60,6 +60,7 @@ module RedmineDmsf
end
@file1 = DmsfFile.find 1
@file2 = DmsfFile.find 2
@file4 = DmsfFile.find 4
@file6 = DmsfFile.find 6
@file9 = DmsfFile.find 9
@file10 = DmsfFile.find 10

View File

@ -24,7 +24,13 @@ require File.expand_path('../../test_helper', __FILE__)
class DmsfFolderTest < RedmineDmsf::Test::UnitTest
fixtures :dmsf_folder_permissions, :dmsf_locks, :dmsf_folders, :dmsf_files, :dmsf_file_revisions
fixtures :dmsf_folder_permissions, :dmsf_locks, :dmsf_folders, :dmsf_files, :dmsf_file_revisions,
:dmsf_links
def setup
super
@link2 = DmsfLink.find 2
end
def test_visiblity
# The role has got permissions
@ -55,6 +61,16 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert @folder6.deleted?, "Folder #{@folder6} hasn't been deleted"
end
def test_delete_recursively
assert @folder1.delete(false), @folder1.errors.full_messages.to_sentence
# First&second level
[@folder1, @folder2].each do |folder|
assert_equal folder.dmsf_folders.all.size, folder.dmsf_folders.collect(&:deleted?).size
assert_equal folder.dmsf_files.all.size, folder.dmsf_files.collect(&:deleted?).size
assert_equal folder.dmsf_links.all.size, folder.dmsf_links.collect(&:deleted?).size
end
end
def test_restore
assert @folder6.delete(false), @folder6.errors.full_messages.to_sentence
assert @folder6.deleted?, "Folder #{@folder6} hasn't been deleted"
@ -62,9 +78,37 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert !@folder6.deleted?, "Folder #{@folder6} hasn't been restored"
end
def test_restore_recursively
# Delete
assert @folder1.delete(false), @folder1.errors.full_messages.to_sentence
# Restore
assert @folder1.restore, @folder1.errors.full_messages.to_sentence
assert !@folder1.deleted?, "Folder #{@folder1} hasn't been restored"
# First level
assert !@folder2.deleted?, "Folder #{@folder2} hasn't been restored"
assert !@link2.deleted?, "Link #{@link2} hasn't been restored"
# Second level
assert !@file4.deleted?, "File #{@file4} hasn't been restored"
end
def test_destroy
folder6_id = @folder6.id
@folder6.delete true
assert_nil DmsfFolder.find_by(id: @folder6.id)
assert_nil DmsfFolder.find_by(id: folder6_id)
end
def test_destroy_recursively
folder1_id = @folder1.id
folder2_id = @folder2.id
link2_id = @link2.id
file4_id = @file4.id
@folder1.delete true
assert_nil DmsfFolder.find_by(id: folder1_id)
# First level
assert_nil DmsfFolder.find_by(id: folder2_id)
assert_nil DmsfLink.find_by(id: link2_id)
# Second level
assert_nil DmsfFile.find_by(id: file4_id)
end
def test_is_column_on_default