#48 Attached documents available in the DMS view

This commit is contained in:
Karel Picman 2017-04-26 12:08:53 +02:00
parent 208b8b1ae7
commit c1a5939c7c
56 changed files with 400 additions and 274 deletions

View File

@ -38,7 +38,7 @@ class DmsfController < ApplicationController
helper :dmsf_folder_permissions
def permissions
render_403 unless DmsfFolder.permissions(@folder)
render_403 unless DmsfFolder.permissions?(@folder)
true
end
@ -80,7 +80,7 @@ class DmsfController < ApplicationController
@file_manipulation_allowed = User.current.allowed_to? :file_manipulation, @project
@file_delete_allowed = User.current.allowed_to? :file_delete, @project
@subfolders = DmsfFolder.deleted.where(:project_id => @project.id)
@files = DmsfFile.deleted.where(:container_id => @project.id, :container_type => 'Project')
@files = DmsfFile.deleted.where(:project_id => @project.id)
@dir_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s)
@file_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s)
@url_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => 'DmsfUrl')
@ -643,6 +643,7 @@ class DmsfController < ApplicationController
private
def get_display_params
@system_folder = @folder && @folder.system
@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)
@ -658,7 +659,7 @@ class DmsfController < ApplicationController
if tag
@subfolders = []
folder_id = @folder.id if @folder
DmsfFolder.where(:project_id => @project.id, :dmsf_folder_id => folder_id).visible.each do |f|
DmsfFolder.where(:project_id => @project.id, :dmsf_folder_id => folder_id, :system => false).visible.each do |f|
f.custom_field_values.each do |v|
if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field.compare_values?(v.value, params[:custom_value])
@ -669,7 +670,7 @@ class DmsfController < ApplicationController
end
end
@files = []
DmsfFile.where(:container_id => @project.id, :container_type => 'Project', :dmsf_folder_id => folder_id).visible.each do |f|
DmsfFile.where(:project_id => @project.id, :dmsf_folder_id => folder_id).visible.each do |f|
r = f.last_revision
if r
r.custom_field_values.each do |v|
@ -733,7 +734,7 @@ class DmsfController < ApplicationController
@trash_visible = @folder_manipulation_allowed && @file_manipulation_allowed &&
@file_delete_allowed && !@locked_for_user && !@folder
@trash_enabled = DmsfFolder.deleted.where(:project_id => @project.id).any? ||
DmsfFile.deleted.where(:container_id => @project.id, :container_type => 'Project').any? ||
DmsfFile.deleted.where(:project_id => @project.id).any? ||
DmsfLink.deleted.where(:project_id => @project.id).any?
end

View File

@ -38,7 +38,7 @@ class DmsfFilesController < ApplicationController
def permissions
if @file
render_403 unless DmsfFolder.permissions(@file.dmsf_folder)
render_403 unless DmsfFolder.permissions?(@file.dmsf_folder)
end
true
end
@ -192,7 +192,7 @@ class DmsfFilesController < ApplicationController
commit = params[:commit] == 'yes'
if @file.delete(commit)
flash[:notice] = l(:notice_file_deleted)
if commit && (@file.container_type == 'Project')
if commit
log_activity('deleted')
begin
recipients = DmsfMailer.get_notify_users(@project, [@file])

View File

@ -27,7 +27,7 @@ class DmsfFolderPermissionsController < ApplicationController
before_filter :permissions
def permissions
render_403 unless DmsfFolder.permissions(@dmsf_folder)
render_403 unless DmsfFolder.permissions?(@dmsf_folder)
true
end

View File

@ -26,7 +26,7 @@ class DmsfFoldersCopyController < ApplicationController
before_filter :permissions
def permissions
render_403 unless DmsfFolder.permissions(@folder)
render_403 unless DmsfFolder.permissions?(@folder)
true
end

View File

@ -29,7 +29,7 @@ class DmsfLinksController < ApplicationController
def permissions
if @dmsf_link
render_403 unless DmsfFolder.permissions(@dmsf_link.dmsf_folder)
render_403 unless DmsfFolder.permissions?(@dmsf_link.dmsf_folder)
end
true
end

View File

@ -36,7 +36,7 @@ class DmsfUploadController < ApplicationController
accept_api_auth :upload, :commit
def permissions
render_403 unless DmsfFolder.permissions(@folder)
render_403 unless DmsfFolder.permissions?(@folder)
true
end

View File

@ -32,7 +32,7 @@ class DmsfWorkflowsController < ApplicationController
def permissions
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id] if params[:dmsf_file_revision_id].present?
if revision
render_403 unless revision.dmsf_file || DmsfFolder.permissions(revision.dmsf_file.dmsf_folder)
render_403 unless revision.dmsf_file || DmsfFolder.permissions?(revision.dmsf_file.dmsf_folder)
end
true
end

View File

@ -21,20 +21,15 @@
module DmsfUploadHelper
include Redmine::I18n
def self.commit_files_internal(commited_files, container, folder, controller)
def self.commit_files_internal(commited_files, project, folder, controller)
failed_uploads = []
files = []
if container.is_a?(Project)
project = container
else
project = container.project
end
if commited_files && commited_files.is_a?(Hash)
failed_uploads = []
commited_files.each_value do |commited_file|
name = commited_file[:name]
new_revision = DmsfFileRevision.new
file = DmsfFile.visible.find_file_by_name(container, folder, name)
file = DmsfFile.visible.find_file_by_name(project, folder, name)
unless file
link = DmsfLink.find_link_by_file_name(project, folder, name)
file = link.target_file if link
@ -42,8 +37,7 @@ module DmsfUploadHelper
unless file
file = DmsfFile.new
file.container_type = container.class.name.demodulize
file.container_id = container.id
file.project_id = project.id
file.name = name
file.dmsf_folder = folder
file.notification = Setting.plugin_redmine_dmsf[:dmsf_default_notifications].present?
@ -119,7 +113,7 @@ module DmsfUploadHelper
failed_uploads.push(commited_file)
end
end
if container.is_a?(Project) && ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
if ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
begin
recipients = DmsfMailer.get_notify_users(project, files)
recipients.each do |u|

View File

