#1132 Copying/Moving of multiple entries

This commit is contained in:
Karel Pičman 2023-09-07 09:30:08 +02:00
parent 17ac75f90a
commit 06d7bb8762
37 changed files with 484 additions and 816 deletions

View File

@ -111,4 +111,3 @@ Style/OpenStructUse:
Style/OptionalBooleanParameter:
Exclude:
- lib/redmine_dmsf/field_formats/dmsf_file_format.rb

View File

@ -61,8 +61,8 @@ def dmsf_init
Redmine::AccessControl.map do |map|
map.project_module :dmsf do |pmap|
pmap.permission :view_dmsf_file_revision_accesses, read: true
pmap.permission :view_dmsf_file_revisions, read: true
pmap.permission :view_dmsf_file_revision_accesses, {}, read: true
pmap.permission :view_dmsf_file_revisions, {}, read: true
pmap.permission :view_dmsf_folders, { dmsf: %i[show index] }, read: true
pmap.permission :user_preferences, { dmsf_state: [:user_pref_save] }, require: :member
pmap.permission(:view_dmsf_files,
@ -75,9 +75,8 @@ def dmsf_init
{ dmsf_public_urls: [:create] }
pmap.permission :folder_manipulation,
{ dmsf: %i[new create delete edit save edit_root save_root lock unlock notify_activate
notify_deactivate restore drop],
notify_deactivate restore drop copymove],
dmsf_folder_permissions: %i[new append autocomplete_for_user],
dmsf_folders_copy: %i[new copy move],
dmsf_context_menus: [:dmsf] }
pmap.permission :file_manipulation,
{ dmsf_files: %i[create_revision lock unlock delete_revision obsolete_revision
@ -85,7 +84,6 @@ def dmsf_init
dmsf_upload: %i[upload_files upload commit_files commit delete_dmsf_attachment
delete_dmsf_link_attachment multi_upload],
dmsf_links: %i[new create destroy restore autocomplete_for_project autocomplete_for_folder],
dmsf_files_copy: %i[new copy move],
dmsf_context_menus: [:dmsf] }
pmap.permission :file_delete,
{ dmsf: %i[trash delete_entries empty_trash],
@ -97,8 +95,7 @@ def dmsf_init
pmap.permission :manage_workflows,
{ dmsf_workflows: %i[index new create destroy show new_step add_step remove_step
reorder_steps update update_step delete_step edit] }
pmap.permission :display_system_folders,
read: true
pmap.permission :display_system_folders, {}, read: true
# Watchers
pmap.permission :view_dmsf_file_watchers, {}, read: true
pmap.permission :add_dmsf_file_watchers, { watchers: %i[new create append autocomplete_for_user] }

View File

@ -35,6 +35,8 @@ class DmsfController < ApplicationController
before_action :find_folder_by_title, only: [:show]
before_action :query, only: %i[expand_folder show trash empty_trash index]
before_action :project_roles, only: %i[new edit create save]
before_action :find_target_folder, only: %i[copymove entries_operation]
before_action :check_target_folder, only: [:entries_operation]
accept_api_auth :show, :create, :save, :delete
@ -138,59 +140,55 @@ class DmsfController < ApplicationController
flash[:error] = e.message
end
def entries_operation
# Download/Email
if params[:ids].present?
selected_folders = params[:ids].grep(/folder-\d+/).map { |x| Regexp.last_match(1).to_i if x =~ /folder-(\d+)/ }
selected_files = params[:ids].grep(/file-\d+/).map { |x| Regexp.last_match(1).to_i if x =~ /file-(\d+)/ }
selected_dir_links = params[:ids].grep(/folder-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /folder-link-(\d+)/ }
selected_file_links = params[:ids].grep(/file-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /file-link-(\d+)/ }
selected_url_links = params[:ids].grep(/url-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /url-link-(\d+)/ }
else
selected_folders = []
selected_files = []
selected_dir_links = []
selected_file_links = []
selected_url_links = []
def copymove
@ids = params[:ids]
member = Member.find_by(project_id: @project.id, user_id: User.current.id)
@fast_links = member&.dmsf_fast_links
unless @fast_links
@projects = DmsfFolder.allowed_target_projects_on_copy
@folders = DmsfFolder.directory_tree(@target_project, @folder)
@target_folder = DmsfFolder.visible.find(params[:target_folder_id]) if params[:target_folder_id].present?
end
@back_url = params[:back_url]
render layout: !request.xhr?
end
if selected_folders.blank? &&
selected_files.blank? &&
selected_dir_links.blank? &&
selected_file_links.blank? &&
selected_url_links.blank?
def entries_operation
# Download/Email
if @selected_folders.blank? && @selected_files.blank? && @selected_links.blank?
flash[:warning] = l(:warning_no_entries_selected)
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
return
end
if selected_dir_links.present? && (params[:email_entries].present? || params[:download_entries].present?)
selected_folders = DmsfLink.where(id: selected_dir_links).pluck(:target_id) | selected_folders
if @selected_dir_links.present? && (params[:email_entries].present? || params[:download_entries].present?)
@selected_folders = DmsfLink.where(id: selected_dir_links).pluck(:target_id) | @selected_folders
end
if selected_file_links.present? && (params[:email_entries].present? || params[:download_entries].present?)
selected_files = DmsfLink.where(id: selected_file_links).pluck(:target_id) | selected_files
if @selected_file_links.present? && (params[:email_entries].present? || params[:download_entries].present?)
@selected_files = DmsfLink.where(id: selected_file_links).pluck(:target_id) | @selected_files
end
begin
if params[:email_entries].present?
email_entries selected_folders, selected_files
email_entries @selected_folders, @selected_files
elsif params[:restore_entries].present?
restore_entries selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links
restore_entries @selected_folders, @selected_files, @selected_links
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
elsif params[:delete_entries].present?
delete_entries(selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links,
false)
delete_entries @selected_folders, @selected_files, @selected_links, false
redirect_back_or_default dmsf_folder_path id: @project, folder_id: @folder
elsif params[:destroy_entries].present?
delete_entries(selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links,
true)
delete_entries @selected_folders, @selected_files, @selected_links, true
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
elsif params[:move_entries].present?
move_entries @selected_folders, @selected_files, @selected_links
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
elsif params[:copy_entries].present?
copy_entries @selected_folders, @selected_files, @selected_links
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
else
download_entries selected_folders, selected_files
download_entries @selected_folders, @selected_files
end
rescue RedmineDmsf::Errors::DmsfFileNotFoundError
render_404
@ -574,7 +572,7 @@ class DmsfController < ApplicationController
zip
end
def restore_entries(selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links)
def restore_entries(selected_folders, selected_files, selected_links)
# Folders
selected_folders.each do |id|
folder = DmsfFolder.find_by(id: id)
@ -589,7 +587,7 @@ class DmsfController < ApplicationController
flash[:error] = file.errors.full_messages.to_sentence unless file.restore
end
# Links
(selected_dir_links + selected_file_links + selected_url_links).each do |id|
selected_links.each do |id|
link = DmsfLink.find_by(id: id)
raise RedmineDmsf::Errors::DmsfFileNotFoundError unless link
@ -597,8 +595,7 @@ class DmsfController < ApplicationController
end
end
def delete_entries(selected_folders, selected_files, selected_dir_links, selected_file_links, selected_url_links,
commit)
def delete_entries(selected_folders, selected_files, selected_links, commit)
# Folders
selected_folders.each do |id|
raise RedmineDmsf::Errors::DmsfAccessError unless User.current.allowed_to?(:folder_manipulation, @project)
@ -613,9 +610,10 @@ class DmsfController < ApplicationController
# Files
deleted_files = []
not_deleted_files = []
selected_files.each do |id|
if selected_files.any?
raise RedmineDmsf::Errors::DmsfAccessError unless User.current.allowed_to?(:file_delete, @project)
end
selected_files.each do |id|
file = DmsfFile.find_by(id: id)
if file
if file.delete(commit: commit)
@ -647,21 +645,70 @@ class DmsfController < ApplicationController
flash[:warning] = l(:warning_some_entries_were_not_deleted, entries: not_deleted_files.map(&:title).join(', '))
end
# Links
selected_dir_links.each do |id|
if selected_links.any?
raise RedmineDmsf::Errors::DmsfAccessError unless User.current.allowed_to?(:folder_manipulation, @project)
link = DmsfLink.find_by(id: id)
link&.delete commit: commit
end
(selected_file_links + selected_url_links).each do |id|
raise RedmineDmsf::Errors::DmsfAccessError unless User.current.allowed_to?(:file_delete, @project)
selected_links.each do |id|
link = DmsfLink.find_by(id: id)
link&.delete commit: commit
end
flash[:notice] = l(:notice_entries_deleted) if flash[:error].blank? && flash[:warning].blank?
end
def copy_entries(selected_folders, selected_files, selected_links)
# Folders
selected_folders.each do |id|
folder = DmsfFolder.find_by(id: id)
new_folder = folder.copy_to(@target_project, @target_folder)
raise(StandardError, new_folder.errors.full_messages.to_sentence) unless new_folder.errors.empty?
end
# Files
selected_files.each do |id|
file = DmsfFile.find_by(id: id)
new_file = file.copy_to(@target_project, @target_folder)
raise(StandardError, new_file.errors.full_messages.to_sentence) unless new_file.errors.empty?
end
# Links
selected_links.each do |id|
link = DmsfLink.find_by(id: id)
new_link = link.copy_to(@target_project, @target_folder)
raise(StandardError, new_link.errors.full_messages.to_sentence) unless new_link.errors.empty?
end
flash[:notice] = l(:notice_entries_copied) if flash[:error].blank? && flash[:warning].blank?
end
def move_entries(selected_folders, selected_files, selected_links)
# Permissions
if selected_folders.any? && !User.current.allowed_to?(:folder_manipulation, @project)
raise RedmineDmsf::Errors::DmsfAccessError
end
if (selected_folders.any? || selected_links.any?) && !User.current.allowed_to?(:file_manipulation, @project)
raise RedmineDmsf::Errors::DmsfAccessError
end
# Folders
selected_folders.each do |id|
folder = DmsfFolder.find_by(id: id)
unless folder.move_to(@target_project, @target_folder)
raise(StandardError, folder.errors.full_messages.to_sentence)
end
end
# Files
selected_files.each do |id|
file = DmsfFile.find_by(id: id)
unless file.move_to(@target_project, @target_folder)
raise(StandardError, file.errors.full_messages.to_sentence)
end
end
# Links
selected_links.each do |id|
link = DmsfLink.find_by(id: id)
unless link.move_to(@target_project, @target_folder)
raise(StandardError, link.errors.full_messages.to_sentence)
end
end
flash[:notice] = l(:notice_entries_moved) if flash[:error].blank? && flash[:warning].blank?
end
def find_folder
@folder = DmsfFolder.find(params[:folder_id]) if params[:folder_id].present?
rescue ActiveRecord::RecordNotFound
@ -719,4 +766,68 @@ class DmsfController < ApplicationController
@project_roles = Role.givable.joins(:member_roles).joins(:members).where(members: { project_id: @project.id })
.distinct
end
def find_target_folder
@target_project = if params[:dmsf_entries] && params[:dmsf_entries][:target_project_id].present?
Project.find params[:dmsf_entries][:target_project_id]
else
@project
end
if params[:dmsf_entries] && params[:dmsf_entries][:target_folder_id].present?
target_folder_id = params[:dmsf_entries][:target_folder_id]
@target_folder = DmsfFolder.find(target_folder_id)
raise ActiveRecord::RecordNotFound unless DmsfFolder.visible.exists?(id: target_folder_id)
@target_project = @target_folder&.project
end
rescue ActiveRecord::RecordNotFound
render_404
end
def check_target_folder
if params[:ids].present?
@selected_folders = params[:ids].grep(/folder-\d+/).map { |x| Regexp.last_match(1).to_i if x =~ /folder-(\d+)/ }
@selected_files = params[:ids].grep(/file-\d+/).map { |x| Regexp.last_match(1).to_i if x =~ /file-(\d+)/ }
@selected_dir_links = params[:ids].grep(/folder-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /folder-link-(\d+)/ }
@selected_file_links = params[:ids].grep(/file-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /file-link-(\d+)/ }
@selected_url_links = params[:ids].grep(/url-link-\d+/)
.map { |x| Regexp.last_match(1).to_i if x =~ /url-link-(\d+)/ }
@selected_links = @selected_dir_links + @selected_file_links + @selected_url_links
else
@selected_folders = []
@selected_files = []
@selected_links = []
end
if params[:copy_entries].present? || params[:move_entries].present?
begin
# Prevent copying/moving to the same destination
folders = DmsfFolder.where(id: @selected_folders).to_a
files = DmsfFile.where(id: @selected_files).to_a
links = DmsfLink.where(id: @selected_links).to_a
(folders + files + links).each do |entry|
raise RedmineDmsf::Errors::DmsfParentError if entry.dmsf_folder == @target_folder || entry == @target_folder
end
# Prevent recursion
if params[:move_entries].present?
folders.each do |entry|
b = entry.any_child?(@target_folder)
raise RedmineDmsf::Errors::DmsfParentError if entry.any_child?(@target_folder)
end
end
# Check permissions
if (@target_folder && (@target_folder.locked_for_user? ||
!DmsfFolder.permissions?(@target_folder, allow_system: false))) ||
!@target_project.allows_to?(:folder_manipulation)
raise RedmineDmsf::Errors::DmsfAccessError
end
rescue RedmineDmsf::Errors::DmsfParentError
flash[:error] = l(:error_target_folder_same)
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder)
rescue RedmineDmsf::Errors::DmsfAccessError
render_403
end
end
end
end

View File

@ -1,138 +0,0 @@
# frozen_string_literal: true
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Files copy controller
class DmsfFilesCopyController < ApplicationController
menu_item :dmsf
before_action :find_file
before_action :authorize
before_action :find_target_folder
before_action :check_target_folder, only: %i[copy move]
accept_api_auth :copy, :move
helper :dmsf
def new
member = Member.find_by(project_id: @project.id, user_id: User.current.id)
@fast_links = member&.dmsf_fast_links
unless @fast_links
@projects = DmsfFile.allowed_target_projects_on_copy
@folders = DmsfFolder.directory_tree(@target_project, @folder)
end
@back_url = params[:back_url]
render layout: !request.xhr?
end
def copy
new_file = @file.copy_to(@target_project, @target_folder)
failure = new_file.nil? || new_file.errors.present?
if failure
flash[:error] = new_file ? new_file.errors.full_messages.to_sentence : @file.errors.full_messages.to_sentence
else
flash[:notice] = l(:notice_successful_update)
end
respond_to do |format|
format.html do
redirect_back_or_default dmsf_folder_path(id: @file.project, folder_id: @file.dmsf_folder)
end
format.api do
if failure
render_validation_errors new_file || @file
else
render_api_ok
end
end
end
end
def move
success = @file.move_to(@target_project, @target_folder)
if success
flash[:notice] = l(:notice_successful_update)
else
flash[:error] = @file.errors.full_messages.to_sentence
end
respond_to do |format|
format.html do
redirect_back_or_default dmsf_folder_path(id: @file.project, folder_id: @file.dmsf_folder)
end
format.api do
if success
render_api_ok
else
render_validation_errors @file
end
end
end
end
private
def find_file
raise ActiveRecord::RecordNotFound unless DmsfFile.exists?(id: params[:id])
@file = DmsfFile.visible.find params[:id]
raise RedmineDmsf::Errors::DmsfAccessError if @file.locked_for_user?
@project = @file.project
rescue ActiveRecord::RecordNotFound
render_404
rescue RedmineDmsf::Errors::DmsfAccessError
render_403
end
def find_target_folder
target_folder_id = if params[:target_folder_id].present?
params[:target_folder_id]
elsif params[:dmsf_file_or_folder] && params[:dmsf_file_or_folder][:target_folder_id].present?
params[:dmsf_file_or_folder][:target_folder_id]
end
@target_folder = DmsfFolder.visible.find(target_folder_id) if target_folder_id
target_project_id = if params[:target_project_id].present?
params[:target_project_id]
elsif params[:dmsf_file_or_folder] && params[:dmsf_file_or_folder][:target_project_id].present?
params[:dmsf_file_or_folder][:target_project_id]
else
@target_folder&.project_id
end
@target_project = target_project_id ? Project.visible.find(target_project_id) : @project
rescue ActiveRecord::RecordNotFound
render_404
end
def check_target_folder
if (@target_folder && @target_folder == @file.dmsf_folder) ||
(@target_folder.nil? && @file.dmsf_folder.nil? && @target_project == @file.project)
flash[:error] = l(:error_target_folder_same)
redirect_to action: :new, id: @file, target_project_id: @target_project&.id, target_folder_id: @target_folder
return
end
if (@target_folder && (@target_folder.locked_for_user? ||
!DmsfFolder.permissions?(@target_folder, allow_system: false))) ||
!@target_project.allows_to?(:file_manipulation)
raise RedmineDmsf::Errors::DmsfAccessError
end
rescue RedmineDmsf::Errors::DmsfAccessError
render_403
end
end

View File

@ -1,137 +0,0 @@
# frozen_string_literal: true
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Folders copy controller
class DmsfFoldersCopyController < ApplicationController
menu_item :dmsf
before_action :find_folder
before_action :authorize
before_action :find_target_folder
before_action :check_target_folder, only: %i[copy move]
accept_api_auth :copy, :move
helper :dmsf
def new
member = Member.find_by(project_id: @project.id, user_id: User.current.id)
@fast_links = member&.dmsf_fast_links
unless @fast_links
@projects = DmsfFolder.allowed_target_projects_on_copy
@folders = DmsfFolder.directory_tree(@target_project, @folder)
@target_folder = DmsfFolder.visible.find(params[:target_folder_id]) if params[:target_folder_id].present?
end
@back_url = params[:back_url]
render layout: !request.xhr?
end
def copy
new_folder = @folder.copy_to(@target_project, @target_folder)
success = new_folder.errors.empty?
if success
flash[:notice] = l(:notice_successful_update)
else
flash[:error] = new_folder.errors.full_messages.to_sentence
end
respond_to do |format|
format.html do
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder.dmsf_folder)
end
format.api do
if success
render_api_ok
else
render_validation_errors new_folder
end
end
end
end
def move
success = @folder.move_to(@target_project, @target_folder)
if success
flash[:notice] = l(:notice_successful_update)
else
flash[:error] = @folder.errors.full_messages.to_sentence
end
respond_to do |format|
format.html do
redirect_back_or_default dmsf_folder_path(id: @project, folder_id: @folder.dmsf_folder)
end
format.api do
if success
render_api_ok
else
render_validation_errors @folder
end
end
end
end
private
def find_folder
raise ActiveRecord::RecordNotFound unless DmsfFolder.exists?(id: params[:id])
@folder = DmsfFolder.visible.find params[:id]
raise RedmineDmsf::Errors::DmsfAccessError if @folder.locked_for_user?
@project = @folder.project
rescue ActiveRecord::RecordNotFound
render_404
rescue RedmineDmsf::Errors::DmsfAccessError
render_403
end
def find_target_folder
@target_project = if params[:dmsf_file_or_folder] && params[:dmsf_file_or_folder][:target_project_id].present?
Project.find params[:dmsf_file_or_folder][:target_project_id]
else
@project
end
if params[:dmsf_file_or_folder] && params[:dmsf_file_or_folder][:target_folder_id].present?
target_folder_id = params[:dmsf_file_or_folder][:target_folder_id]
@target_folder = DmsfFolder.find(target_folder_id)
raise ActiveRecord::RecordNotFound unless DmsfFolder.visible.exists?(id: target_folder_id)
@target_project = @target_folder&.project
end
rescue ActiveRecord::RecordNotFound
render_404
end
def check_target_folder
if (@target_folder && @target_folder == @folder.dmsf_folder) ||
(@target_folder.nil? && @folder.dmsf_folder.nil? && @target_project == @folder.project)
flash[:error] = l(:error_target_folder_same)
redirect_to action: :new, id: @folder, target_project_id: @target_project.id, target_folder_id: @target_folder
return
end
if (@target_folder && (@target_folder.locked_for_user? ||
!DmsfFolder.permissions?(@target_folder, allow_system: false))) ||
!@target_project.allows_to?(:folder_manipulation)
raise RedmineDmsf::Errors::DmsfAccessError
end
rescue RedmineDmsf::Errors::DmsfAccessError
render_403
end
end

