Status 404 after moving the folder to another project #1106

This commit is contained in:
Karel Pičman 2020-04-23 10:13:06 +02:00
parent 0b750831d2
commit ecec07b520
23 changed files with 299 additions and 184 deletions

View File

@ -83,8 +83,6 @@ class DmsfContextMenusController < ApplicationController
def find_folder
@folder = DmsfFolder.find params[:folder_id] if params[:folder_id].present?
rescue DmsfAccessError
render_403
rescue ActiveRecord::RecordNotFound
render_404
end

View File

@ -30,13 +30,13 @@ class DmsfController < ApplicationController
:autocomplete_for_user]
before_action :find_parent, only: [:new, :create]
before_action :permissions
# also try to lookup folder by title if this is API call
# Also try to lookup folder by title if this is an API call
before_action :find_folder_by_title, only: [:show]
before_action :get_query, only: [:expand_folder, :show, :trash]
accept_api_auth :show, :create, :save, :delete
helper :all # TODO: Is it needed?
helper :custom_fields
helper :dmsf_folder_permissions
helper :queries
include QueriesHelper
@ -48,7 +48,6 @@ class DmsfController < ApplicationController
def expand_folder
@idnt = params[:idnt].present? ? params[:idnt].to_i + 1 : 0
#@query = retrieve_query(DmsfQuery, true)
@query.dmsf_folder_id = @folder.id
@query.deleted = false
respond_to do |format|
@ -62,8 +61,6 @@ class DmsfController < ApplicationController
@folder_manipulation_allowed = User.current.allowed_to?(:folder_manipulation, @project)
@file_manipulation_allowed = User.current.allowed_to?(:file_manipulation, @project)
@trash_enabled = @folder_manipulation_allowed && @file_manipulation_allowed
#use_session = !request.format.csv?
#@query = retrieve_query(DmsfQuery, use_session)
@query.dmsf_folder_id = @folder ? @folder.id : nil
@query.deleted = false
if (@folder && @folder.deleted?) || (params[:folder_title].present? && !@folder)
@ -89,7 +86,6 @@ class DmsfController < ApplicationController
@folder_manipulation_allowed = User.current.allowed_to? :folder_manipulation, @project
@file_manipulation_allowed = User.current.allowed_to? :file_manipulation, @project
@file_delete_allowed = User.current.allowed_to? :file_delete, @project
#@query = retrieve_query(DmsfQuery, true)
@query.deleted = true
respond_to do |format|
format.html {
@ -604,9 +600,7 @@ class DmsfController < ApplicationController
end
def find_folder
@folder = DmsfFolder.find_by!(id: params[:folder_id], project_id: @project.id) if params[:folder_id].present?
rescue DmsfAccessError
render_403
@folder = DmsfFolder.find(params[:folder_id]) if params[:folder_id].present?
rescue ActiveRecord::RecordNotFound
render_404
end

View File

@ -38,24 +38,22 @@ class DmsfFoldersCopyController < ApplicationController
def copy
new_folder = @folder.copy_to(@target_project, @target_folder)
unless new_folder.errors.empty?
if new_folder.errors.empty?
flash[:notice] = l(:notice_successful_update)
redirect_to dmsf_folder_path(id: @target_project, folder_id: new_folder)
else
flash[:error] = new_folder.errors.full_messages.to_sentence
redirect_to action: 'new', id: @folder, target_project_id: @target_project, target_folder_id: @target_folder
return
redirect_to :back
end
flash[:notice] = l(:notice_successful_update)
redirect_to dmsf_folder_path(id: @target_project, folder_id: new_folder)
end
def move
@folder.project = @target_project
@folder.dmsf_folder = @target_folder
if @folder.save
if @folder.move_to(@target_project, @target_folder)
flash[:notice] = l(:notice_successful_update)
redirect_to dmsf_folder_path(id: @target_project, folder_id: @folder)
else
flash[:error] = @folder.errors.full_messages.to_sentence
redirect_to action: 'new', id: @folder, target_project_id: @target_project, target_folder_id: @target_folder
redirect_to :back
end
end

View File

@ -155,7 +155,8 @@ class DmsfLinksController < ApplicationController
if params[:dmsf_link][:dmsf_file_id].present?
redirect_to dmsf_file_path(@dmsf_link.target_file)
else
redirect_to edit_dmsf_path(id: params[:dmsf_link][:project_id], folder_id: params[:dmsf_link][:dmsf_folder_id])
folder = @dmsf_link.target_folder.dmsf_folder if @dmsf_link.target_folder
redirect_to dmsf_folder_path(id: @project, folder_id: folder)
end
end
}