@ -32,6 +32,7 @@ class DmsfFile < ActiveRecord::Base
include RedmineDmsf::Lockable
belongs_to :project
belongs_to :dmsf_folder
belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id'
@ -58,7 +59,7 @@ class DmsfFile < ActiveRecord::Base
attr_accessible :project, :project_id
def validates_name_uniqueness
existing_file = DmsfFile.visible.findn_file_by_name(self.container_id, self.container_type, self.dmsf_folder, self.name)
existing_file = DmsfFile.visible.findn_file_by_name(self.project_id, self.dmsf_folder, self.name)
errors.add(:name, l('activerecord.errors.messages.taken')) unless (existing_file.nil? || existing_file.id == self.id)
end
@ -120,14 +121,13 @@ class DmsfFile < ActiveRecord::Base
@@storage_path = path
end
def self.find_file_by_name(container, folder, name)
self.findn_file_by_name(container.id, container.class.name.demodulize, folder, name)
def self.find_file_by_name(project, folder, name)
self.findn_file_by_name(project.id, folder, name)
end
def self.findn_file_by_name(container_id, container_type, folder, name)
def self.findn_file_by_name(project_id, folder, name)
where(
:container_id => container_id,
:container_type => container_type,
:project_id => project_id,
:dmsf_folder_id => folder ? folder.id : nil,
:name => name).visible.first
end
@ -249,19 +249,17 @@ class DmsfFile < ActiveRecord::Base
projects
end
def move_to(container, folder)
def move_to(project, folder)
if self.locked_for_user?
errors[:base] << l(:error_file_is_locked)
return false
end
# Must invalidate source parent folder cache before moving
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
self.container_type = self.container_type
self.container_id = container.id
self.project_id = project.id
self.dmsf_folder = folder
new_revision = self.last_revision.clone
new_revision.dmsf_file = self
project = container.is_a?(Project) ? container : container.project
new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}")
new_revision.custom_values = []
self.last_revision.custom_values.each do |cv|
@ -271,15 +269,14 @@ class DmsfFile < ActiveRecord::Base
self.save && new_revision.save
end
def copy_to(container, folder = nil)
copy_to_filename(container, folder, self.name)
def copy_to(project, folder = nil)
copy_to_filename(project, folder, self.name)
end
def copy_to_filename(container, folder=nil, filename)
def copy_to_filename(project, folder, filename)
file = DmsfFile.new
file.dmsf_folder = folder
file.container_type = self.container_type
file.container_id = container.id
file.project_id = project.id
file.name = filename
file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present?
if file.save && self.last_revision
@ -289,7 +286,6 @@ class DmsfFile < ActiveRecord::Base
if File.exist? self.last_revision.disk_file
FileUtils.cp self.last_revision.disk_file, new_revision.disk_file
end
project = container.is_a?(Project) ? container : container.project
new_revision.comment = l(:comment_copied_from, :source => "#{project.identifier}: #{self.dmsf_path_str}")
new_revision.custom_values = []
self.last_revision.custom_values.each do |cv|
@ -325,8 +321,7 @@ class DmsfFile < ActiveRecord::Base
project_conditions << Project.allowed_to_condition(user, :view_dmsf_files)
project_conditions << "#{Project.table_name}.id IN (#{project_ids.join(',')})" if project_ids.present?
scope = self.visible.joins(:dmsf_file_revisions).joins(
"JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id AND #{DmsfFile.table_name}.container_type = 'Project'")
scope = self.visible.joins(:dmsf_file_revision).joins(:project)
scope = scope.limit(options[:limit]) unless options[:limit].blank?
scope = scope.where(limit_options) unless limit_options.blank?
scope = scope.where(project_conditions.join(' AND '))
@ -516,13 +511,11 @@ class DmsfFile < ActiveRecord::Base
end
def propfind_cache_key
if self.container_type == 'Project'
if dmsf_folder_id.nil?
# File is in project root
return "PROPFIND/#{self.container_id}"
else
return "PROPFIND/#{self.container_id}/#{self.dmsf_folder_id}"
end
unless dmsf_folder_id
# File is in project root
return "PROPFIND/#{self.project_id}"
else
return "PROPFIND/#{self.project_id}/#{self.dmsf_folder_id}"
end
end
@ -606,31 +599,6 @@ class DmsfFile < ActiveRecord::Base
csv
end
def project
unless @project
case self.container_type
when 'Project'
@project = Project.find_by_id(self.container_id)
when 'Issue'
issue = Issue.find_by_id(self.container_id)
@project = issue.project if issue
end
end
@project
end
def container
unless @container
case self.container_type
when 'Project'
@container = Project.find_by_id(self.container_id)
when 'Issue'
@container = Issue.find_by_id(self.container_id)
end
end
@container
end
def thumbnail(options={})
if image?
size = options[:size].to_i
@ -665,4 +633,10 @@ class DmsfFile < ActiveRecord::Base
l(:title_unlock_file)
end
def container
if self.dmsf_folder && self.dmsf_folder.system
Issue.where(:id => self.dmsf_folder.title.to_i).first
end
end
end

View File

@ -49,10 +49,8 @@ class DmsfFileRevision < ActiveRecord::Base
:timestamp => "#{DmsfFileRevision.table_name}.updated_at",
:author_key => "#{DmsfFileRevision.table_name}.user_id",
:permission => :view_dmsf_file_revisions,
:scope => select("#{DmsfFileRevision.table_name}.*").
joins(:dmsf_file).joins(
"LEFT JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id").
where("#{DmsfFile.table_name}.container_type = ?", 'Project').visible
:scope => select("#{DmsfFileRevision.table_name}.*").joins(:dmsf_file).
joins("JOIN #{Project.table_name} ON #{Project.table_name}.id = #{DmsfFile.table_name}.project_id").visible
validates :title, :presence => true
validates_format_of :name, :with => DmsfFolder::INVALID_CHARACTERS,

View File

@ -41,8 +41,6 @@ class DmsfFileRevisionAccess < ActiveRecord::Base
:author_key => "#{DmsfFileRevisionAccess.table_name}.user_id",
:permission => :view_dmsf_file_revision_accesses,
:scope => select("#{DmsfFileRevisionAccess.table_name}.*").
joins(:dmsf_file_revision).joins(
"LEFT JOIN #{DmsfFile.table_name} ON #{DmsfFileRevision.table_name}.dmsf_file_id = #{DmsfFile.table_name}.id " +
"LEFT JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id").
where("#{DmsfFile.table_name}.deleted = ? AND #{DmsfFile.table_name}.container_type = ?", DmsfFile::STATUS_ACTIVE, 'Project')
joins(:dmsf_file_revision).joins(:dmsf_file).
where(["#{DmsfFile.table_name}.deleted = ?", DmsfFile::STATUS_ACTIVE])
end

View File