View File

@ -304,11 +304,10 @@ class DmsfFolder < ApplicationRecord
new_folder.description = description
new_folder.user = User.current
new_folder.custom_values = []
custom_values.each do |cv|
v = CustomValue.new
v.custom_field = cv.custom_field
v.value = cv.value
new_folder.custom_values << v
new_folder.custom_field_values =
custom_field_values.inject({}) do |h, v|
h[v.custom_field_id] = v.value
h
end
unless new_folder.save
Rails.logger.error new_folder.errors.full_messages.to_sentence
@ -601,6 +600,15 @@ class DmsfFolder < ApplicationRecord
title
end
# Check whether any child folder is equal to the folder
def any_child?(folder)
dmsf_folders.each do |child|
return true if child == folder
child.any_child? folder
end
false
end
class << self
def directory_subtree(tree, folder, level, current_folder)
folders = folder.dmsf_folders.visible.to_a

View File

@ -0,0 +1,75 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render partial: '/dmsf/path', locals: { folder: nil, filename: nil, title: nil } %>
<% if @projects.present? || @fast_links %>
<%= form_tag(entries_operations_dmsf_path, id: 'copyForm') do %>
<% @ids.each do |id| %>
<%= hidden_field_tag 'ids[]', id %>
<% end %>
<%= hidden_field_tag 'back_url', @back_url %>
<%= hidden_field_tag 'id', @project %>
<%= hidden_field_tag 'copy_entries', true %>
<div class="box tabular">
<% unless @fast_links %>
<p>
<%= label_tag 'dmsf_entries[target_project_id]', l(:field_target_project) %>
<%= select_tag 'dmsf_entries[target_project_id]',
project_tree_options_for_select(@projects, selected: @target_project) %>
</p>
<% end %>
<p>
<%= label_tag 'dmsf_entries[target_folder_id]', l(:field_target_folder) %><%= ' #' if @fast_links %>
<% if @fast_links %>
<%= text_field_tag 'dmsf_entries[target_folder_id]', '', required: true, max_length: 255 %>
<% else %>
<%= select_tag 'dmsf_entries[target_folder_id]', options_for_select(@folders, selected: @target_folder&.id) %>
<% end %>
</p>
</div>
<p>
<%= submit_tag l(:button_copy), id: 'copy_button' %>
<%# TODO: Lock and proper permissions %>
<% if User.current.allowed_to?(:folder_manipulation, @project) &&
User.current.allowed_to?(:file_manipulation, @project)%>
<%= submit_tag l(:button_move), id: 'move_button' %>
<% end %>
</p>
<% end %>
<% end %>
<%= late_javascript_tag do %>
$('#move_button').click(function(event) {
$('#copyForm').attr('action', "<%= entries_operations_dmsf_path(ids: @ids, move_entries: true) %>");
$('#copyForm').submit();
});
<% unless @fast_links %>
$('#dmsf_entries_target_project_id').change(function () {
$('#content').load("<%= copymove_entries_path(id: @project, folder_id: @folder, ids: @ids) %>",
$('#copyForm').serialize());
});
$('#dmsf_entries_target_project_id').select2();
$('#dmsf_entries_target_folder_id').select2();
<% end %>
<% end %>

