This commit is contained in:
Karel Pičman 2023-09-07 15:50:56 +02:00
parent 06d7bb8762
commit de3d262965
11 changed files with 131 additions and 161 deletions

View File

@ -4,6 +4,13 @@ Changelog for Redmine DMSF
3.1.3 *????-??-??*
------------------
DMS Document as a new custom field type
Copy/Move of multiple entries
REST API
Entries operation (copy, move, download, delete)
IMPORTANT: REST API for copying/moving has changed.
3.1.2 *2023-08-23*
------------------

View File

@ -38,7 +38,7 @@ class DmsfController < ApplicationController
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
accept_api_auth :show, :create, :save, :delete, :entries_operation
helper :custom_fields
helper :dmsf_folder_permissions
@ -612,7 +612,7 @@ class DmsfController < ApplicationController
not_deleted_files = []
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
@ -625,6 +625,7 @@ class DmsfController < ApplicationController
raise RedmineDmsf::Errors::DmsfFileNotFoundError
end
end
end
# Activities
unless deleted_files.empty?
begin
@ -647,11 +648,12 @@ class DmsfController < ApplicationController
# Links
if selected_links.any?
raise RedmineDmsf::Errors::DmsfAccessError unless User.current.allowed_to?(:folder_manipulation, @project)
end
selected_links.each do |id|
link = DmsfLink.find_by(id: id)
link&.delete commit: commit
end
end
flash[:notice] = l(:notice_entries_deleted) if flash[:error].blank? && flash[:warning].blank?
end
@ -685,6 +687,7 @@ class DmsfController < ApplicationController
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)
@ -695,16 +698,12 @@ class DmsfController < ApplicationController
# 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
raise(StandardError, file.errors.full_messages.to_sentence) unless file.move_to(@target_project, @target_folder)
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
raise(StandardError, link.errors.full_messages.to_sentence) unless link.move_to(@target_project, @target_folder)
end
flash[:notice] = l(:notice_entries_moved) if flash[:error].blank? && flash[:warning].blank?
end
@ -800,7 +799,8 @@ class DmsfController < ApplicationController
@selected_files = []
@selected_links = []
end
if params[:copy_entries].present? || params[:move_entries].present?
return unless params[:copy_entries].present? || params[:move_entries].present?
begin
# Prevent copying/moving to the same destination
folders = DmsfFolder.where(id: @selected_folders).to_a
@ -812,7 +812,6 @@ class DmsfController < ApplicationController
# 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
@ -830,4 +829,3 @@ class DmsfController < ApplicationController
end
end
end
end

View File

@ -305,9 +305,8 @@ class DmsfFolder < ApplicationRecord
new_folder.user = User.current
new_folder.custom_values = []
new_folder.custom_field_values =
custom_field_values.inject({}) do |h, v|
custom_field_values.each_with_object({}) do |v, h|
h[v.custom_field_id] = v.value
h
end
unless new_folder.save
Rails.logger.error new_folder.errors.full_messages.to_sentence
@ -604,6 +603,7 @@ class DmsfFolder < ApplicationRecord
def any_child?(folder)
dmsf_folders.each do |child|
return true if child == folder
child.any_child? folder
end
false

View File

@ -36,7 +36,7 @@ if Redmine::Plugin.installed? 'redmine_dmsf'
delete '/projects/:id/dmsf/delete', controller: 'dmsf', action: 'delete', as: 'delete_dmsf'
post '/projects/:id/dmsf/save', controller: 'dmsf', action: 'save'
post '/projects/:id/dmsf/save/root', controller: 'dmsf', action: 'save_root'
post '/projects/dmsf/entries', controller: 'dmsf', action: 'entries_operation', as: 'entries_operations_dmsf'
post '/projects/:id/dmsf/entries', controller: 'dmsf', action: 'entries_operation', as: 'entries_operations_dmsf'
post '/projects/:id/dmsf/entries/delete', controller: 'dmsf', action: 'delete_entries', as: 'delete_entries'
post '/projects/:id/dmsf/entries/email', to: 'dmsf#entries_email', as: 'email_entries'
get '/projects/:id/dmsf/entries/download_email_entries', controller: 'dmsf',

View File