@ -50,14 +50,15 @@ class DmsfFolder < ActiveRecord::Base
AVAILABLE_COLUMNS = %w(id title extension size modified version workflow author).freeze
DEFAULT_COLUMNS = %w(title size modified version workflow author).freeze
scope :visible, -> { joins(:project).joins(
scope :visible, -> (system=true) { joins(:project).joins(
"LEFT JOIN #{DmsfFolderPermission.table_name} ON #{DmsfFolder.table_name}.id = #{DmsfFolderPermission.table_name}.dmsf_folder_id").where(
:deleted => STATUS_ACTIVE).where(DmsfFolder.visible_condition).distinct
:deleted => STATUS_ACTIVE).where(DmsfFolder.visible_condition(system)).distinct
}
scope :deleted, -> { joins(:project).joins(
"LEFT JOIN #{DmsfFolderPermission.table_name} ON #{DmsfFolder.table_name}.id = #{DmsfFolderPermission.table_name}.dmsf_folder_id").where(
:deleted => STATUS_DELETED).where(DmsfFolder.visible_condition).distinct
}
scope :system, -> { where(:system => true) }
acts_as_customizable
@ -83,8 +84,8 @@ class DmsfFolder < ActiveRecord::Base
before_create :default_values
def self.visible_condition
Project.allowed_to_condition(User.current, :view_dmsf_folders) do |role, user|
def self.visible_condition(system=true)
sql = Project.allowed_to_condition(User.current, :view_dmsf_folders) do |role, user|
if user.id && user.logged?
%{
(#{DmsfFolderPermission.table_name}.object_id IS NULL) OR
@ -92,14 +93,16 @@ class DmsfFolder < ActiveRecord::Base
(#{DmsfFolderPermission.table_name}.object_id = #{user.id} AND #{DmsfFolderPermission.table_name}.object_type = 'User')
}
else
'0=1'
'0 = 1'
end
end
"#{sql} AND (#{DmsfFolder.table_name}.system = 0 OR 1 = #{(system && Setting.plugin_redmine_dmsf['dmsf_show_system_folders']) ? 1 : 0})"
end
def self.permissions(folder)
def self.permissions?(folder, allow_system = true)
return false if folder && folder.system && (!allow_system || !Setting.plugin_redmine_dmsf['dmsf_show_system_folders'])
return true if (User.current.admin? || folder.nil?)
if !folder.dmsf_folder || permissions(folder.dmsf_folder)
if !folder.dmsf_folder || permissions?(folder.dmsf_folder, allow_system)
if folder.dmsf_folder_permissions.any?
role_ids = User.current.roles_for_project(folder.project).map{ |r| r.id }
role_permission_ids = folder.dmsf_folder_permissions.roles.map{ |p| p.object_id }
@ -205,7 +208,7 @@ class DmsfFolder < ActiveRecord::Base
def self.directory_tree(project, current_folder = nil)
tree = [[l(:link_documents), nil]]
project.dmsf_folders.visible.each do |folder|
project.dmsf_folders.visible(false).each do |folder|
unless folder == current_folder
tree.push(["...#{folder.title}", folder.id])
directory_subtree(tree, folder, 2, current_folder)
@ -316,8 +319,8 @@ class DmsfFolder < ActiveRecord::Base
self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = time if time
time = DmsfFile.where(
['container_id = ? AND container_type = ? AND dmsf_folder_id = ? AND updated_at > ?',
self.project_id, 'Project', self.id, last_update]).maximum(:updated_at)
['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = time if time
time = DmsfLink.where(
['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
@ -329,7 +332,7 @@ class DmsfFolder < ActiveRecord::Base
# Number of items in the folder
def items
dmsf_folders.visible.where(:project_id => self.project_id).count +
dmsf_files.visible.where(:container_id => self.project_id).count +
dmsf_files.visible.where(:project_id => self.project_id).count +
dmsf_links.visible.where(:project_id => self.project_id).count
end
@ -351,6 +354,10 @@ class DmsfFolder < ActiveRecord::Base
end
def self.get_column_position(column)
unless @@dmsf_columns
@@dmsf_columns = Setting.plugin_redmine_dmsf['dmsf_columns']
@@dmsf_columns = DmsfFolder::DEFAULT_COLUMNS unless columns
end
pos = 0
# 0 - checkbox
# 1 - id
@ -517,7 +524,7 @@ class DmsfFolder < ActiveRecord::Base
private
def self.directory_subtree(tree, folder, level, current_folder)
folder.dmsf_folders.visible.each do |subfolder|
folder.dmsf_folders.visible(false).each do |subfolder|
unless subfolder == current_folder
tree.push(["#{'...' * level}#{subfolder.title}", subfolder.id])
directory_subtree(tree, subfolder, level + 1, current_folder)

View File

@ -76,8 +76,7 @@ class DmsfUpload
@minor_version = 0
@workflow = nil
file = DmsfFile.new
file.container_type = 'Project'
file.container_id = project.id
file.project_id = project.id
revision = DmsfFileRevision.new
revision.dmsf_file = file
@custom_values = revision.custom_field_values

View File

@ -106,8 +106,8 @@ class DmsfWorkflow < ActiveRecord::Base
def delegates(q, dmsf_workflow_step_assignment_id, dmsf_file_revision_id)
if dmsf_workflow_step_assignment_id && dmsf_file_revision_id
sql = [
'id NOT IN (SELECT a.user_id FROM dmsf_workflow_step_assignments a WHERE id = ?) AND id IN (SELECT m.user_id FROM members m JOIN dmsf_files f ON f.container_id = m.project_id JOIN dmsf_file_revisions r ON r.dmsf_file_id = f.id WHERE r.id = ? AND container_type = ?)',
dmsf_workflow_step_assignment_id, dmsf_file_revision_id, 'Project']
'id NOT IN (SELECT a.user_id FROM dmsf_workflow_step_assignments a WHERE id = ?) AND id IN (SELECT m.user_id FROM members m JOIN dmsf_files f ON f.project_id = m.project_id JOIN dmsf_file_revisions r ON r.dmsf_file_id = f.id WHERE r.id = ?)',
dmsf_workflow_step_assignment_id, dmsf_file_revision_id]
elsif project
sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?)', project.id]
else

View File

@ -20,8 +20,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<td class="dmsf_checkbox"><%= check_box_tag(name, id, false,
:title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %></td>
<td class="dmsf_checkbox">
<% unless (subfolder && subfolder.system) %>
<%= check_box_tag(name, id, false, :title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %>
<% end %>
</td>
<% if DmsfFolder.is_column_on?('id') %>
<td class="id"><%= link_to(subfolder.id, edit_dmsf_path(:id => project, :folder_id => subfolder)) %></td>
<% end %>
@ -68,7 +71,7 @@
<% end %>
<% end %>
<td class="dmsf_buttons">
<% if @folder_manipulation_allowed %>
<% if @folder_manipulation_allowed && !(subfolder && subfolder.system) %>
<% if subfolder && subfolder.locked? %>
<span class="icon"></span>
<% if subfolder.unlockable? && (!subfolder.locked_for_user? || @force_file_unlock_allowed) %>

View File

@ -19,6 +19,7 @@
<% end %>
<% if obj.is_a? DmsfFolder %>
<% classes << ' dmsf_system' if obj.system %>
<tr <%= id %> class="dir <%= classes %>">
<%= render(:partial => 'dir',
:locals => {

View File

@ -133,46 +133,9 @@
<span class="icon"></span>
<% end %>
<% end %>
<% if @file_approval_allowed %>
<% case file.last_revision.workflow %>
<% when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL %>
<% if wf %>
<% assignments = wf.next_assignments(file.last_revision.id) %>
<% index = assignments.find_index{|assignment| assignment.user_id == User.current.id} if assignments %>
<% if index %>
<%= link_to('',
action_dmsf_workflow_path(
:project_id => project.id,
:id => wf.id,
:dmsf_workflow_step_assignment_id => assignments[index].id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:title_waiting_for_approval),
:remote => true,
:class => 'icon icon-wf-waiting') %>
<% end %>
<% end %>
<% when DmsfWorkflow::STATE_ASSIGNED %>
<% if User.current && (file.last_revision.dmsf_workflow_assigned_by == User.current.id) && wf %>
<%= link_to('',
start_dmsf_workflow_path(
:id => file.last_revision.dmsf_workflow_id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_start),
:class => 'icon icon-wf-assigned') %>
<% end %>
<% when DmsfWorkflow::STATE_APPROVED, DmsfWorkflow::STATE_REJECTED %>
<% else %>
<% if @workflows_available %>
<%= link_to('',
assign_dmsf_workflow_path(
:project_id => project.id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_assign),
:remote => true,
:class => 'icon icon-wf-none') %>
<% end %>
<% end %>
<% end %>
<%= render(:partial => 'dmsf_files/approval_workflow_button',
:locals => {:file => file, :file_approval_allowed => @file_approval_allowed,
:workflows_available => @workflows_available, :project => project, :wf => wf }) %>
</td>
<td class="hol"><%= position %></td>
<td class="hol"><%= file.last_revision.size %></td>

View File

@ -65,7 +65,7 @@
</thead>
<tbody>
<% @subfolders.each do |subfolder| %>
<tr class="dir">
<tr class="dir <%= 'dmsf_system' if subfolder.system %>">
<%= render(:partial => 'dir',
:locals => {
:project => @project,

View File

@ -25,7 +25,7 @@
<% html_title(l(:dmsf)) %>
<div class="contextual">
<% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) %>
<% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) && !@folder.system %>
<% unless @folder.locked? %>
<%= link_to(l(:button_lock), lock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_lock_file), :class => 'icon icon-lock') %>

View File

@ -24,7 +24,7 @@
<% html_title l(:dmsf) %>
<div class="contextual">
<% if @folder_manipulation_allowed %>
<% if @folder_manipulation_allowed && !@system_folder %>
<% if @folder.nil? %>
<%= link_to(l(:button_edit), edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)),
@ -92,16 +92,18 @@
<%= submit_tag(l(:button_delete), :title => l(:title_delete_checked), :name => 'delete_entries') if @file_delete_allowed %>
<% end %>
</div>
<% values = @folder ? @folder.custom_field_values : DmsfFolder.new.custom_field_values %>
<% unless values.empty? %>
<div id="dmsf_tag" class="dmsf_controls" style="float: right">
<% custom_value = values.first %>
<% custom_value.custom_field.is_required = false %>
<% custom_value.value = params[:custom_value].present? ? params[:custom_value] : '' %>
<% name = :dmsf_folder %>
<%= content_tag('label', custom_field_name_tag(custom_value.custom_field),
:for => "#{name}_custom_field_values_#{custom_value.custom_field.id}") + ': ' + custom_field_tag(name, custom_value) %>
</div>
<% unless @system_folder %>
<% values = @folder ? @folder.custom_field_values : DmsfFolder.new.custom_field_values %>
<% unless values.empty? %>
<div id="dmsf_tag" class="dmsf_controls" style="float: right">
<% custom_value = values.first %>
<% custom_value.custom_field.is_required = false %>
<% custom_value.value = params[:custom_value].present? ? params[:custom_value] : '' %>
<% name = :dmsf_folder %>
<%= content_tag('label', custom_field_name_tag(custom_value.custom_field),
:for => "#{name}_custom_field_values_#{custom_value.custom_field.id}") + ': ' + custom_field_tag(name, custom_value) %>
</div>
<% end %>
<% end %>
<div class="autoscroll">
<% if @tree_view %>
@ -181,7 +183,7 @@
<% if @folder %>
return "<%= "#{l(:label_number_of_folders)}: #{@folder.deep_folder_count} #{l(:label_number_of_documents)}: #{@folder.deep_file_count}" %>";
<% else %>
return "<%= "#{l(:label_number_of_folders)}: #{DmsfFolder.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFolder').count}, #{l(:label_number_of_documents)}: #{DmsfFile.visible.where(:container_id => @project.id, :container_type => 'Project').count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFile').count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfUrl').count}" %>";
return "<%= "#{l(:label_number_of_folders)}: #{DmsfFolder.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFolder').count}, #{l(:label_number_of_documents)}: #{DmsfFile.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => ['DmsfFile', 'DmsfUrl']).count}" %>";
<% end %>
<% else %>
return "<%= "#{l(:label_number_of_folders)}: #{@subfolders.count + @dir_links.count}, #{l(:label_number_of_documents)}: #{@files.count + @file_links.count + @url_links.count}" %>";
@ -207,12 +209,14 @@
</script>
<% end %>
<% if (@file_manipulation_allowed && !@locked_for_user) %>
<% if (@file_manipulation_allowed && !@locked_for_user && !@system_folder) %>
<%= render(:partial => 'dmsf_upload/multi_upload') %>
<% end %>
<% other_formats_links do |f| %>
<% unless @system_folder %>
<% other_formats_links do |f| %>
<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% end %>
<% end %>
<div id="csv-export-options" style="display:none;">

View File

@ -0,0 +1,62 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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 file_approval_allowed %>
<% case file.last_revision.workflow %>
<% when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL %>
<% if wf %>
<% assignments = wf.next_assignments(file.last_revision.id) %>
<% index = assignments.find_index{|assignment| assignment.user_id == User.current.id} if assignments %>
<% if index %>
<%= link_to('',
action_dmsf_workflow_path(
:project_id => project.id,
:id => wf.id,
:dmsf_workflow_step_assignment_id => assignments[index].id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:title_waiting_for_approval),
:remote => true,
:class => 'icon icon-wf-waiting') %>
<% end %>
<% end %>
<% when DmsfWorkflow::STATE_ASSIGNED %>
<% if User.current && (file.last_revision.dmsf_workflow_assigned_by == User.current.id) && wf %>
<%= link_to('',
start_dmsf_workflow_path(
:id => file.last_revision.dmsf_workflow_id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_start),
:class => 'icon icon-wf-assigned') %>
<% end %>
<% when DmsfWorkflow::STATE_APPROVED, DmsfWorkflow::STATE_REJECTED %>
<% else %>
<% if workflows_available %>
<%= link_to('',
assign_dmsf_workflow_path(
:project_id => project.id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_assign),
:remote => true,
:class => 'icon icon-wf-none') %>
<% end %>
<% end %>
<% end %>

View File

@ -22,7 +22,7 @@
<% if dmsf_files.present? %>
<hr/>
<div class="attachments">
<div class="attachments dmsf_parent_container">
<% for dmsf_file in dmsf_files %>
<% if dmsf_file.last_revision %>
<p>
@ -50,6 +50,14 @@
:class => 'icon icon-del') %>
<% end %>
<span class="author"><%= dmsf_file.last_revision.user %>, <%= format_time(dmsf_file.last_revision.updated_at) %></span>
<span class="dmsf_upload_select">
<% wf = DmsfWorkflow.find_by_id(dmsf_file.last_revision.dmsf_workflow_id) if dmsf_file.last_revision.dmsf_workflow_id %>
<%= render(:partial => 'dmsf_files/approval_workflow_button',
:locals => {:file => dmsf_file,
:file_approval_allowed => User.current.allowed_to?(:file_approval, dmsf_file.project),
:workflows_available => DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', dmsf_file.project.id]).exists?,
:project => dmsf_file.project, :wf => wf }) %>
</span>
</p>
<% end %>
<% end %>

View File

@ -1,8 +1,7 @@
api.dmsf_file do
api.id @file.id
api.name @file.name
api.container_id @file.container_id
api.container_type @file.container_type
api.project_id @file.project_id
api.dmsf_folder_id @file.folder if @file.dmsf_folder_id
api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}" if @file.last_revision
api.content_url url_for(:controller => :dmsf_files, :action => 'show', :download => '', :id => @file)

View File

@ -152,10 +152,8 @@
<div class="status attribute">
<%= content_tag :div, l(:label_file), :class => 'label' %>
<div class="value">
<% if revision.dmsf_file.dmsf_folder %>
<%= (h("#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/")) %>
<% end %>
<%= h(revision.name) %>
<% path = "#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/" if revision.dmsf_file.dmsf_folder %>
<%= h("#{path}#{revision.name}") %>
</div>
</div>
<div class="status attribute">

View File

@ -137,6 +137,15 @@
</em>
</p>
<p>
<%= content_tag(:label, l(:label_show_system_folders)) %>
<%= check_box_tag('settings[dmsf_show_system_folders]', true, @settings['dmsf_show_system_folders']) %>
<em class="info">
<%= l(:note_dmsf_show_system_folders) %><br/>
<%= l(:label_default)%>: <%= l(:general_text_No)%>
</em>
</p>
<hr/>
<em class="info">
<%= l(:menu_dmsf) %> <%= l(:field_column_names) %>

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

View File

@ -194,6 +194,7 @@ div.dmsf_revision_inner_box .attribute .label {
/* File types */
.dmsf_gray .icon-folder { background-image: url(../images/folder_gray.png); }
.dmsf_system .icon-folder { background-image: url(../images/folder_system.png); }
.icon-file.filetype-doc, .icon-file.filetype-docx { background-image: url(../images/filetypes/doc.png); }
.icon-file.filetype-xls, .icon-file.filetype-xlsx { background-image: url(../images/filetypes/xls.png); }
@ -240,6 +241,10 @@ div.dmsf_revision_inner_box .attribute .label {
.dmsf_gray { color: #AAA }
.dmsf_gray a, .dmsf_gray a:link, .dmsf_gray a:visited{ color: #484848; text-decoration: none; }
/* System folders */
.dmsf_system { color: #5C82AD }
.dmsf_system a, .dmsf_gray a:link, .dmsf_gray a:visited{ color: #484848; text-decoration: none; }
/* Search results */
.dmsf-file { background-image: url(../../../images/document.png); }
.dmsf-folder { background-image: url(../../../images/folder.png); }

View File

@ -363,5 +363,7 @@ cs:
label_act_as_attachable: Jako příloha
note_dmsf_act_as_attachable: Umožní přikládat dokumenty k objektům např. úkolům.
label_show_system_folders: Zobrazit systémové složky
note_dmsf_show_system_folders: Systémové složky jsou složky se specifickým určením, např. pro dokumenty nahrané k úkolům.
label_user_search_add: Vyhledej uživatele pro přidání

View File

@ -360,5 +360,7 @@ de:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ en:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ es:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ fr:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -362,5 +362,7 @@ hu:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ it: # Italian strings thx 2 Matteo Arceci!
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ ja:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ pl:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ pt-BR:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ ru:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ sl:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ zh-TW:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -363,5 +363,7 @@ zh:
label_act_as_attachable: Act as attachable
note_dmsf_act_as_attachable: Allows to attach documents to objects e.g. issues.
label_show_system_folders: Show system folders
note_dmsf_show_system_folders: System folders are folders with a specifics purpose, e.g. for documents attached to issues.
label_user_search_add: Search for user to add

View File

@ -0,0 +1,85 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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 DmsfFileContainerRollback < ActiveRecord::Migration
def up
# Create necessary folders
new_folder_ids = []
description = 'Documents assigned to issues'
DmsfFile.where(:container_type => 'Issue').each do |file|
issue = Issue.find_by_id file.container_id
unless issue
Rails.logger.error "Issue ##{file.container_id} not found"
next
end
# Parent folder
parent = DmsfFolder.where(:project_id => issue.project.id, :title => '.Issues', :description => description).first
unless parent
parent = DmsfFolder.new
parent.project_id = issue.project.id
parent.title = '.Issues'
parent.description = description
parent.user_id = User.anonymous.id
parent.save
new_folder_ids << parent.id
end
# Issue folder
folder = DmsfFolder.new
folder.project_id = issue.project.id
folder.dmsf_folder_id = parent.id
folder.title = "#{issue.id} - #{issue.subject}"
folder.user_id = User.anonymous.id
folder.save
new_folder_ids << folder.id
# Move the file into the new folder
file.dmsf_folder_id = folder.id
file.save
end
# Make DB changes in dmsf_files
remove_index :dmsf_files, [:container_id, :container_type]
remove_column :dmsf_files, :container_type
rename_column :dmsf_files, :container_id, :project_id
add_index :dmsf_files, :project_id
# Add system folder_flag to dmsf_folders
add_column :dmsf_folders, :system, :boolean, :null => false, :default => false
DmsfFolder.where(:id => new_folder_ids).update_all(:system => true)
end
def down
# dmsf_files
file_folder_ids = DmsfFile.joins(:dmsf_folder).where('dmsf_folders.system = 1').pluck('dmsf_files.id, cast(dmsf_folders.title as unsigned)')
remove_index :dmsf_files, :project_id
rename_column :dmsf_files, :project_id, :container_id
add_column :dmsf_files, :container_type, :string, :limit => 30, :null => false, :default => 'Project'
DmsfFile.update_all(:container_type => 'Project')
file_folder_ids.each do |id, container_id|
file = DmsfFile.find_by_id(id)
if file
file.container_id = container_id
file.container_type = 'Issue'
file.save
end
end
add_index :dmsf_files, [:container_id, :container_type]
# dmsf_folders
DmsfFolder.where(:system => true).delete_all
remove_column :dmsf_folders, :system
end
end

View File

@ -52,7 +52,8 @@ Redmine::Plugin.register :redmine_dmsf do
'dmsf_webdav_ignore' => '^(\._|\.DS_Store$|Thumbs.db$)',
'dmsf_webdav_disable_versioning' => '^\~\$|\.tmp$',
'dmsf_keep_documents_locked' => false,
'dmsf_act_as_attachable' => false
'dmsf_act_as_attachable' => false,
'dmsf_show_system_folders' => false
}
menu :project_menu, :dmsf, { :controller => 'dmsf', :action => 'show' }, :caption => :menu_dmsf, :before => :documents, :param => :id

View File

@ -33,8 +33,8 @@ module RedmineDmsf
copied_from = Issue.find_by_id(params[:copy_from]) if params[:copy_from].present?
# Save documents
if copied_from
issue.dmsf_files = copied_from.dmsf_files.map do |dmsf_file|
dmsf_file.copy_to(issue)
copied_from.dmsf_files.each do |dmsf_file|
dmsf_file.copy_to(issue.project, issue.system_folder(true))
end
end
end
@ -53,14 +53,15 @@ module RedmineDmsf
params = context[:params]
uploaded_files = params[:dmsf_attachments]
if uploaded_files && uploaded_files.is_a?(Hash)
# standard file input uploads
system_folder = issue.system_folder(true)
uploaded_files.each_value do |uploaded_file|
upload = DmsfUpload.create_from_uploaded_attachment(issue.project, nil, uploaded_file)
upload = DmsfUpload.create_from_uploaded_attachment(issue.project, system_folder, uploaded_file)
uploaded_file[:disk_filename] = upload.disk_filename
uploaded_file[:name] = upload.name
uploaded_file[:title] = upload.title
end
DmsfUploadHelper.commit_files_internal uploaded_files, issue, nil, context[:controller]
DmsfUploadHelper.commit_files_internal uploaded_files, issue.project, system_folder,
context[:controller]
end
end
end

View File

@ -26,20 +26,47 @@ module RedmineDmsf
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method_chain :copy_from, :dmsf_copy_from
has_many :dmsf_files, -> { where(dmsf_folder_id: nil, container_type: 'Issue').order(:name) },
:class_name => 'DmsfFile', :foreign_key => 'container_id', :dependent => :destroy
before_destroy :delete_system_folder
end
end
module InstanceMethods
def copy_from_with_dmsf_copy_from(arg, options={})
copy_from_without_dmsf_copy_from(arg, options)
# issue = @copied_from
# self.dmsf_files = issue.dmsf_files.map do |dmsf_file|
# dmsf_file.copy_to(self)
# end
def system_folder(create = false)
parent = DmsfFolder.system.where(:project_id => self.project_id, :title => '.Issues').first
if create && !parent
parent = DmsfFolder.new
parent.project_id = self.project_id
parent.title = '.Issues'
parent.description = 'Documents assigned to issues'
parent.user_id = User.anonymous.id
parent.system = true
parent.save
end
if parent
folder = DmsfFolder.system.where(['project_id = ? AND dmsf_folder_id = ? AND CAST(title AS UNSIGNED) = ?',
self.project_id, parent.id, self.id]).first
if create && !folder
folder = DmsfFolder.new
folder.dmsf_folder_id = parent.id
folder.project_id = self.project_id
folder.title = "#{self.id} - #{self.subject}"
folder.user_id = User.anonymous.id
folder.system = true
folder.save
end
end
folder
end
def dmsf_files
folder = self.system_folder
folder.dmsf_files if folder
end
def delete_system_folder
folder = self.system_folder
folder.destroy if folder
end
def dmsf_file_added(dmsf_file)

View File

@ -31,11 +31,10 @@ module RedmineDmsf
unloadable
alias_method_chain :copy, :dmsf
has_many :dmsf_files, -> { where(dmsf_folder_id: nil, container_type: 'Project').order(:name) },
:class_name => 'DmsfFile', :foreign_key => 'container_id', :dependent => :destroy
has_many :dmsf_folders, -> { where(dmsf_folder_id: nil).order(:title) },
:class_name => 'DmsfFolder', :foreign_key => 'project_id',
:dependent => :destroy
has_many :dmsf_files, -> { where(dmsf_folder_id: nil).order(:name) },
:class_name => 'DmsfFile', :foreign_key => 'project_id', :dependent => :destroy
has_many :dmsf_folders, ->{ where(:dmsf_folder_id => nil).order(:title) },
:class_name => 'DmsfFolder', :foreign_key => 'project_id', :dependent => :destroy
has_many :dmsf_workflows, :dependent => :destroy
has_many :folder_links, -> { where dmsf_folder_id: nil, target_type: 'DmsfFolder' },
:class_name => 'DmsfLink', :foreign_key => 'project_id', :dependent => :destroy

View File

@ -210,10 +210,10 @@ module RedmineDmsf
# File
# Use file.id & file.last_revision.id as key
# When revision changes then the key will change and the old cached item will eventually be evicted
propstats_key = "PROPSTATS/#{resource.resource.file.id}-#{resource.resource.file.last_revision.id}"
propstats_key = "PROPSTATS/#{resource.resource.file.id}-#{resource.resource.file.last_revision.id}" if resource.resource.file
end
xml_str = RedmineDmsf::Webdav::Cache.read(propstats_key)
xml_str = RedmineDmsf::Webdav::Cache.read(propstats_key) if propstats_key
if xml_str.nil?
# Create the complete PROPSTATS response
propstats_builder = Nokogiri::XML::Builder.new do |propstats_xml|
@ -238,7 +238,7 @@ module RedmineDmsf
# Add PROPSTATS to cache
# Caching the PROPSTATS response as xml text string.
RedmineDmsf::Webdav::Cache.write(propstats_key, xml_str)
RedmineDmsf::Webdav::Cache.write(propstats_key, xml_str) if propstats_key
end
xml << xml_str
end

View File

@ -88,50 +88,21 @@ module RedmineDmsf
# Check if current entity is a folder and return DmsfFolder object if found (nil if not)
def folder
unless @folder
return nil unless project # If the project doesn't exist, this entity can't exist
# Note: Folder is searched for as a generic search to prevent SQL queries being generated:
# if we were to look within parent, we'd have to go all the way up the chain as part of the
# existence check, and although I'm sure we'd love to access the hierarchy, I can't yet
# see a practical need for it
folders = DmsfFolder.visible.where(:project_id => project.id, :title => basename).order('title ASC').to_a
return nil unless folders.length > 0
if (folders.length > 1)
folders.delete_if { |x| '/' + x.dmsf_path_str != projectless_path }
return nil unless folders.length > 0
@folder = folders[0]
else
if (('/' + folders[0].dmsf_path_str) == projectless_path)
@folder = folders[0]
end
end
return nil unless project
f = parent.folder
@folder = DmsfFolder.visible.where(:project_id => project.id, :title => basename,
:dmsf_folder_id => parent.folder ? parent.folder.id : nil).first
end
@folder
end
# Check if current entity exists as a file (DmsfFile), and returns corresponding object if found (nil otherwise)
# Currently has a dual search approach (depending on if parent can be determined)
def file
unless @file
return nil unless project # Again if entity project is nil, it cannot exist in context of this object
# Hunt for files parent path
f = false
if (parent.projectless_path != '/')
f = parent.folder if parent.folder
else
f = nil
end
if f || f.nil?
# f has a value other than false? - lets use traditional
# DMSF file search by name.
@file = DmsfFile.visible.find_file_by_name(project, f, basename)
else
# If folder is false, means it couldn't pick up parent,
# as such its probably fine to bail out, however we'll
# perform a search in this scenario
files = DmsfFile.visible.where(:container_id => project.id, :container_type => 'Project', :name => basename).order('name ASC').to_a
files.delete_if { |x| File.dirname('/' + x.dmsf_path_str) != File.dirname(projectless_path) }
@file = files[0] if files.length > 0
end
@file = DmsfFile.visible.joins('JOIN dmsf_file_revisions ON dmsf_files.id = dmsf_file_revisions.dmsf_file_id').where(
["dmsf_files.project_id = ? AND dmsf_files.dmsf_folder_id #{parent.folder ? '=' : 'IS'} ? AND dmsf_file_revisions.name = ?",
project.id, parent.folder ? parent.folder.id : nil, basename]).first
end
@file
end
@ -189,6 +160,7 @@ module RedmineDmsf
##
def get(request, response)
raise NotFound unless exist?
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder))
if collection?
html_display
response['Content-Length'] = response.body.bytesize.to_s
@ -207,6 +179,7 @@ module RedmineDmsf
if request.body.read.to_s.empty?
raise NotFound unless project && project.module_enabled?('dmsf')
raise Forbidden unless User.current.admin? || User.current.allowed_to?(:folder_manipulation, project)
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder, false))
return MethodNotAllowed if exist? # If we already exist, why waste the time trying to save?
parent_folder = nil
if (parent.projectless_path != '/')
@ -231,7 +204,7 @@ module RedmineDmsf
def delete
if file
raise Forbidden unless User.current.admin? || User.current.allowed_to?(:file_delete, project)
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder, false))
pattern = Setting.plugin_redmine_dmsf['dmsf_webdav_disable_versioning']
if !pattern.blank? && basename.match(pattern)
# Files that are not versioned should be destroyed
@ -253,6 +226,7 @@ module RedmineDmsf
end
elsif folder
raise Forbidden unless User.current.admin? || User.current.allowed_to?(:folder_manipulation, project)
raise Forbidden unless DmsfFolder.permissions?(folder, false)
folder.delete(false) ? NoContent : Conflict
else
MethodNotAllowed
@ -271,11 +245,13 @@ module RedmineDmsf
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 collection?
# At the moment we don't support cross project destinations
return MethodNotImplemented 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)
# Current object is a folder, so now we need to figure out information about Destination
if dest.exist?
@ -386,6 +362,7 @@ module RedmineDmsf
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 collection?
# Current object is a folder, so now we need to figure out information about Destination
@ -402,6 +379,7 @@ module RedmineDmsf
User.current.allowed_to?(:view_dmsf_folders, resource.project) &&
User.current.allowed_to?(:view_dmsf_files, project) &&
User.current.allowed_to?(:view_dmsf_folders, project))
raise Forbidden unless DmsfFolder.permissions?(folder, false)
return PreconditionFailed if (parent.projectless_path != '/' && !parent.folder)
folder.title = resource.basename
@ -552,6 +530,7 @@ module RedmineDmsf
def put(request, response)
raise BadRequest if collection?
raise Forbidden unless User.current.admin? || User.current.allowed_to?(:file_manipulation, project)
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder, false))
# Ignore file name patterns given in the plugin settings
pattern = Setting.plugin_redmine_dmsf['dmsf_webdav_ignore']
@ -593,8 +572,7 @@ module RedmineDmsf
else
raise BadRequest unless (parent.projectless_path == '/' || (parent.exist? && parent.folder))
f = DmsfFile.new
f.container_type = 'Project'
f.container_id = project.id
f.project_id = project.id
f.name = basename
f.dmsf_folder = parent.folder
f.notification = !Setting.plugin_redmine_dmsf['dmsf_default_notifications'].blank?
@ -677,6 +655,7 @@ module RedmineDmsf
# also best-utilising DAV4Rack's implementation.
def download
raise NotFound unless (file && file.last_revision && file.last_revision.disk_file)
raise Forbidden unless (!parent.exist? || !parent.folder || DmsfFolder.permissions?(parent.folder))
# If there is no range (start of ranged download, or direct download) then we log the
# file access, so we can properly keep logged information