View File

@ -24,8 +24,8 @@
</li>
<% unless dmsf_link %>
<li>
<%= link_to "#{l(:button_copy)}/#{l(:button_move)}", copy_file_path(id: dmsf_file, back_url: back_url),
title: l(:title_copy), class: 'icon icon-copy' %>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copymove_entries_path(id: project, folder_id: folder,
ids: ["file-#{dmsf_file.id}"], back_url: back_url), class: 'icon icon-copy' %>
</li>
<li>
<%= link_to l(:label_link_to),

View File

@ -26,8 +26,8 @@
<% end %>
<% unless dmsf_link %>
<li>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copy_folder_path(id: dmsf_folder, back_url: back_url),
class: 'icon icon-copy', disabled: !allowed || locked %>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copymove_entries_path(id: project, folder_id: folder,
ids: ["folder-#{dmsf_folder.id}"], back_url: back_url), class: 'icon icon-copy', disabled: !allowed || locked %>
</li>
<li>
<%= context_menu_link l(:label_link_to),

View File

@ -27,9 +27,12 @@
ids: params[:ids], email_entries: true), method: :post, class: 'icon icon-email',
disabled: !email_allowed %>
</li>
<li>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copymove_entries_path(id: project, folder_id: folder,
ids: params[:ids], back_url: back_url), class: 'icon icon-copy', disabled: project.nil? %>
</li>
<li>
<%= context_menu_link l(:button_delete), entries_operations_dmsf_path(id: project, folder_id: folder,
ids: params[:ids], delete_entries: true), method: :post, class: 'icon icon-del',
data: { confirm: l(:text_are_you_sure) }, id: 'dmsf-cm-delete',
disabled: !allowed %>
data: { confirm: l(:text_are_you_sure) }, id: 'dmsf-cm-delete', disabled: !allowed %>
</li>