@ -19,8 +19,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Authentication as input parameters either as login + password or the API key
# -u ${1}:${2}
# -H "X-Redmine-API-Key: ${1}"
#USER_LOGIN="${1}"
#USER_PASSWORD="${2}"
#USER_API_KEY="${1}"
# BOTH XML and JSON formats are supported.
# Just replace .xml with .json
@ -28,41 +29,41 @@
# Uncomment a corresponding line to the case you would like to test
# 1. List of documents in a given folder or the root folder
#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000/projects/12/dmsf.xml
#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000/projects/12/dmsf.xml?folder_id=5155
#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} "http://localhost:3000/projects/12/dmsf.xml?limit=2&offset=1"
#curl -v -H "Content-Type: application/xml" -X GET -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/12/dmsf.xml
#curl -v -H "Content-Type: application/xml" -X GET -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/12/dmsf.xml?folder_id=5155
#curl -v -H "Content-Type: application/xml" -X GET -u ${USER_LOGIN}:${USER_PASSWORD} "http://localhost:3000/projects/12/dmsf.xml?limit=2&offset=1"
# 2. Get a document
#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000/dmsf/files/17216.xml
#curl -v -H "Content-Type: application/octet-stream" -X GET -u ${1}:${2} http://localhost:3000/dmsf/files/41532/download > file.txt
#curl -v -H "Content-Type: application/xml" -X GET -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/dmsf/files/17216.xml
#curl -v -H "Content-Type: application/octet-stream" -X GET -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/dmsf/files/41532/download > file.txt
# 3. Upload a document into a given folder or the root folder
#curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif
#curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/commit.xml
#curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/12/dmsf/upload.xml?filename=cat.gif
#curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/12/dmsf/commit.xml
# 4. Create a new revision
#curl -v -H "Content-Type: application/xml" -X POST --data "@revision.xml" -u ${1}:${2} http://localhost:3000/dmsf/files/232565/revision/create.xml
#curl -v -H "Content-Type: application/xml" -X POST --data "@revision.xml" -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/dmsf/files/232565/revision/create.xml
# 5. Copy a document
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/files/233313/copy/copy.xml
# 5. Copy document(s)
#curl -v -H "Content-Type: application/xml" -X POST --data "@entries.xml" -H "X-Redmine-API-Key: ${USER_API_KEY}" "http://localhost:3000/projects/3342/dmsf/entries.xml?ids[]=file-254566&copy_entries=true"
# 6. Move a document
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/files/233313/copy/move.xml
# 6. Move document(s)
#curl -v -H "Content-Type: application/xml" -X POST --data "@entries.xml" -H "X-Redmine-API-Key: ${USER_API_KEY}" "http://localhost:3000/projects/3342/dmsf/entries.xml?ids[]=file-254566&move_entries=true"
# 7. Delete a document
# a) Move to trash only
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/dmsf/files/196118.xml
# b) Delete permanently
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/dmsf/files/196118.xml?commit=yes"
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/dmsf/files/196118.xml?commit=yes"
# 8. Create a folder
#curl -v -H "Content-Type: application/xml" -X POST --data "@folder.xml" -u ${1}:${2} http://localhost:3000/projects/12/dmsf/create.xml
#curl -v -H "Content-Type: application/xml" -X POST --data "@folder.xml" -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/12/dmsf/create.xml
# 9. List folder content & check folder existence (by folder title)
# curl -v -H "Content-Type: application/json" -X GET -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/projects/1/dmsf.json?folder_title=Updated%20title
# curl -v -H "Content-Type: application/json" -X GET -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000/projects/1/dmsf.json?folder_title=Updated%20title
# 10. List folder content & check folder existence (by folder id)
# curl -v -H "Content-Type: application/json" -X GET -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/projects/1/dmsf.json?folder_id=3
# curl -v -H "Content-Type: application/json" -X GET -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000/projects/1/dmsf.json?folder_id=3
# both returns 404 not found, or json with following structure:
# {
# "dmsf":{
@ -74,7 +75,7 @@
#}
# 11. Update a folder
# curl -v -H "Content-Type: application/json" -X POST --data "@update-folder-payload.json" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000//projects/#{project_id}/dmsf/save.json?folder_id=#{folder_id}
# curl -v -H "Content-Type: application/json" -X POST --data "@update-folder-payload.json" -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000//projects/#{project_id}/dmsf/save.json?folder_id=#{folder_id}
# update-folder-payload.json
# {
@ -85,16 +86,16 @@
# }
# 12. Copy a folder
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/folders/53075/copy/copy.xml
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000/dmsf/folders/53075/copy/copy.xml
# 13. Move a folder
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/folders/53075/copy/move.xml
#curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000/dmsf/folders/53075/copy/move.xml
# 14. Delete a folder
# a) Move to trash only
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} http://localhost:3000/projects/2387/dmsf/delete.xml?folder_id=#{folder_id}
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${USER_LOGIN}:${USER_PASSWORD} http://localhost:3000/projects/2387/dmsf/delete.xml?folder_id=#{folder_id}
# b) Delete permanently
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${1}:${2} "http://localhost:3000/projects/2387/dmsf/delete.xml?folder_id=#{folder_id}&commit=yes"
# curl -v -H "Content-Type: application/xml" -X DELETE -u ${USER_LOGIN}:${USER_PASSWORD} "http://localhost:3000/projects/2387/dmsf/delete.xml?folder_id=#{folder_id}&commit=yes"
# 15. Create a symbolic link
# curl -v -H "Content-Type: application/xml" -X POST --data "@link.xml" -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf_links.xml
# curl -v -H "Content-Type: application/xml" -X POST --data "@link.xml" -H "X-Redmine-API-Key: ${USERS_API_KEY}" http://localhost:3000/dmsf_links.xml