View File

@ -1,8 +1,7 @@
---
dmsf_files_001:
id: 1
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: NULL
name: "test.txt"
notification: 0
@ -12,8 +11,7 @@ dmsf_files_001:
#file on non-dmsf enabled project
dmsf_files_002:
id: 2
container_id: 2
container_type: "Project"
project_id: 2
dmsf_folder_id: NULL
name: "test.txt"
notification: 0
@ -23,8 +21,7 @@ dmsf_files_002:
#deleted file on dmsf-enabled project
dmsf_files_003:
id: 3
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: NULL
name: "deleted.txt"
notification: 0
@ -33,8 +30,7 @@ dmsf_files_003:
dmsf_files_004:
id: 4
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: 2
name: "test.txt"
notification: 0
@ -43,8 +39,7 @@ dmsf_files_004:
dmsf_files_005:
id: 5
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: 5
name: "test.txt"
notification: 0
@ -53,8 +48,7 @@ dmsf_files_005:
dmsf_files_006:
id: 6
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: 3
name: "test.txt"
notification: 0
@ -63,9 +57,8 @@ dmsf_files_006:
dmsf_files_007:
id: 7
container_id: 1
container_type: "Issue"
dmsf_folder_id: NULL
project_id: 1
dmsf_folder_id: 8
name: "test.gif"
notification: 0
deleted: 0
@ -73,8 +66,7 @@ dmsf_files_007:
dmsf_files_008:
id: 8
container_id: 1
container_type: "Issue"
project_id: 1
dmsf_folder_id: NULL
name: "test.pdf"
notification: 0
@ -83,8 +75,7 @@ dmsf_files_008:
dmsf_files_009:
id: 9
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: NULL
name: "myfile.txt"
notification: 0
@ -93,8 +84,7 @@ dmsf_files_009:
dmsf_files_010:
id: 10
container_id: 1
container_type: "Project"
project_id: 1
dmsf_folder_id: NULL
name: "zero.txt"
notification: 0