View File

@ -36,8 +36,8 @@
dmsf_file_id: file.id, type: 'link_to', back_url: back_url),
title: l(:title_create_link),
class: 'icon dmsf-icon-link' %>
<%= link_to "#{l(:button_copy)}/#{l(:button_move)}", copy_file_path(id: file, back_url: back_url),
title: l(:title_copy), class: 'icon icon-copy' %>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copymove_entries_path(id: project,
folder_id: file.dmsf_folder, ids: ["file-#{file.id}"], back_url: back_url), class: 'icon icon-copy' %>
<% member = Member.find_by(user_id: User.current.id, project_id: file.project.id) %>
<% filename = file.last_revision&.formatted_name(member) %>
<%= link_to l(:button_download), static_dmsf_file_path(file, filename: filename), class: 'icon icon-download',

View File

@ -1,35 +0,0 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render partial: '/dmsf/path', locals: { folder: @file.dmsf_folder, filename: @file.title, title: nil } %>
<%= render partial: '/dmsf_folders_copy/form',
locals: {
projects: @projects,
project: @project,
target_project: @target_project,
folders: @folders,
file_or_folder: @file,
target_folder: @target_folder,
permission: :file_manipulation,
fast_links: @fast_links,
back_url: @back_url } %>

View File

@ -1,63 +0,0 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% if projects.present? || fast_links %>
<%= form_tag({ action: 'copy', id: file_or_folder}, id: 'copyForm') do %>
<%= hidden_field_tag 'back_url', back_url %>
<div class="box tabular">
<% unless fast_links %>
<p>
<%= label_tag 'dmsf_file_or_folder[target_project_id]', l(:field_target_project) %>
<%= select_tag 'dmsf_file_or_folder[target_project_id]',
project_tree_options_for_select(projects, selected: target_project) %>
</p>
<% end %>
<p>
<%= label_tag 'dmsf_file_or_folder[target_folder_id]', l(:field_target_folder) %><%= ' #' if fast_links %>
<% if fast_links %>
<%= text_field_tag 'dmsf_file_or_folder[target_folder_id]', '', required: true, max_length: 255 %>
<% else %>
<%= select_tag 'dmsf_file_or_folder[target_folder_id]',
options_for_select(folders, selected: (target_folder.id if target_folder)) %>
<% end %>
</p>
</div>
<p>
<%= submit_tag l(:button_copy), id: 'copy_button' %>
<% if !file_or_folder.locked? && User.current.allowed_to?(permission, project) %>
<%= submit_tag l(:button_move), id: 'move_button' %>
<% end %>
</p>
<% end %>
<% end %>
<%= late_javascript_tag do %>
$('#move_button').click(function(event) {
$('#copyForm').attr('action', "<%= url_for(action: 'move', id: file_or_folder) %>");
$('#copyForm').submit();
});
<% unless fast_links %>
$('#dmsf_file_or_folder_target_project_id').change(function () {
$('#content').load("<%= url_for(action: 'new') %>", $('#copyForm').serialize());
});
$('#dmsf_file_or_folder_target_project_id').select2();
$('#dmsf_file_or_folder_target_folder_id').select2();
<% end %>
<% end %>