View File

@ -235,8 +235,12 @@ class DmsfFile < ActiveRecord::Base
errors[:base] << l(:error_file_is_locked)
return false
end
unless last_revision
errors[:base] << l(:error_at_least_one_revision_must_be_present)
return false
end
source = "#{project.identifier}:#{dmsf_path_str}"
self.project_id = project.id
self.project = project
self.dmsf_folder = folder
new_revision = last_revision.clone
new_revision.workflow = nil
@ -251,12 +255,12 @@ class DmsfFile < ActiveRecord::Base
last_revision.custom_values.each do |cv|
new_revision.custom_values << CustomValue.new({ custom_field: cv.custom_field, value: cv.value })
end
set_last_revision(new_revision)
set_last_revision new_revision
save && new_revision.save
end
def copy_to(project, folder = nil)
copy_to_filename(project, folder, name)
copy_to_filename project, folder, name
end
def copy_to_filename(project, folder, filename)

View File

@ -247,6 +247,23 @@ class DmsfFolder < ActiveRecord::Base
projects
end
def move_to(target_project, target_folder)
if self.project != target_project
dmsf_files.visible.find_each do |f|
f.move_to target_project, f.dmsf_folder
end
dmsf_folders.visible.find_each do |s|
s.move_to target_project, s.dmsf_folder
end
dmsf_links.visible.find_each do |l|
l.move_to target_project, l.dmsf_folder
end
self.project = target_project
end
self.dmsf_folder = target_folder
save
end
def copy_to(project, folder)
new_folder = DmsfFolder.new
new_folder.dmsf_folder = folder ? folder : nil
@ -254,7 +271,6 @@ class DmsfFolder < ActiveRecord::Base
new_folder.title = title
new_folder.description = description
new_folder.user = User.current
new_folder.custom_values = []
custom_values.each do |cv|
v = CustomValue.new
@ -262,36 +278,22 @@ class DmsfFolder < ActiveRecord::Base
v.value = cv.value
new_folder.custom_values << v
end
unless new_folder.save
Rails.logger.error new_folder.errors.full_messages.to_sentence
return new_folder
end
dmsf_files.visible.find_each do |f|
f.copy_to project, new_folder
end
dmsf_folders.visible.find_each do |s|
s.copy_to project, new_folder
end
folder_links.visible.find_each do |l|
dmsf_links.visible.find_each do |l|
l.copy_to project, new_folder
end
file_links.visible.find_each do |l|
l.copy_to project, new_folder
end
url_links.visible.find_each do |l|
l.copy_to project, new_folder
end
dmsf_folder_permissions.find_each do |p|
p.copy_to new_folder
end
new_folder
end

View File

@ -79,13 +79,6 @@ class DmsfLink < ActiveRecord::Base
@target_project
end
def folder
if !@folder && dmsf_folder_id
@folder = DmsfFolder.find_by(id: dmsf_folder_id)
end
@folder
end
def title
name
end
@ -114,6 +107,12 @@ class DmsfLink < ActiveRecord::Base
path
end
def move_to(target_project, target_folder)
self.project = target_project
self.dmsf_folder = target_folder
save
end
def copy_to(project, folder)
link = DmsfLink.new
link.target_project_id = target_project_id
@ -128,8 +127,8 @@ class DmsfLink < ActiveRecord::Base
end
def container
if folder && folder.system
Issue.find_by(id: folder.title)
if dmsf_folder && dmsf_folder.system
Issue.find_by id: dmsf_folder.title
end
end

View File