View File

@ -46,4 +46,12 @@ dmsf_folders_007:
title: folder7
project_id: 1
dmsf_folder_id: NULL
user_id: 1
user_id: 1
dmsf_folders_008:
id: 8
title: .Issues
project_id: 1
dmsf_folder_id: NULL
user_id: 1
system: true

View File

@ -63,15 +63,13 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
# <dmsf_file>
# <id>1</id>
# <name>test.txt</name>
# <container_id>1</container_id>
# <container_type>Project</container_type>
# <project_id>1</project_id>
# <version>1.0</version>
# <content_url>/dmsf/files/1/download</content_url>
# </dmsf_file>
assert_select 'dmsf_file > id', :text => @file1.id.to_s
assert_select 'dmsf_file > name', :text => @file1.name
assert_select 'dmsf_file > container_id', :text => @file1.container_id.to_s
assert_select 'dmsf_file > container_type', :text => @file1.container_type.to_s
assert_select 'dmsf_file > project_id', :text => @file1.project_id.to_s
assert_select 'dmsf_file > version', :text => "#{@file1.last_revision.major_version}.#{@file1.last_revision.minor_version}"
assert_select 'dmsf_file > content_url', :text => "/dmsf/files/#{@file1.id}/download"
#curl -v -H "Content-Type: application/octet-stream" -X GET -u ${1}:${2} http://localhost:3000/dmsf/files/41532/download > file.txt