View File

@ -1,34 +0,0 @@
<%
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render partial: '/dmsf/path', locals: { folder: @folder, filename: nil, title: nil } %>
<%= render partial: '/dmsf_folders_copy/form', locals: {
projects: @projects,
project: @project,
target_project: @target_project,
folders: @folders,
file_or_folder: @folder,
target_folder: @target_folder,
permission: :folder_manipulation,
fast_links: @fast_links,
back_url: @back_url} %>

View File

@ -473,6 +473,9 @@ cs:
text_fulltext_search: 'Full-textové vyhledávání v dokumentech vyžaduje přítomnost %{cmd1} and %{cmd2} na serveru.'
notice_entries_copied: Kopírování se podařilo
notice_entries_moved: Přesun se podařil
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -469,6 +469,9 @@ de:
text_fulltext_search: 'Full-text Suche in Dokumente fordert die Existenz %{cmd1} and %{cmd2} auf dem Server.'
notice_entries_copied: Kopieren ist gelungen
notice_entries_moved: Verschiebung ist gelungen
easy_pages:
modules:
dmsf_locked_documents: Von mir gesperrte Dokumente

View File

@ -473,6 +473,9 @@ en:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -473,6 +473,9 @@ es:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -452,6 +452,9 @@ fa:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: اسناد قفل شده‌ی من