5
extra/api/entries.xml Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_entries>
<target_project_id>3342</target_project_id>
<target_folder_id>58659</target_folder_id>
</dmsf_entries>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_file_or_folder>
<target_project_id>3057</target_project_id>
<target_folder_id>53064</target_folder_id>
</dmsf_file_or_folder>

View File

@ -496,7 +496,7 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
assert_nil flash[:error]
end
def test_entries_copy
def test_entries_copy_to_the_same_folder
post :entries_operation,
params: { id: @file1.project,
dmsf_entries: { target_project_id: @file1.project.id, target_folder_id: @file1.dmsf_folder },

View File

@ -109,4 +109,40 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
assert_select 'node > target_id', text: @folder_link1.target_id.to_s
assert_select 'node > target_project_id', text: @folder_link1.target_project_id.to_s
end
def test_copy_entries
# curl -v -H "Content-Type: application/xml" -X POST --data "@entries.xml" -H "X-Redmine-API-Key: ${USER_API_KEY}" \
# "http://localhost:3000/projects/3342/dmsf/entries.xml?ids[]=file-254566&copy_entries=true"
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_entries>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_entries>
)
assert_difference('@folder1.dmsf_files.count', 1) do
post "/projects/#{@project1.id}/dmsf/entries.xml?ids[]=file-#{@file1.id}&copy_entries=true&key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :redirect
end
def test_move_entries
# curl -v -H "Content-Type: application/xml" -X POST --data "@entries.xml" -H "X-Redmine-API-Key: ${USER_API_KEY}" \
# "http://localhost:3000/projects/3342/dmsf/entries.xml?ids[]=file-254566&move_entries=true"
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_entries>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_entries>
)
assert_difference('@folder1.dmsf_files.count', 1) do
post "/projects/#{@project1.id}/dmsf/entries.xml?ids[]=file-#{@file1.id}&move_entries=true&key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :redirect
end
end

View File

@ -240,40 +240,4 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
# </dmsf_file_revision>
assert_select 'dmsf_file_revision > id', text: @file1.last_revision.id.to_s
end
def test_copy_document
# curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml"
# -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/files/1/copy/copy.xml
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_file_or_folder>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_file_or_folder>
)
assert_difference('@folder1.dmsf_files.count', 1) do
post "/dmsf/files/#{@file1.id}/copy/copy.xml?key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :success
end
def test_move_document
# curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml" -H
# "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/files/1/copy/move.xml
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_file_or_folder>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_file_or_folder>
)
assert_difference('@folder1.dmsf_files.count', 1) do
post "/dmsf/files/#{@file1.id}/copy/move.xml?key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :success
end
end

View File

@ -292,40 +292,4 @@ class DmsfFolderApiTest < RedmineDmsf::Test::IntegrationTest
@folder2.reload
assert_equal DmsfFolder::STATUS_ACTIVE, @folder2.deleted
end
def test_copy_folder
# curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml"
# -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/folders/6/copy/copy.xml
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_file_or_folder>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_file_or_folder>
)
assert_difference('@folder1.dmsf_folders.count', 1) do
post "/dmsf/folders/#{@folder6.id}/copy/copy.xml?key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :success
end
def test_move_document
# curl -v -H "Content-Type: application/xml" -X POST --data "@file_or_folder_copy_move.xml"
# -H "X-Redmine-API-Key: USERS_API_KEY" http://localhost:3000/dmsf/folders/6/copy/move.xml
payload = %(
<?xml version="1.0" encoding="utf-8" ?>
<dmsf_file_or_folder>
<target_project_id>#{@project1.id}</target_project_id>
<target_folder_id>#{@folder1.id}</target_folder_id>
</dmsf_file_or_folder>
)
assert_difference('@folder1.dmsf_folders.count', 1) do
post "/dmsf/folders/#{@folder6.id}/copy/move.xml?key=#{@token.value}",
params: payload,
headers: { 'CONTENT_TYPE' => 'application/xml' }
end
assert_response :success
end
end