View File

@ -322,7 +322,7 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest
def test_propfind_depth1_on_project1_for_admin_with_cache
RedmineDmsf::Webdav::Cache.init_testcache
assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +8 do
assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +9 do
xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil,
@admin.merge!({:HTTP_DEPTH => '1'})
assert_response 207 # MultiStatus
@ -376,7 +376,7 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest
log_user 'admin', 'admin' # login as admin
assert !User.current.anonymous?, 'Current user is anonymous'
assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +8 do
assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +9 do
xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil,
@admin.merge!({:HTTP_DEPTH => '1'})
assert_response 207 # MultiStatus

View File

@ -60,9 +60,8 @@ class DmsfFileRevisionTest < RedmineDmsf::Test::UnitTest
def test_new_storage_filename
# Create a file.
f = DmsfFile.new
f.container_type = 'Project'
f.container_id = 1
f.name = "Testfile.txt"
f.project_id = 1
f.name = 'Testfile.txt'
f.dmsf_folder = nil
f.notification = !Setting.plugin_redmine_dmsf['dmsf_default_notifications'].blank?
f.save
@ -74,7 +73,7 @@ class DmsfFileRevisionTest < RedmineDmsf::Test::UnitTest
r1.dmsf_file = f
r1.user = User.current
r1.name = "Testfile.txt"
r1.title = DmsfFileRevision.filename_to_title("Testfile.txt")
r1.title = DmsfFileRevision.filename_to_title('Testfile.txt')
r1.description = nil
r1.comment = nil
r1.mime_type = nil