View File

@ -473,6 +473,9 @@ fr:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -472,6 +472,9 @@ hu:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -473,6 +473,9 @@ it: # Italian strings thx 2 Matteo Arceci!
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -474,6 +474,9 @@ ja:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: 自分がロック中の文書

View File

@ -473,6 +473,9 @@ ko:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: 내 잠긴 파일

View File

@ -473,6 +473,9 @@ nl:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -472,6 +472,9 @@ pl:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -473,6 +473,9 @@ pt-BR:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -473,6 +473,9 @@ sl:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -475,6 +475,9 @@ uk:
text_fulltext_search: 'Повнотекстовий пошук вимагає наявності %{cmd1} та %{cmd2} команд на сервері.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: Мої заблоковані документи

View File

@ -472,6 +472,9 @@ zh-TW:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -473,6 +473,9 @@ zh:
text_fulltext_search: 'Full-text search in documents requires presence of %{cmd1} and %{cmd2} commands on the server.'
notice_entries_copied: Copying has succeeded
notice_entries_moved: Moving has succeeded
easy_pages:
modules:
dmsf_locked_documents: My locked documents

View File

@ -42,6 +42,7 @@ if Redmine::Plugin.installed? 'redmine_dmsf'
get '/projects/:id/dmsf/entries/download_email_entries', controller: 'dmsf',
action: 'download_email_entries',
as: 'download_email_entries'
get '/projects/:id/entries/copymove', to: 'dmsf#copymove', as: 'copymove_entries'
get '/projects/:id/dmsf/lock', controller: 'dmsf', action: 'lock', as: 'lock_dmsf'
get '/projects/:id/dmsf/unlock', controller: 'dmsf', action: 'unlock', as: 'unlock_dmsf'
get '/projects/:id/dmsf/', controller: 'dmsf', action: 'show', as: 'dmsf_folder'

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module RedmineDmsf
module Errors
# Parent error
class DmsfParentError < StandardError
# Nothing to do
end
end
end

View File