@ -189,9 +189,13 @@ class DmsfQuery < Query
joins('LEFT JOIN users ON dmsf_folders.user_id = users.id').
visible(!deleted)
if deleted
scope.where(dmsf_folders: { project_id: project.id, deleted: deleted })
scope.where dmsf_folders: { project_id: project.id, deleted: deleted }
else
scope.where(dmsf_folders: { project_id: project.id, dmsf_folder_id: dmsf_folder_id, deleted: deleted })
if dmsf_folder_id
scope.where dmsf_folders: { dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
scope.where dmsf_folders: { project_id: project.id, dmsf_folder_id: nil, deleted: deleted }
end
end
end
@ -204,7 +208,7 @@ class DmsfQuery < Query
select(%{
dmsf_links.id AS id,
COALESCE(dmsf_folders.project_id, dmsf_links.project_id) AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
dmsf_links.target_id AS revision_id,
dmsf_links.name AS title,
dmsf_folders.title AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
@ -222,10 +226,13 @@ class DmsfQuery < Query
joins('LEFT JOIN dmsf_folders ON dmsf_links.target_id = dmsf_folders.id').
joins('LEFT JOIN users ON users.id = COALESCE(dmsf_folders.user_id, dmsf_links.user_id)')
if deleted
scope.where(dmsf_links: { target_type: 'DmsfFolder', project_id: project.id, deleted: deleted })
scope.where dmsf_links: { target_type: 'DmsfFolder', project_id: project.id, deleted: deleted }
else
scope.where(dmsf_links: { target_type: 'DmsfFolder', project_id: project.id, dmsf_folder_id: dmsf_folder_id,
deleted: deleted })
if dmsf_folder_id
scope.where dmsf_links: { target_type: 'DmsfFolder', dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
scope.where dmsf_links: { target_type: 'DmsfFolder', project_id: project.id, dmsf_folder_id: nil, deleted: deleted }
end
end
end
@ -257,9 +264,14 @@ class DmsfQuery < Query
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where('dmsf_file_revisions.created_at = (SELECT MAX(r.created_at) FROM dmsf_file_revisions r WHERE r.dmsf_file_id = dmsf_file_revisions.dmsf_file_id)')
if deleted
scope.where(dmsf_files: { project_id: project.id, deleted: deleted })
scope.where dmsf_files: { project_id: project.id, deleted: deleted }
else
scope.where(dmsf_files: { project_id: project.id, dmsf_folder_id: dmsf_folder_id, deleted: deleted })
# Consider files belonging to the folder but with wrong project (#1106)
if dmsf_folder_id
scope.where dmsf_files: { dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
scope.where dmsf_files: { project_id: project.id, dmsf_folder_id: nil, deleted: deleted }
end
end
end
@ -272,7 +284,7 @@ class DmsfQuery < Query
select(%{
dmsf_links.id AS id,
dmsf_files.project_id AS project_id,
dmsf_file_revisions.id AS revision_id,
dmsf_files.id AS revision_id,
dmsf_links.name AS title,
dmsf_file_revisions.name AS filename,
dmsf_file_revisions.size AS size,
@ -292,9 +304,13 @@ class DmsfQuery < Query
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where('dmsf_file_revisions.created_at = (SELECT MAX(r.created_at) FROM dmsf_file_revisions r WHERE r.dmsf_file_id = dmsf_file_revisions.dmsf_file_id)')
if deleted
scope.where(project_id: project.id, deleted: deleted)
scope.where project_id: project.id, deleted: deleted
else
scope.where(project_id: project.id, dmsf_folder_id: dmsf_folder_id, deleted: deleted)
if dmsf_folder_id
scope.where dmsf_folder_id: dmsf_folder_id, deleted: deleted
else
scope.where project_id: project.id, dmsf_folder_id: nil, deleted: deleted
end
end
end
@ -324,9 +340,13 @@ class DmsfQuery < Query
1 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_links.user_id = users.id ')
if deleted
scope.where(target_type: 'DmsfUrl', project_id: project.id, deleted: deleted)
scope.where target_type: 'DmsfUrl', project_id: project.id, deleted: deleted
else
scope.where(target_type: 'DmsfUrl', project_id: project.id, dmsf_folder_id: dmsf_folder_id, deleted: deleted)
if dmsf_folder_id
scope.where target_type: 'DmsfUrl', dmsf_folder_id: dmsf_folder_id, deleted: deleted
else
scope.where target_type: 'DmsfUrl', project_id: project.id, dmsf_folder_id: nil, deleted: deleted
end
end
end

View File

@ -47,11 +47,6 @@
class: 'icon icon-email-add') %>
<% end %>
<% end %>
<%= link_to(l(:label_link_to),
new_dmsf_link_path(project_id: @project.id, dmsf_folder_id: @folder.id, type: 'link_to'),
title: l(:title_create_link), class: 'icon icon-link') %>
<%= link_to("#{l(:button_copy)}/#{l(:button_move)}", copy_folder_path(id: @folder),
title: l(:title_copy), class: 'icon icon-copy') %>
<% unless @folder.locked? %>
<%= link_to(l(:button_delete), delete_dmsf_path(id: @project, folder_id: @folder),
data: { confirm: l(:text_are_you_sure) },

View File

@ -25,7 +25,7 @@
<% html_title l(:dmsf) %>
<div class="contextual">
<% if @file_manipulation_allowed && !@locked_for_user && !@system_folder %>
<%= link_to l(:label_attachment_new), multi_dmsf_upload_path(id: @project, dmsf_folder_id: @folder),
<%= link_to l(:label_attachment_new), multi_dmsf_upload_path(id: @project, folder_id: @folder),
class: 'icon icon-add' %>
<% end %>
<% if defined?(EasyExtensions) %>

View File

@ -22,36 +22,40 @@
<li>
<%= context_menu_link l(:button_edit), edit_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-edit',
disabled: !allowed || locked %>
class: 'icon icon-edit', disabled: !allowed || locked %>
</li>
<li>
<%= context_menu_link "#{l(:button_copy)}/#{l(:button_move)}", copy_folder_path(id: dmsf_folder),
class: 'icon icon-copy', disabled: !allowed || locked %>
</li>
<li>
<%= context_menu_link l(:label_link_to),
new_dmsf_link_path(project_id: project.id, dmsf_folder_id: dmsf_folder.id, type: 'link_to'),
class: 'icon icon-link', disabled: !allowed || locked %>
</li>
<li>
<% if locked %>
<%= context_menu_link l(:button_unlock), unlock_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-unlock',
disabled: !allowed || !unlockable %>
class: 'icon icon-unlock', disabled: !allowed || !unlockable %>
<% else %>
<%= context_menu_link l(:button_lock), lock_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-lock',
disabled: !allowed %>
class: 'icon icon-lock', disabled: !allowed %>
<% end %>
</li>
<li>
<% if dmsf_folder.notification %>
<%= context_menu_link l(:label_notifications_off), notify_deactivate_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-email',
disabled: !allowed || locked || !dmsf_folder.notification? %>
class: 'icon icon-email', disabled: !allowed || locked || !dmsf_folder.notification? %>
<% else %>
<%= context_menu_link l(:label_notifications_on), notify_activate_dmsf_path(id: project, folder_id: dmsf_folder),
class: 'icon icon-email-add',
disabled: !allowed || locked || dmsf_folder.notification? %>
class: 'icon icon-email-add', disabled: !allowed || locked || dmsf_folder.notification? %>
<% end %>
</li>
<li>
<%= 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_folder.empty? %>
disabled: !allowed || locked || (dmsf_link ? false : !dmsf_folder.empty?) %>
</li>
<li>
<%= context_menu_link l(:button_download), entries_operations_dmsf_path(id: project, folder_id: folder,

View File

@ -32,8 +32,8 @@
<div class="box tabular">
<% if (@type == 'link_from') && !@container %>
<p>
<%= radio_button_tag(:external_link, 'false', true) %> <%= l(:label_internal) %><br/>
<%= radio_button_tag(:external_link, 'true', false) %> <%= l(:label_external) %>
<%= radio_button_tag :external_link, 'false', true %> <%= l(:label_internal) %><br/>
<%= radio_button_tag :external_link, 'true', false %> <%= l(:label_external) %>
</p>
<% end %>
<div id="dmsf_link_internal">
@ -44,9 +44,9 @@
<% else %>
<label for="dmsf_link[target_project_id]"><%= l(:label_target_project) %></label>
<% end %>
<%= select_tag('dmsf_link[target_project_id]',
<%= select_tag 'dmsf_link[target_project_id]',
project_tree_options_for_select(DmsfFile.allowed_target_projects_on_copy,
selected: @dmsf_link.target_project)) %>
selected: @dmsf_link.target_project) %>
<%= late_javascript_tag do %>
$('#dmsf_link_target_project_id').change(function(){
$.ajax({
@ -60,7 +60,7 @@
<% end %>
<p>
<% if @type == 'link_from' %>
<%= label_tag('dmsf_link[target_folder_id]', l(:label_source_folder)) %>
<%= label_tag 'dmsf_link[target_folder_id]', l(:label_source_folder) %>
<% else %>
<label for="dmsf_link_target_folder_id">
<%= l(:label_target_folder) %> <%= ' #' if @fast_links %>
@ -71,9 +71,8 @@
<% end %>
<% end %>
<% if !@fast_links || (@type != 'link_to') %>
<%= select_tag('dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project),
selected: @target_folder_id)) %>
<%= select_tag 'dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project)) %>
<%= late_javascript_tag do %>
$('#dmsf_link_target_folder_id').change(function(){
$.ajax({
@ -87,10 +86,9 @@
</p>
<% if @type == 'link_from' %>
<p>
<%= label_tag('dmsf_link[target_file_id]', l(:field_target_file)) %>
<%= label_tag 'dmsf_link[target_file_id]', l(:field_target_file) %>
<% files = files_for_select(@dmsf_link.target_project.id, @target_folder_id) %>
<%= select_tag('dmsf_link[target_file_id]',
options_for_select(DmsfFolder.file_list(files)), required: modal) %>
<%= select_tag 'dmsf_link[target_file_id]', options_for_select(DmsfFolder.file_list(files)), required: modal %>
</p>
<% end %>
</div>

View File

@ -72,6 +72,7 @@ if Redmine::Plugin.installed? :redmine_dmsf
get '/projects/:id/dmsf/upload/multi_upload', controller: 'dmsf_upload', action: 'multi_upload', as: 'multi_dmsf_upload'
post '/projects/:id/dmsf/upload/files', controller: 'dmsf_upload', action: 'upload_files'
get '/projects/:id/dmsf/upload/files', controller: 'dmsf_upload', action: 'upload_files'
post '/projects/:id/dmsf/upload/file', controller: 'dmsf_upload', action: 'upload_file'
post '/projects/:id/dmsf/upload', controller: 'dmsf_upload', action: 'upload'
post '/projects/:id/dmsf/upload/commit', controller: 'dmsf_upload', action: 'commit_files'

View File

@ -0,0 +1,28 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011-20 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.
class AddIndexesOnDmsfFolderId < ActiveRecord::Migration[5.2]
def change
add_index :dmsf_files, :dmsf_folder_id
add_index :dmsf_links, :dmsf_folder_id
end
end

View File

@ -76,7 +76,7 @@ module RedmineDmsf
else
tag = "<span class=\"dmsf_expander\" onclick=\"dmsfToggle('#{item.id}','#{item.id}span','#{escape_javascript(expand_folder_dmsf_path)}')\"></span>".html_safe +
link_to(h(value),
dmsf_folder_path(id: item.project_id, folder_id: item.id),
dmsf_folder_path(id: item.project, folder_id: item.id),
class: 'icon icon-folder',
title: h(value))
end
@ -86,8 +86,9 @@ module RedmineDmsf
tag = content_tag('span', value, class: 'icon icon-folder')
else
tag = "<span class=\"dmsf_expander\"></span>".html_safe +
# For links we use revision_id containing dmsf_folder.id in fact
link_to(h(value),
dmsf_folder_path(id: item.project_id, folder_id: item.id),
dmsf_folder_path(id: item.project, folder_id: item.revision_id),
class: 'icon icon-folder',
title: h(value))
end
@ -96,7 +97,8 @@ module RedmineDmsf
if item.deleted && (item.deleted > 0)
tag = content_tag('span', value, class: "icon icon-file #{DmsfHelper.filetype_css(item.filename)}")
else
file_view_url = url_for({ controller: :dmsf_files, action: 'view', id: item.id })
# For links we use revision_id containing dmsf_file.id in fact
file_view_url = url_for({ controller: :dmsf_files, action: 'view', id: (item.type == 'file') ? item.id : item.revision_id })
content_type = Redmine::MimeType.of(value)
content_type = 'application/octet-stream' if content_type.blank?
tag = "<span class=\"dmsf_expander\"></span>".html_safe +

View File

@ -31,7 +31,7 @@ module RedmineDmsf
def initialize(path, request, response, options)
@folder = nil
@file = nil
super(path, request, response, options)
super path, request, response, options
end
# Here we make sure our folder and file methods are not aliased - it should shave a few cycles off of processing
@ -227,64 +227,52 @@ module RedmineDmsf
resource = dest.is_a?(ResourceProxy) ? dest.resource : dest
return PreconditionFailed if !resource.is_a?(DmsfResource) || resource.project.nil?
parent = resource.parent
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder, false))
if !parent.exist? || (!User.current.admin? && (!DmsfFolder.permissions?(folder, false) ||
!DmsfFolder.permissions?(parent.folder, false)))
raise Forbidden
end
if collection?
if dest.exist?
return overwrite ? NotImplemented : PreconditionFailed
end
# At the moment we don't support cross project destinations
return NotImplemented unless (project.id == resource.project.id)
raise Forbidden unless User.current.admin? || User.current.allowed_to?(:folder_manipulation, project)
raise Forbidden unless DmsfFolder.permissions?(folder, false)
if !User.current.admin? && (!User.current.allowed_to?(:folder_manipulation, project) ||
!User.current.allowed_to?(:folder_manipulation, resource.project))
raise Forbidden
end
# Current object is a folder, so now we need to figure out information about Destination
if dest.exist?
return overwrite ? NotImplemented : PreconditionFailed
else
if parent.projectless_path == '/' # Project root
folder.dmsf_folder_id = nil
else
return PreconditionFailed unless parent.exist? && parent.folder
folder.dmsf_folder_id = parent.folder.id
end
folder.title = resource.basename
folder.save ? Created : PreconditionFailed
folder.move_to(resource.project, parent.folder) ? Created : PreconditionFailed
end
else
raise Forbidden unless User.current.admin? ||
User.current.allowed_to?(:folder_manipulation, project) ||
User.current.allowed_to?(:folder_manipulation, resource.project)
if !User.current.admin? && (!User.current.allowed_to?(:file_manipulation, project) ||
!User.current.allowed_to?(:file_manipulation, resource.project))
raise Forbidden
end
if dest.exist?
return PreconditionFailed unless overwrite
if (project == resource.project) && file.name.match(/.\.tmp$/i)
# Renaming a *.tmp file to an existing file in the same project, probably Office that is saving a file.
Rails.logger.info "WebDAV MOVE: #{file.name} -> #{resource.basename} (exists), possible MSOffice rename from .tmp when saving"
if resource.file.last_revision.size == 0 || reuse_version_for_locked_file(resource.file)
# Last revision in the destination has zero size so reuse that revision
new_revision = resource.file.last_revision
else
# Create a new revison by cloning the last revision in the destination
new_revision = resource.file.last_revision.clone
new_revision.increase_version(1)
new_revision.increase_version 1
end
# The file on disk must be renamed from .tmp to the correct filetype or else Xapian won't know how to index.
# Copy file.last_revision.disk_file to new_revision.disk_file
new_revision.size = file.last_revision.size
new_revision.disk_filename = new_revision.new_storage_filename
Rails.logger.info "WebDAV MOVE: Copy file #{file.last_revision.disk_filename} -> #{new_revision.disk_filename}"
File.open(file.last_revision.disk_file, 'rb') do |f|
new_revision.copy_file_content(f)
new_revision.copy_file_content f
end
# Save
new_revision.save && resource.file.save
# Delete (and destroy) the file that should have been renamed and return what should have been returned in case of a copy
file.delete(true) ? Created : PreconditionFailed
else
@ -300,11 +288,10 @@ module RedmineDmsf
f = parent.folder
end
return PreconditionFailed unless exist? && file
if (project == resource.project) && resource.basename.match(/.\.tmp$/i)
Rails.logger.info "WebDAV MOVE: #{file.name} -> #{resource.basename}, possible MSOffice rename to .tmp when saving."
# Renaming the file to X.tmp, might be Office that is saving a file. Keep the original file.
file.copy_to_filename(resource.project, f, resource.basename)
file.copy_to_filename resource.project, f, resource.basename
Created
else
if (project == resource.project) && (file.last_revision.size == 0)
@ -313,14 +300,12 @@ module RedmineDmsf
else
return InternalServerError unless file.move_to(resource.project, f)
end
# Update Revision and names of file [We can link to old physical resource, as it's not changed]
if file.last_revision
file.last_revision.name = resource.basename
file.last_revision.title = DmsfFileRevision.filename_to_title(resource.basename)
end
file.name = resource.basename
# Save Changes
(file.last_revision.save && file.save) ? Created : PreconditionFailed
end

View File

@ -190,3 +190,25 @@ dmsf_file_revisions_009:
dmsf_workflow_assigned_by_user_id: NULL
dmsf_workflow_started_by_user_id: NULL
created_at: 2017-04-18 14:52:27 +02:00
dmsf_file_revisions_010:
id: 10
dmsf_file_id: 5
source_dmsf_file_revision_id: NULL
name: "test.txt"
disk_filename: "test.txt"
size: 4
mime_type: text/plain
title: "Test File"
description: 'Some file :-)'
workflow: 1 # DmsfWorkflow::STATE_WAITING_FOR_APPROVAL
minor_version: 0
major_version: 1
comment: NULL
deleted: 0
deleted_by_user_id: NULL
user_id: 1
dmsf_workflow_assigned_by_user_id: 1
dmsf_workflow_started_by_user_id: 1
digest: '81dc9bdb52d04dc20036dbd8313ed055'
created_at: 2017-04-18 14:52:27 +02:00

View File

@ -253,9 +253,10 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
def test_show_folder_doesnt_correspond_the_project
@role.add_permission! :view_dmsf_files
@role.add_permission! :view_dmsf_folders
# project1 X project2.folder3
# Despite the fact that project != @folder3.project
assert @project != @folder3.project
get :show, params: { id: @project.id, folder_id: @folder3.id }
assert_response :not_found
assert_response :success
end
def test_new_forbidden

View File

@ -170,6 +170,12 @@ class DmsfFoldersCopyControllerTest < RedmineDmsf::Test::TestCase
assert_nil flash[:error]
end
def test_move_to_another_project
post :move, params: { id: @folder1.id, target_project_id: @project2.id, target_folder_id: 'Documents' }
assert_response :redirect
assert_nil flash[:error]
end
def test_move_the_same_target
post :move, params: { id: @folder1.id, target_project_id: @folder1.project.id, target_folder_id: @folder1.dmsf_folder }
assert_equal flash[:error], l(:error_target_folder_same)

View File

@ -322,7 +322,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase
type: 'link_to'
}}
end
assert_redirected_to edit_dmsf_path(id: @project1.id, folder_id: @folder1.id)
assert_redirected_to dmsf_folder_path(id: @project1, folder_id: @folder1.dmsf_folder)
end
def test_create_folder_link_to_f2
@ -337,7 +337,7 @@ class DmsfLinksControllerTest < RedmineDmsf::Test::TestCase
type: 'link_to'
}}
end
assert_redirected_to edit_dmsf_path(id: @project1.id, folder_id: @folder1.id)
assert_redirected_to dmsf_folder_path(id: @project1, folder_id: @folder1.dmsf_folder)
end
def test_destroy

View File

@ -37,13 +37,16 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
@jsmith_user = User.find_by(login: 'jsmith')
@admin_user = User.find_by(login: 'admin')
@project1 = Project.find 1
@project1.enable_module! :dmsf
@project2 = Project.find 2
@project2.enable_module! :dmsf
@file1 = DmsfFile.find 1
@file10 = DmsfFile.find 10
@folder1 = DmsfFolder.find 1
# Fix permissions for jsmith's role
@role = Role.find 1 #
@role = Role.find 1
@role.add_permission! :view_dmsf_folders
@role.add_permission! :folder_manipulation
@role.add_permission! :file_manipulation
@dmsf_webdav = Setting.plugin_redmine_dmsf['dmsf_webdav']
Setting.plugin_redmine_dmsf['dmsf_webdav'] = true
@dmsf_webdav_strategy = Setting.plugin_redmine_dmsf['dmsf_webdav_strategy']
@ -68,6 +71,7 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
def test_truth
assert_kind_of Project, @project1
assert_kind_of Project, @project2
assert_kind_of Role, @role
assert_kind_of DmsfFile, @file1
assert_kind_of DmsfFile, @file10
@ -85,8 +89,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
end
end
def test_move_to_new_filename_without_folder_manipulation_permission
@role.remove_permission! :folder_manipulation
def test_move_to_new_filename_without_file_manipulation_permission
@role.remove_permission! :file_manipulation
new_name = "#{@file1.name}.moved"
assert_no_difference '@file1.dmsf_file_revisions.count' do
process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", params: nil,
@ -95,8 +99,8 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
end
end
def test_move_to_new_filename_without_folder_manipulation_permission_as_admin
@role.remove_permission! :folder_manipulation
def test_move_to_new_filename_without_file_manipulation_permission_as_admin
@role.remove_permission! :file_manipulation
new_name = "#{@file1.name}.moved"
assert_difference '@file1.dmsf_file_revisions.count', +1 do
process :move, "/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", params: nil,
@ -107,6 +111,37 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
end
end
def test_without_folder_manipulation_permission
@role.remove_permission! :folder_manipulation
new_name = "#{@folder1.title}.moved"
process :move, "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", params: nil,
headers: @jsmith.merge!({ destination: "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}" })
assert_response :forbidden
end
def test_without_folder_manipulation_permission_as_admin
@role.remove_permission! :folder_manipulation
new_name = "#{@folder1.title}.moved"
process :move, "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", params: nil,
headers: @admin.merge!({ destination: "http://www.example.com/dmsf/webdav/#{@project1.identifier}/#{new_name}" })
assert_response :created
end
def test_move_folder_to_another_project
process :move, "/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}", params: nil,
headers: @admin.merge!({ destination: "http://www.example.com/dmsf/webdav/#{@project2.identifier}/#{@folder1.title}" })
assert_response :created
@folder1.dmsf_folders.each do |d|
assert_equal @project2, d.project
end
@folder1.dmsf_files.each do |f|
assert_equal @project2, f.project
end
@folder1.dmsf_links.each do |l|
assert_equal @project2, l.project
end
end
def test_move_non_existent_file
process :move, "/dmsf/webdav/#{@project1.identifier}/not_a_file.txt", params: nil,
headers: @jsmith.merge!({ destination: "http://www.example.com/dmsf/webdav/#{@project1.identifier}/moved_file.txt" })

View File

@ -27,8 +27,10 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
:dmsf_folder_permissions
def setup
@project = Project.find 1
@project.enable_module! :dmsf
@project1 = Project.find 1
@project1.enable_module! :dmsf
@project2 = Project.find 2
@project2.enable_module! :dmsf
@folder1 = DmsfFolder.find 1
@folder2 = DmsfFolder.find 2
@folder4 = DmsfFolder.find 4
@ -51,7 +53,8 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert_kind_of DmsfFolder, @folder5
assert_kind_of DmsfFolder, @folder6
assert_kind_of DmsfFolder, @folder7
assert_kind_of Project, @project
assert_kind_of Project, @project1
assert_kind_of Project, @project2
assert_kind_of User, @manager
assert_kind_of User, @developer
assert_kind_of Role, @manager_role
@ -69,7 +72,7 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert_equal 4, DmsfFolder.visible.where(project_id: 1).all.size
# Anonymous user
User.current = User.anonymous
@project.add_default_member User.anonymous
@project1.add_default_member User.anonymous
assert_equal 5, DmsfFolder.visible.where(project_id: 1).all.size
end
@ -145,7 +148,7 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
end
def test_directory_tree
tree = DmsfFolder.directory_tree(@project)
tree = DmsfFolder.directory_tree(@project1)
assert tree
# [["Documents", nil],
# ["...folder7", 7],
@ -157,7 +160,7 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
end
def test_directory_tree_id
tree = DmsfFolder.directory_tree(@project.id)
tree = DmsfFolder.directory_tree(@project1.id)
assert tree
# [["Documents", nil],
# ["...folder7", 7],
@ -193,4 +196,23 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
assert_equal 1, users.size
end
def test_move_to
assert @folder1.move_to(@project2, nil)
assert_equal @project2, @folder1.project
@folder1.dmsf_folders.each do |d|
assert_equal @project2, d.project
end
@folder1.dmsf_files.each do |f|
assert_equal @project2, f.project
end
@folder1.dmsf_links.each do |l|
assert_equal @project2, l.project
end
end
def test_copy_to
assert @folder1.copy_to(@project2, nil)
assert DmsfFolder.find_by_title(@project2, nil, @folder1.title)
end
end

View File

@ -163,8 +163,8 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest
end
def test_folder
assert_equal @folder1, @file_link.folder
assert_nil @folder_link.folder
assert_equal @folder1, @file_link.dmsf_folder
assert_nil @folder_link.dmsf_folder
end
def test_title
@ -174,7 +174,7 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest
def test_find_link_by_file_name
file_link = DmsfLink.find_link_by_file_name(@file_link.project,
@file_link.folder, @file_link.target_file.name)
@file_link.dmsf_folder, @file_link.target_file.name)
assert file_link, 'File link not found by its name'
end