View File

@ -208,18 +208,6 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
RedmineDmsf::Webdav::Cache.init_nullcache
end
def test_container_project
container = @file1.container
assert_not_nil container
assert container.is_a?(Project)
end
def test_container_issue
container = @file7.container
assert_not_nil container
assert container.is_a?(Issue)
end
def test_project_project
project = @file1.project
assert_not_nil project

View File

@ -53,7 +53,7 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
def test_visiblity
# The role has got permissions
User.current = @manager
assert_equal 5, DmsfFolder.where(:project_id => 1).count
assert_equal 6, DmsfFolder.where(:project_id => 1).count
assert_equal 5, DmsfFolder.visible.where(:project_id => 1).count
# The user has got permissions
User.current = @developer
@ -65,10 +65,10 @@ class DmsfFolderTest < RedmineDmsf::Test::UnitTest
def test_permissions
User.current = @developer
assert DmsfFolder.permissions(@folder7)
assert DmsfFolder.permissions?(@folder7)
@folder7.dmsf_folder_permissions.where(:object_type => 'User').delete_all
@folder7.reload
assert !DmsfFolder.permissions(@folder7)
assert !DmsfFolder.permissions?(@folder7)
end
def test_delete

View File

@ -67,7 +67,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
def test_dmsf_count
hash = @project1.dmsf_count
assert_equal 7, hash[:files]
assert_equal 8, hash[:files]
assert_equal 6, hash[:folders]
end
@ -79,7 +79,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
end
def test_copy_dmsf
assert_equal 3, @project1.dmsf_files.visible.count
assert_equal 4, @project1.dmsf_files.visible.count
assert_equal 3, @project1.dmsf_folders.visible.count
assert_equal 1, @project1.file_links.visible.count
assert_equal 1, @project1.folder_links.visible.count
@ -90,7 +90,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
assert_equal 0, @project3.folder_links.visible.count
assert_equal 0, @project3.url_links.visible.count
@project3.copy_dmsf(@project1)
assert_equal 3, @project3.dmsf_files.visible.count
assert_equal 4, @project3.dmsf_files.visible.count
assert_equal 3, @project3.dmsf_folders.count
assert_equal 1, @project3.file_links.visible.count
assert_equal 1, @project3.folder_links.visible.count