@ -454,4 +454,138 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
get :index
assert_response :forbidden
end
def test_copymove_authorize_admin
@request.session[:user_id] = @admin.id
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file1.id}"] }
assert_response :success
assert_template 'copymove'
end
def test_copymove_authorize_non_member
@request.session[:user_id] = @someone.id
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file1.id}"] }
assert_response :forbidden
end
def test_copymove_authorize_member_no_module
@file1.project.disable_module! :dmsf
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file1.id}"] }
assert_response :forbidden
end
def test_copymove_authorize_forbidden
@role_manager.remove_permission! :folder_manipulation
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file1.id}"] }
assert_response :forbidden
end
def test_copymove_target_folder
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file1.id}"] }
assert_response :success
assert_template 'copymove'
end
def test_entries_copy
post :entries_operation,
params: { id: @file1.project,
dmsf_entries: { target_project_id: @folder1.project.id, target_folder_id: @folder1.id },
ids: ["file-#{@file1.id}"],
copy_entries: true }
assert_response :redirect
assert_nil flash[:error]
end
def test_entries_copy
post :entries_operation,
params: { id: @file1.project,
dmsf_entries: { target_project_id: @file1.project.id, target_folder_id: @file1.dmsf_folder },
ids: ["file-#{@file1.id}"],
copy_entries: true }
assert_response :redirect
assert_equal flash[:error], l(:error_target_folder_same)
end
def test_entries_move_recursion
# Move a folder under the same folder
post :entries_operation,
params: { id: @folder1.project,
dmsf_entries: { target_project_id: @folder2.project.id, target_folder_id: @folder2.id },
ids: ["folder-#{@folder1.id}"],
move_entries: true }
assert_response :redirect
assert_equal flash[:error], l(:error_target_folder_same)
end
def test_entries_move_infinity
# Move the folder to itself
post :entries_operation,
params: { id: @folder1.project,
dmsf_entries: { target_project_id: @folder2.project.id, target_folder_id: @folder2.id },
ids: ["folder-#{@folder2.id}"],
move_entries: true }
assert_response :redirect
assert_equal flash[:error], l(:error_target_folder_same)
end
def test_entries_copy_to_locked_folder
@request.session[:user_id] = @admin.id
post :entries_operation,
params: { id: @folder1.project,
dmsf_entries: { target_project_id: @folder2.project.id, target_folder_id: @folder2.id },
ids: ["file-#{@file1.id}"],
move_entries: true }
assert_response :forbidden
end
def test_entries_copy_to_dmsf_not_enabled
@project2.disable_module! :dmsf
post :entries_operation,
params: { id: @project2.id,
dmsf_entries: { target_project_id: @project2.id },
ids: ["file-#{@file1.id}"],
copy_entries: true }
assert_response :forbidden
end
def test_entries_copy_to_dmsf_enabled
post :entries_operation,
params: { id: @project2.id,
dmsf_entries: { target_project_id: @project2.id },
ids: ["file-#{@file1.id}"],
copy_entries: true }
assert_response :redirect
end
def test_entries_copy_to_as_non_member
@request.session[:user_id] = @someone.id
post :entries_operation,
params: { id: @project2.id,
dmsf_entries: { target_project_id: @project2.id },
ids: ["file-#{@file1.id}"],
copy_entries: true }
assert_response :forbidden
end
def test_copymove_new_fast_links_enabled
member = Member.find_by(user_id: @jsmith.id, project_id: @project1.id)
assert member
member.dmsf_fast_links = true
member.save
get :copymove, params: { id: @file1.project, folder_id: @file1.dmsf_folder, ids: ["file-#{@file4.id}"] }
assert_response :success
assert_select 'label', { count: 0, text: l(:label_target_project) }
assert_select 'label', { count: 0, text: "#{l(:label_target_folder)}#" }
end
def test_entries_move_fast_links_enabled
# Target project is not given
post :entries_operation,
params: { id: @project1.id,
dmsf_entries: { target_folder_id: @folder1.id },
ids: ["file-#{@file1.id}"],
move_entries: true }
assert_response :redirect
assert_nil flash[:error]
end
end

View File

@ -1,142 +0,0 @@
# frozen_string_literal: true
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
# Files controller
class DmsfFilesControllerTest < RedmineDmsf::Test::TestCase
fixtures :dmsf_folders, :dmsf_files, :dmsf_file_revisions, :dmsf_locks
def setup
super
@request.session[:user_id] = @jsmith.id
end
def teardown
super
DmsfFile.clear_previews
end
def test_show_file_ok
# Permissions OK
get :show, params: { id: @file1.id }
assert_response :success
end
def test_show_formatting_html
Setting.text_formatting = 'HTML'
get :show, params: { id: @file1.id }
assert_response :success
assert_include 'dmsf-description', response.body, 'dmsf-description class not found'
assert_include 'wiki-edit', response.body, 'wiki-edit class not found'
end
def test_show_formatting_textile
Setting.text_formatting = 'Textile'
get :show, params: { id: @file1.id }
assert_response :success
assert_include 'dmsf-description', response.body, 'dmsf-description class not found'
assert_include 'wiki-edit', response.body, 'wiki-edit class not found'
end
def test_show_file_forbidden
# Missing permissions
@role_manager.remove_permission! :view_dmsf_files
get :show, params: { id: @file1.id }
assert_response :forbidden
end
def test_view_file_ok
# Permissions OK
get :view, params: { id: @file1.id }
assert_response :success
end
def test_view_file_forbidden
# Missing permissions
@role_manager.remove_permission! :view_dmsf_files
get :view, params: { id: @file1.id }
assert_response :forbidden
end
def test_view_preview
return unless RedmineDmsf::Preview.office_available?
get :view, params: { id: @file13.id }
assert_response :success
assert_equal 'application/pdf', @response.media_type
assert @response.body.starts_with?('%PDF')
end
def delete_forbidden
# Missing permissions
@role_manager.remove_permission! :file_manipulation
delete :delete, params: { id: @file1, folder_id: @file1.dmsf_folder, commit: false }
assert_response :forbidden
end
def delete_locked
# Permissions OK but the file is locked
delete :delete, params: { id: @file2, folder_id: @file2.dmsf_folder, commit: false }
assert_response :redirect
assert_include l(:error_file_is_locked), flash[:error]
end
def delete_ok
# Permissions OK and not locked
delete :delete, params: { id: @file1, folder_id: @file1.dmsf_folder, commit: false }
assert_redirected_to dmsf_folder_path(id: @file1.project, folder_id: @file1.dmsf_folder)
end
def test_delete_in_subfolder
delete :delete, params: { id: @file4, folder_id: @file4.dmsf_folder, commit: false }
assert_redirected_to dmsf_folder_path(id: @file4.project, folder_id: @file4.dmsf_folder)
end
def test_obsolete_revision_ok
get :obsolete_revision, params: { id: @file1.last_revision.id }
assert_redirected_to action: 'show', id: @file1
end
def test_obsolete_revision_missing_permissions
@role_manager.remove_permission! :file_manipulation
get :obsolete_revision, params: { id: @file1.last_revision.id }
assert :forbiden
end
def test_create_revision
assert_difference 'DmsfFileRevision.count', +1 do
post :create_revision,
params: {
id: @file1.id,
version_major: @file1.last_revision.major_version,
version_minor: @file1.last_revision.minor_version + 1,
dmsf_file_revision: {
title: @file1.last_revision.title,
name: @file1.last_revision.name,
description: @file1.last_revision.description,
comment: 'New revision'
}
}
end
assert_redirected_to dmsf_folder_path(id: @file1.project)
assert_not_nil @file1.last_revision.digest
end
end

View File

@ -1,199 +0,0 @@
# frozen_string_literal: true
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011-23 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require File.expand_path('../../test_helper', __FILE__)
# Folders copy controller
class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase
include Redmine::I18n
fixtures :dmsf_locks, :dmsf_folders, :dmsf_files, :dmsf_file_revisions
def setup
super
@request.session[:user_id] = @jsmith.id
end
def test_authorize_admin
@request.session[:user_id] = @admin.id
get :new, params: { id: @folder1.id }
assert_response :success
assert_template 'new'
end
def test_authorize_non_member
@request.session[:user_id] = @someone.id
get :new, params: { id: @folder1.id }
assert_response :not_found
end
def test_authorize_member_no_module
@project1.disable_module! :dmsf
get :new, params: { id: @folder1.id }
assert_response :not_found
end
def test_authorize_forbidden
@role_manager.remove_permission! :folder_manipulation
get :new, params: { id: @folder1.id }
assert_response :forbidden
end
def test_target_folder
get :new, params: { id: @folder1.id, target_folder_id: @folder2.id }
assert_response :success
assert_template 'new'
end
def test_target_folder_forbidden
@role_manager.remove_permission! :view_dmsf_folders
get :new, params: { id: @folder1.id, target_folder_id: @folder2.id }
assert_response :not_found
end
def test_target_project
get :new, params: { id: @folder1.id, target_project_id: @project1.id }
assert_response :success
assert_template 'new'
end
def test_new
get :new, params: { id: @folder1.id }
assert_response :success
assert_template 'new'
end
def test_copy
post :copy, params: { id: @folder1.id, dmsf_file_or_folder: { target_project_id: @project1.id,
target_folder_id: @folder6.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_copy_to_another_project
@request.session[:user_id] = @admin.id
assert_equal @project1.id, @folder1.project_id
post :copy, params: { id: @folder1.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_copy_the_same_target
post :copy, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder6.project.id } }
assert_equal flash[:error], l(:error_target_folder_same)
assert_redirected_to action: :new, target_project_id: @folder6.project.id
end
def test_copy_to_locked_folder
@request.session[:user_id] = @admin.id
post :copy, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder2.project.id,
target_folder_id: @folder2.id } }
assert_response :forbidden
end
def test_copy_to_dmsf_not_enabled
@project2.disable_module! :dmsf
post :copy, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :forbidden
end
def test_copy_to_dmsf_enabled
post :copy, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_copy_to_as_non_member
@request.session[:user_id] = @someone.id
post :copy, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder1.project.id,
target_folder_id: @folder1.id } }
assert_response :not_found
end
def test_move
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder1.project.id,
target_folder_id: @folder1.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_move_to_another_project
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_move_the_same_target
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder6.project.id } }
assert_equal flash[:error], l(:error_target_folder_same)
assert_redirected_to action: :new, target_project_id: @folder6.project.id
end
def test_move_locked_folder
@request.session[:user_id] = @admin.id
post :move, params: { id: @folder2.id, dmsf_file_or_folder: { target_project_id: @folder6.project.id,
target_folder_id: @folder6.id } }
assert_response :forbidden
end
def test_move_to_locked_folder
@request.session[:user_id] = @admin.id
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder2.project.id,
target_folder_id: @folder2.id } }
assert_response :forbidden
end
def test_move_to_dmsf_not_enabled
@project2.disable_module! :dmsf
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :forbidden
end
def test_move_to_dmsf_enabled
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @project2.id } }
assert_response :redirect
assert_nil flash[:error]
end
def test_move_to_as_non_member
@request.session[:user_id] = @someone.id
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_project_id: @folder1.project.id,
target_folder_id: @folder1.id } }
assert_response :not_found
end
def test_new_fast_links_enabled
member = Member.find_by(user_id: @jsmith.id, project_id: @project1.id)
assert member
member.dmsf_fast_links = true
member.save
get :new, params: { id: @folder1.id }
assert_response :success
assert_select 'label', { count: 0, text: l(:label_target_project) }
assert_select 'label', { count: 0, text: "#{l(:label_target_folder)}#" }
end
def test_move_fast_links_enabled
# Target project is not given
post :move, params: { id: @folder6.id, dmsf_file_or_folder: { target_folder_id: @folder1.id } }
assert_response :redirect
assert_nil flash[:error]
end
end

View File

@ -292,4 +292,12 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert @folder8.save
assert_not DmsfFolder.where(id: @folder8.id).issystem.exists?
end
def test_any_child
# folder1
## folder 2
# folder6
assert_not @folder1.any_child?(@folder6)
assert @folder1.any_child?(@folder2)
end
end