diff --git a/README.md b/README.md
index 2e6b3133..3e8bba90 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,7 @@ Features
* Documents and folders symbolic links
* Document tagging
* Trash bin
+ * Documents attachable to issues
* Compatible with Redmine 3.3.x
Dependencies
@@ -235,9 +236,9 @@ Before installing ensure that the Redmine instance is stopped.
6. Restart the web server.
7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure.
8. Assign DMSF permissions to appropriate roles.
-9. There are two rake tasks:
+9. There are a few rake tasks:
- a) To convert documents from the standard Redmine document module
+ I) To convert documents from the standard Redmine document module
Available options:
@@ -253,11 +254,42 @@ Before installing ensure that the Redmine instance is stopped.
chown -R www-data:www-data /redmine/files/dmsf
afterwards)
- b) To alert all users who are expected to do an approval in the current approval steps
+ II) To alert all users who are expected to do an approval in the current approval steps
Example:
- rake redmine:dmsf_alert_approvals RAILS_ENV="production"
+ rake redmine:dmsf_alert_approvals RAILS_ENV="production"
+
+ III) To clears the Webdav Cache
+
+ Example:
+
+ rake redmine:dmsf_clear_webdav_cache RAILS_ENV="production"
+
+ IV) To create missing MD5 digest for all file revisions
+
+ Available options:
+
+ *dry_run - test, no changes to the database
+
+ Example:
+
+ bundle exec rake redmine:dmsf_create_digests RAILS_ENV="production"
+ bundle exec rake redmine:dmsf_create_digests dry_run=1 RAILS_ENV="production"
+
+ V) To maintain DMSF
+
+ * Remove all files with no database record from the document directory
+ * Remove all links project_id = -1 (added links to an issue which hasn't been created)
+
+ Available options:
+
+ *dry_run - No physical deletion but to list of all unused files only
+
+ Example:
+
+ rake redmine:dmsf_maintenance RAILS_ENV="production"
+ rake redmine:dmsf_maintenance dry_run=1 RAILS_ENV="production"
### Fulltext search (optional)
If you want to use full-text search features, you must setup file content indexing.
diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb
index 5fa504eb..feeced3a 100644
--- a/app/controllers/dmsf_controller.rb
+++ b/app/controllers/dmsf_controller.rb
@@ -728,19 +728,7 @@ class DmsfController < ApplicationController
end
end
# Remove system folders you are not allowed to see because you are not allowed to see the issue
- @subfolders.delete_if{ |folder|
- if folder.system
- issue_id = folder.title.to_i
- if issue_id > 0
- issue = Issue.find_by_id issue_id
- issue && !issue.visible?(User.current)
- else
- false
- end
- else
- false
- end
- }
+ @subfolders = DmsfHelper.visible_folders(@subfolders)
end
@ajax_upload_size = Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'].present? ? Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'] : 100
diff --git a/app/controllers/dmsf_links_controller.rb b/app/controllers/dmsf_links_controller.rb
index 08b0fce3..7d8eb1a2 100644
--- a/app/controllers/dmsf_links_controller.rb
+++ b/app/controllers/dmsf_links_controller.rb
@@ -26,6 +26,7 @@ class DmsfLinksController < ApplicationController
before_filter :find_link_project
before_filter :authorize
before_filter :permissions
+ protect_from_forgery except: :new
def permissions
if @dmsf_link
@@ -43,109 +44,80 @@ class DmsfLinksController < ApplicationController
def new
@dmsf_link = DmsfLink.new
@dmsf_link.project_id = params[:project_id]
-
- if params[:dmsf_link].present?
- # Reload
- @dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
- @dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
- @type = params[:dmsf_link][:type]
- @link_external = (@type == 'link_from') && (params[:external_link] == 'true')
- @dmsf_link.target_project_id = params[:dmsf_link][:target_project_id]
- @target_folder_id = params[:dmsf_link][:target_folder_id].to_i if params[:reload].blank? && DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id])
- if @type == 'link_to'
- if params[:dmsf_link][:dmsf_file_id].present?
- file = DmsfFile.find_by_id params[:dmsf_link][:dmsf_file_id]
- @dmsf_link.name = file.title if file
- else
- folder = DmsfFolder.find_by_id params[:dmsf_link][:dmsf_folder_id]
- @dmsf_link.name = folder.title if folder
- end
+ @dmsf_link.dmsf_folder_id = params[:dmsf_folder_id]
+ @dmsf_file_id = params[:dmsf_file_id]
+ @type = params[:type]
+ @dmsf_link.target_project_id = params[:project_id]
+ @dmsf_link.project_id = params[:project_id]
+ @target_folder_id = params[:dmsf_folder_id].to_i if params[:dmsf_folder_id].present?
+ if @type == 'link_to'
+ if @dmsf_file_id
+ file = DmsfFile.find_by_id @dmsf_file_id
+ @dmsf_link.name = file.title if file
else
- if params[:dmsf_link][:target_file_id].present?
- @target_file_id = params[:dmsf_link][:target_file_id]
- file = DmsfFile.find_by_id @target_file_id
-
- if file
- folder = DmsfFolder.find_by_id params[:dmsf_link][:target_folder_id]
- if (folder && (folder.project_id == @dmsf_link.target_project_id) && folder.dmsf_files.include?(file)) || folder.nil?
- @dmsf_link.name = file.title
- end
- end
- else
- folder = DmsfFolder.find_by_id params[:dmsf_link][:target_folder_id]
-
- if folder
- if folder.project_id == @dmsf_link.target_project_id
- @dmsf_link.name = folder.title if folder
- end
- end
- end
- end
- else
- # Link from/to
- @dmsf_link.dmsf_folder_id = params[:dmsf_folder_id]
- @dmsf_file_id = params[:dmsf_file_id]
- @type = params[:type]
- @link_external = false
- @dmsf_link.target_project_id = params[:project_id]
- @dmsf_link.project_id = params[:project_id]
- @target_folder_id = params[:dmsf_folder_id].to_i if params[:dmsf_folder_id].present?
- if @type == 'link_to'
- if @dmsf_file_id
- file = DmsfFile.find_by_id @dmsf_file_id
- @dmsf_link.name = file.title if file
- else
- folder = DmsfFolder.find_by_id @target_folder_id
- @dmsf_link.name = folder.title if folder
- end
+ folder = DmsfFolder.find_by_id @target_folder_id
+ @dmsf_link.name = folder.title if folder
end
end
+ @container = params[:container]
+ respond_to do |format|
+ format.html
+ format.js
+ end
+ end
- render :layout => !request.xhr?
+ def autocomplete_for_project
+ respond_to do |format|
+ format.js
+ end
+ end
+
+ def autocomplete_for_folder
+ respond_to do |format|
+ format.js
+ end
end
def create
@dmsf_link = DmsfLink.new
@dmsf_link.user = User.current
-
if params[:dmsf_link][:type] == 'link_from'
# Link from
- @dmsf_link.project_id = params[:dmsf_link][:project_id]
- @dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
+ if params[:dmsf_link][:container].blank?
+ @dmsf_link.project_id = params[:dmsf_link][:project_id]
+ @dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
+ else
+ # An issue link
+ @dmsf_link.project_id = -1
+ @dmsf_link.dmsf_folder_id = nil
+ end
@dmsf_link.target_project_id = params[:dmsf_link][:target_project_id]
- @link_external = (params[:external_link] == 'true')
- @dmsf_link.external_url = params[:dmsf_link][:external_url]
- if (@link_external)
+ if (params[:external_link] == 'true')
+ @dmsf_link.external_url = params[:dmsf_link][:external_url]
@dmsf_link.target_type = 'DmsfUrl'
elsif params[:dmsf_link][:target_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:target_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s
else
- @dmsf_link.target_id = DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
+ @dmsf_link.target_id = DmsfLinksHelper.is_a_number?(
+ params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
+ @dmsf_link.target_id = nil if(@dmsf_link.target_id == 0)
@dmsf_link.target_type = DmsfFolder.model_name.to_s
end
@dmsf_link.name = params[:dmsf_link][:name]
-
if @dmsf_link.save
flash[:notice] = l(:notice_successful_create)
- redirect_to dmsf_folder_path(:id => @project.id, :folder_id => @dmsf_link.dmsf_folder_id)
else
- @dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
- @type = params[:dmsf_link][:type]
- @target_folder_id = params[:dmsf_link][:target_folder_id].to_i if DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id])
- @target_file_id = @dmsf_link.target_id if @dmsf_link.target_type == DmsfFile.model_name.to_s
- render :action => 'new'
+ flash[:error] = @dmsf_link.errors.full_messages.to_sentence
end
else
# Link to
@dmsf_link.project_id = params[:dmsf_link][:target_project_id]
- @dmsf_link.dmsf_folder_id = DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
+ @dmsf_link.dmsf_folder_id = DmsfLinksHelper.is_a_number?(
+ params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
+ @dmsf_link.dmsf_folder_id = nil if(@dmsf_link.dmsf_folder_id == 0)
@dmsf_link.target_project_id = params[:dmsf_link][:project_id]
- @link_external = (params[:external_link] == 'true')
- @dmsf_link.external_url = params[:dmsf_link][:external_url]
- if (@link_external)
- @dmsf_link.target_type = 'DmsfUrl'
- elsif params[:dmsf_link][:dmsf_file_id].present?
+ if params[:dmsf_link][:dmsf_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:dmsf_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s
else
@@ -153,24 +125,26 @@ class DmsfLinksController < ApplicationController
@dmsf_link.target_type = DmsfFolder.model_name.to_s
end
@dmsf_link.name = params[:dmsf_link][:name]
-
if @dmsf_link.save
flash[:notice] = l(:notice_successful_create)
- 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])
- end
else
- @dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
- @type = params[:dmsf_link][:type]
- @target_folder_id = @dmsf_link.dmsf_folder_id
- @dmsf_link.target_project_id = @dmsf_link.project.id
- @dmsf_link.project_id = params[:dmsf_link][:project_id]
- @dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
- render :action => 'new'
+ flash[:error] = @dmsf_link.errors.full_messages.to_sentence
end
end
+ respond_to do |format|
+ format.html {
+ if params[:dmsf_link][:type] == 'link_from'
+ redirect_to dmsf_folder_path(:id => @project.id, :folder_id => @dmsf_link.dmsf_folder_id)
+ else
+ 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])
+ end
+ end
+ }
+ format.js
+ end
end
def destroy
diff --git a/app/helpers/dmsf_helper.rb b/app/helpers/dmsf_helper.rb
index 808aaf8e..844b3593 100644
--- a/app/helpers/dmsf_helper.rb
+++ b/app/helpers/dmsf_helper.rb
@@ -89,9 +89,30 @@ module DmsfHelper
'plupload/js/i18n/en.js'
end
+ def self.visible_folders(folders)
+ allowed = Setting.plugin_redmine_dmsf['dmsf_act_as_attachable']
+ folders.reject{ |folder|
+ if folder.system
+ unless allowed
+ true
+ else
+ issue_id = folder.title.to_i
+ if issue_id > 0
+ issue = Issue.find_by_id issue_id
+ issue && !issue.visible?(User.current)
+ else
+ false
+ end
+ end
+ else
+ false
+ end
+ }
+ end
+
def self.all_children_sorted(parent, pos, ident)
# Folders && files && links
- nodes = parent.dmsf_folders.visible + parent.dmsf_links.visible + parent.dmsf_files.visible
+ nodes = visible_folders(parent.dmsf_folders.visible.to_a) + parent.dmsf_links.visible + parent.dmsf_files.visible
# Alphabetical and type sort
nodes.sort! do |x, y|
if ((x.is_a?(DmsfFolder) || (x.is_a?(DmsfLink) && x.is_folder?)) &&
diff --git a/app/helpers/dmsf_links_helper.rb b/app/helpers/dmsf_links_helper.rb
index 758e5ce3..aa6d1a2d 100644
--- a/app/helpers/dmsf_links_helper.rb
+++ b/app/helpers/dmsf_links_helper.rb
@@ -37,6 +37,18 @@ module DmsfLinksHelper
# An integer test
def self.is_a_number?(s)
s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
- end
+ end
+
+ def files_for_select(project_id, folder_id)
+ files = []
+ if folder_id && (folder_id != '0')
+ folder = DmsfFolder.find_by_id folder_id
+ files = folder.dmsf_files.visible.to_a if folder
+ elsif project_id
+ project = Project.find_by_id project_id
+ files = project.dmsf_files.visible.to_a if project
+ end
+ files
+ end
end
diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb
index a0787be6..6248d6f7 100644
--- a/app/models/dmsf_folder.rb
+++ b/app/models/dmsf_folder.rb
@@ -210,7 +210,10 @@ class DmsfFolder < ActiveRecord::Base
end
def self.directory_tree(project, current_folder = nil)
- tree = [[l(:link_documents), nil]]
+ unless project.is_a? Project
+ project = Project.find_by_id project
+ end
+ tree = [[l(:link_documents), 0]]
project.dmsf_folders.visible(false).each do |folder|
unless folder == current_folder
tree.push(["...#{folder.title}", folder.id])
diff --git a/app/models/dmsf_link.rb b/app/models/dmsf_link.rb
index 26b837a7..08285c18 100644
--- a/app/models/dmsf_link.rb
+++ b/app/models/dmsf_link.rb
@@ -122,8 +122,17 @@ class DmsfLink < ActiveRecord::Base
link
end
+ def container
+ if self.folder && self.folder.system
+ Issue.where(:id => self.folder.title.to_i).first
+ end
+ end
+
def delete(commit = false)
if commit
+ if self.container.is_a?(Issue)
+ self.container.dmsf_file_removed(self.target_file)
+ end
self.destroy
else
self.deleted = STATUS_DELETED
diff --git a/app/views/dmsf/show.html.erb b/app/views/dmsf/show.html.erb
index fb930ba7..7d265216 100644
--- a/app/views/dmsf/show.html.erb
+++ b/app/views/dmsf/show.html.erb
@@ -59,8 +59,9 @@
<% end %>
<% if @file_manipulation_allowed && !@locked_for_user %>
<%= link_to(l(:label_link_from),
- new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder ? @folder.id : @folder, :type => 'link_from'),
- :title => l(:title_create_link), :class => 'icon icon-link') %>
+ new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder ? @folder.id : @folder,
+ :type => 'link_from'), :title => l(:title_create_link),
+ :class => 'icon icon-link') %>
<% end %>
<%= link_to(l(:link_create_folder),
new_dmsf_path(:id => @project, :parent_id => @folder),
@@ -100,7 +101,6 @@
<% custom_value.custom_field.is_required = false %>
<% custom_value.value = params[:custom_value].present? ? params[:custom_value] : '' %>
<%= h(custom_value.custom_field.name) %>:
- <%#= custom_field_tag(:dmsf_folder, custom_value, :style => 'width: auto') %>
<%= custom_value.custom_field.format.edit_tag(self,
custom_field_tag_id(:dmsf_folder, custom_value.custom_field),
custom_field_tag_name(:dmsf_folder, custom_value.custom_field),
diff --git a/app/views/dmsf_files/_file_new_revision.html.erb b/app/views/dmsf_files/_file_new_revision.html.erb
index a0a2c9c9..b80e0cdf 100644
--- a/app/views/dmsf_files/_file_new_revision.html.erb
+++ b/app/views/dmsf_files/_file_new_revision.html.erb
@@ -78,7 +78,7 @@
<%= label_tag('file_upload', l(:label_new_content)) %>
- <%= render :partial => 'dmsf_upload/form', :locals => { :multiple => false } %>
+ <%= render :partial => 'dmsf_upload/form', :locals => { :multiple => false, :container => nil } %>
diff --git a/app/views/dmsf_files/_links.html.erb b/app/views/dmsf_files/_links.html.erb
index 1b928310..d32d3fd1 100644
--- a/app/views/dmsf_files/_links.html.erb
+++ b/app/views/dmsf_files/_links.html.erb
@@ -20,7 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
-<% if dmsf_files.present? %>
+<% if dmsf_files.present? || dmsf_links.present? %>
<% for dmsf_file in dmsf_files %>
@@ -76,4 +76,58 @@
<% end %>
<% end %>
+ <% for dmsf_link in dmsf_links %>
+ <% dmsf_file = dmsf_link.target_file %>
+ <% if dmsf_file.last_revision %>
+
+ <% file_view_url = url_for({:controller => :dmsf_files, :action => 'view', :id => dmsf_file}) %>
+ <%= link_to(h(dmsf_link.title),
+ file_view_url,
+ :target => '_blank',
+ :class => "icon icon-file #{DmsfHelper.filetype_css(dmsf_file.name)}",
+ :title => h(dmsf_file.last_revision.try(:tooltip)),
+ 'data-downloadurl' => "#{dmsf_file.last_revision.detect_content_type}:#{h(dmsf_file.name)}:#{file_view_url}") %>
+ <% if dmsf_file.text? || dmsf_file.image? %>
+ <%= link_to l(:button_view),
+ file_view_url,
+ :class => 'icon-only icon-magnifier',
+ :title => l(:button_view) %>
+ <% end %>
+ <%= " - #{dmsf_file.description}" unless dmsf_file.description.blank? %>
+ (<%= number_to_human_size dmsf_file.last_revision.size %>)
+ <% if @issue.attributes_editable? && User.current.allowed_to?(:file_delete, dmsf_file.project) %>
+ <%= link_to('',
+ dmsf_link_path(dmsf_link, :commit => 'yes'),
+ :data => {:confirm => l(:text_are_you_sure)},
+ :method => :delete,
+ :title => l(:title_delete),
+ :class => 'icon icon-del') %>
+ <% end %>
+ <%= dmsf_file.last_revision.user %>, <%= format_time(dmsf_file.last_revision.updated_at) %>
+
+ <% 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 }) %>
+
+
+ <% end %>
+ <% end %>
+ <% if defined?(thumbnails) && thumbnails %>
+ <% images = dmsf_links.map{ |link| link.target_file }.select(&:image?) %>
+ <% if images.any? %>
+
+ <% images.each do |file| %>
+
+ <%= link_to image_tag(dmsf_thumbnail_path(file)),
+ url_for({:controller => :dmsf_files, :action => 'view', :id => file}),
+ :alt => dmsf_file.title %>
+
+ <% end %>
+
+ <% end %>
+ <% end %>
+
<% end %>
diff --git a/app/views/dmsf_links/_form.html.erb b/app/views/dmsf_links/_form.html.erb
index ddbed231..608176db 100644
--- a/app/views/dmsf_links/_form.html.erb
+++ b/app/views/dmsf_links/_form.html.erb
@@ -20,40 +20,41 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
-<% html_title l(:dmsf) %>
+<%= l(:title_create_link) %>
-<% if @dmsf_file_id %>
- <% file = DmsfFile.find_by_id @dmsf_file_id%>
- <% title = file.title if file %>
-<% end %>
-
-<%= render(:partial => '/dmsf/path',
- :locals => {:folder => @dmsf_link.folder, :filename => nil,
- :title => (@type == 'link_from') ? l(:label_link_from) : l(:label_link_to) }) %>
-
-<%= labelled_form_for @dmsf_link do |f| %>
+<%= labelled_form_for @dmsf_link, :remote => modal do |f| %>
<%= error_messages_for @dmsf_link %>
<%= f.hidden_field :project_id, :value => @dmsf_link.project_id %>
<%= f.hidden_field :dmsf_folder_id, :value => @dmsf_link.dmsf_folder_id if @dmsf_link.dmsf_folder_id %>
<%= f.hidden_field :type, :value => @type %>
<%= f.hidden_field :dmsf_file_id, :value => @dmsf_file_id %>
+ <%= f.hidden_field(:container, :value => @container) if @container %>
- <% if @type == 'link_from' %>
+ <% if (@type == 'link_from') && !@container %>
- <%= radio_button_tag(:external_link, 'false', @link_external == false) %> <%= l(:label_internal) %>
- <%= radio_button_tag(:external_link, 'true', @link_external) %> <%= l(:label_external) %>
+ <%= radio_button_tag(:external_link, 'false', true) %> <%= l(:label_internal) %>
+ <%= radio_button_tag(:external_link, 'true', false) %> <%= l(:label_external) %>
<% end %>
-
+
<% if @type == 'link_from' %>
- <%= l(:label_source_project) %>*
+ <%= l(:label_source_project) %>
<% else %>
- <%= l(:label_target_project) %>*
+ <%= l(:label_target_project) %>
<% end %>
<%= 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), :style => "width=100%") %>
+ <%= javascript_tag do %>
+ $('#dmsf_link_target_project_id').change(function(){
+ $.ajax({
+ url: '<%= autocomplete_for_project_dmsf_link_path(@project, :format => 'js') %>',
+ type: 'get',
+ data: $('#new_dmsf_link').serialize()
+ });
+ });
+ <% end %>
<% if @type == 'link_from' %>
@@ -64,51 +65,50 @@
<%= select_tag('dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project),
:selected => @target_folder_id)) %>
+ <%= javascript_tag do %>
+ $('#dmsf_link_target_folder_id').change(function(){
+ $.ajax({
+ url: '<%= autocomplete_for_folder_dmsf_link_path(@project, :format => 'js') %>',
+ type: 'get',
+ data: $('#new_dmsf_link').serialize()
+ });
+ });
+ <% end %>
<% if @type == 'link_from' %>
- <% if @target_folder_id %>
- <% folder = DmsfFolder.find_by_id @target_folder_id %>
- <% files = folder.dmsf_files.visible if folder %>
- <% else %>
- <% files = @dmsf_link.target_project.dmsf_files.visible if @dmsf_link.target_project %>
- <% end %>
- <%= f.select(:target_file_id,
- options_for_select(DmsfFolder.file_list(files), @target_file_id)) %>
+ <%= 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))) %>
<% end %>
-
+
- <%= f.text_field :external_url, :label => l(:label_link_external_url) %>
+ <%= f.text_field :external_url, :required => true %>
- <%= f.text_field :name, :label => l(:label_link_name) %>
+ <%= f.text_field :name, :required => true %>
-
<%= f.submit l(:button_create) %>
+
<%= f.submit l(:button_create), :onclick => 'hideModal(this);' %>
<% end %>
\ No newline at end of file
+
diff --git a/app/views/dmsf_links/autocomplete_for_folder.js.erb b/app/views/dmsf_links/autocomplete_for_folder.js.erb
new file mode 100644
index 00000000..c18720f0
--- /dev/null
+++ b/app/views/dmsf_links/autocomplete_for_folder.js.erb
@@ -0,0 +1,4 @@
+$('#dmsf_link_target_file_id').html('<%= escape_javascript(
+ select_tag('dmsf_link[target_file_id]',
+ options_for_select(DmsfFolder.file_list(files_for_select(params[:dmsf_link][:target_project_id],
+ params[:dmsf_link][:target_folder_id]))))) %>');
diff --git a/app/views/dmsf_links/autocomplete_for_project.js.erb b/app/views/dmsf_links/autocomplete_for_project.js.erb
new file mode 100644
index 00000000..eda8eb4b
--- /dev/null
+++ b/app/views/dmsf_links/autocomplete_for_project.js.erb
@@ -0,0 +1,4 @@
+$('#dmsf_link_target_folder_id').html('<%= escape_javascript(
+ select_tag('dmsf_link[target_folder_id]',
+ folder_tree_options_for_select(DmsfFolder.directory_tree(params[:dmsf_link][:target_project_id])))) %>');
+$('#dmsf_link_target_folder_id').change();
diff --git a/app/views/dmsf_links/create.js.erb b/app/views/dmsf_links/create.js.erb
new file mode 100644
index 00000000..de57c317
--- /dev/null
+++ b/app/views/dmsf_links/create.js.erb
@@ -0,0 +1,27 @@
+<%
+# encoding: utf-8
+#
+# Redmine plugin for Document Management System "Features"
+#
+# Copyright (C) 2011-17 Karel Pičman
+#
+# 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.
+%>
+
+var linksSpan = $("#dmsf_links_fields");
+var linkId = "<%= @dmsf_link.id %>";
+var linkName = "<%= @dmsf_link.name %>";
+
+dmsfAddLink(linksSpan, linkId, linkName);
diff --git a/app/views/dmsf_links/new.html.erb b/app/views/dmsf_links/new.html.erb
index bc47086f..4cc94ad6 100644
--- a/app/views/dmsf_links/new.html.erb
+++ b/app/views/dmsf_links/new.html.erb
@@ -20,4 +20,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
-<%= render 'form' %>
\ No newline at end of file
+<%= render :partial => 'form', :locals => { :modal => false } %>
\ No newline at end of file
diff --git a/app/views/dmsf_links/new.js.erb b/app/views/dmsf_links/new.js.erb
new file mode 100644
index 00000000..7dd70ab7
--- /dev/null
+++ b/app/views/dmsf_links/new.js.erb
@@ -0,0 +1,24 @@
+<%
+# encoding: utf-8
+#
+# Redmine plugin for Document Management System "Features"
+#
+# Copyright (C) 2011-17 Karel Pičman
+#
+# 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.
+%>
+
+$('#ajax-modal').html('<%= escape_javascript(render :partial => 'form', :locals => { :modal => true }) %>');
+showModal('ajax-modal', '40%');
\ No newline at end of file
diff --git a/app/views/dmsf_upload/_form.html.erb b/app/views/dmsf_upload/_form.html.erb
index 207881f1..a0f2f3ea 100644
--- a/app/views/dmsf_upload/_form.html.erb
+++ b/app/views/dmsf_upload/_form.html.erb
@@ -21,7 +21,7 @@
%>
-<% if defined?(container) && container && container.saved_dmsf_attachments %>
+<% if defined?(container) && container && container.saved_dmsf_attachments.present? %>
<% container.saved_dmsf_attachments.each_with_index do |attachment, i| %>
<%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') +
@@ -47,3 +47,24 @@
} %>
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
+<% if container %>
+
+
+ <% if container.saved_dmsf_links.present? %>
+ <% container.saved_dmsf_links.each_with_index do |dmsf_link, index| %>
+
+
+
+
+
+
+ <% end %>
+ <% end %>
+
+
+ <%= link_to l(:label_link_from),
+ new_dmsf_link_path(:project_id => container.project.id, :type => 'link_from', :container => 'issue'),
+ :title => l(:title_create_link), :class => 'icon icon-add', :remote => true %>
+
+<% end %>
+
diff --git a/app/views/dmsf_upload/_multi_upload.html.erb b/app/views/dmsf_upload/_multi_upload.html.erb
index 61dfa8c7..33c4a026 100644
--- a/app/views/dmsf_upload/_multi_upload.html.erb
+++ b/app/views/dmsf_upload/_multi_upload.html.erb
@@ -40,7 +40,7 @@
<%= l(:label_document_plural) %>
- <%= render :partial => 'dmsf_upload/form', :locals => { :multiple => true } %>
+ <%= render :partial => 'dmsf_upload/form', :locals => { :multiple => true, :container => nil } %>
<%= submit_tag l(:label_upload) %>
diff --git a/app/views/dmsf_workflows/assign.js.erb b/app/views/dmsf_workflows/assign.js.erb
index eae3c44a..8775ff4d 100644
--- a/app/views/dmsf_workflows/assign.js.erb
+++ b/app/views/dmsf_workflows/assign.js.erb
@@ -1,4 +1,5 @@
-<%# Redmine plugin for Document Management System "Features"
+<%
+# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-15 Karel Pičman
#
@@ -14,7 +15,8 @@
#
# 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.%>
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+%>
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'assign', :locals => {:workflow => @dmsf_workflow}) %>');
showModal('ajax-modal', '30%');
diff --git a/assets/javascripts/attachments_dmsf.js b/assets/javascripts/attachments_dmsf.js
index 79bd3f0b..fb07732a 100644
--- a/assets/javascripts/attachments_dmsf.js
+++ b/assets/javascripts/attachments_dmsf.js
@@ -19,6 +19,24 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+function dmsfAddLink(linksSpan, linkId, linkName) {
+
+ if (linksSpan.children().length < 10) {
+
+ var nextLinkId = dmsfAddLink.nextLinkId++;
+ var linkSpan = $('', { id: 'dmsf_links_' + nextLinkId });
+
+ linkSpan.append(
+ " ",
+ " ",
+ $(' ').attr({href: "#", 'class': 'remove-upload icon icon-del'}).click(dmsfRemoveFile),
+ " "
+ ).appendTo(linksSpan);
+ }
+}
+
+dmsfAddLink.nextLinkId = 1000;
+
function dmsfAddFile(inputEl, file, eagerUpload) {
if ($('#dmsf_attachments_fields').children().length < 10) {
diff --git a/assets/stylesheets/redmine_dmsf.css b/assets/stylesheets/redmine_dmsf.css
index a8b23830..e604d970 100644
--- a/assets/stylesheets/redmine_dmsf.css
+++ b/assets/stylesheets/redmine_dmsf.css
@@ -319,3 +319,5 @@ div.dmsf_revision_inner_box .attribute .label {
#dmsf_attachments_fields .ajax-loading input.filename {background:url(../../../images/loading.gif) no-repeat 0px 50%;}
#dmsf_attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; }
+#dmsf_links_fields span {display:block; white-space:nowrap;}
+#dmsf_links_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../../../images/link.png) no-repeat 1px 50%; padding-left:18px;}
diff --git a/config/routes.rb b/config/routes.rb
index d9c4ed67..0b520590 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -151,6 +151,8 @@ if Redmine::Plugin.installed? :redmine_dmsf
resources :dmsf_links do
member do
get 'restore'
+ get 'autocomplete_for_project'
+ get 'autocomplete_for_folder'
end
end
diff --git a/init.rb b/init.rb
index cbeb5bb9..e6eeb30b 100644
--- a/init.rb
+++ b/init.rb
@@ -89,7 +89,7 @@ Redmine::Plugin.register :redmine_dmsf do
permission :file_manipulation,
{ :dmsf_files => [:create_revision, :lock, :unlock, :delete_revision, :notify_activate, :notify_deactivate, :restore],
:dmsf_upload => [:upload_files, :upload_file, :upload, :commit_files, :commit, :delete_dmsf_attachment],
- :dmsf_links => [:new, :create, :destroy, :restore] }
+ :dmsf_links => [:new, :create, :destroy, :restore, :autocomplete_for_project, :autocomplete_for_folder] }
permission :file_delete,
{ :dmsf => [:trash, :delete_entries],
:dmsf_files => [:delete] }
diff --git a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb
index 55196d28..95997bc7 100644
--- a/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb
+++ b/lib/redmine_dmsf/hooks/controllers/issues_controller_hooks.rb
@@ -59,6 +59,7 @@ module RedmineDmsf
issue = context[:issue]
params = context[:params]
issue.save_dmsf_attachments(params[:dmsf_attachments])
+ issue.save_dmsf_links(params[:dmsf_links])
end
end
@@ -85,6 +86,21 @@ module RedmineDmsf
DmsfUploadHelper.commit_files_internal uploaded_files, issue.project, system_folder,
context[:controller]
end
+ dmsf_links = params[:dmsf_links]
+ if dmsf_links && dmsf_links.is_a?(Hash)
+ system_folder = issue.system_folder(true)
+ ids = dmsf_links.map(&:last)
+ ids.each do |id|
+ l = DmsfLink.find_by_id(id)
+ if l
+ l.project_id = system_folder.project_id
+ l.dmsf_folder_id = system_folder.id
+ if l.save
+ issue.dmsf_file_added l.target_file
+ end
+ end
+ end
+ end
end
end
diff --git a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb
index 3d27624a..9ef24dd0 100644
--- a/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb
+++ b/lib/redmine_dmsf/hooks/views/issue_view_hooks.rb
@@ -49,7 +49,8 @@ module RedmineDmsf
if User.current.allowed_to?(:view_dmsf_files, issue.project) &&
Setting.plugin_redmine_dmsf['dmsf_act_as_attachable']
context[:controller].send(:render_to_string, {:partial => 'dmsf_files/links',
- :locals => { :dmsf_files => issue.dmsf_files.to_a, :thumbnails => Setting.thumbnails_enabled? }})
+ :locals => { :dmsf_files => issue.dmsf_files, :dmsf_links => issue.dmsf_links,
+ :thumbnails => Setting.thumbnails_enabled? }})
end
end
end
diff --git a/lib/redmine_dmsf/patches/issue_patch.rb b/lib/redmine_dmsf/patches/issue_patch.rb
index f3857de2..1437f3e7 100644
--- a/lib/redmine_dmsf/patches/issue_patch.rb
+++ b/lib/redmine_dmsf/patches/issue_patch.rb
@@ -34,10 +34,12 @@ module RedmineDmsf
def save_dmsf_attachments(dmsf_attachments)
@saved_dmsf_attachments = []
- dmsf_attachments = dmsf_attachments.map(&:last)
- dmsf_attachments.each do |dmsf_attachment|
- a = Attachment.find_by_token(dmsf_attachment[:token])
- @saved_dmsf_attachments << a if a
+ if dmsf_attachments
+ dmsf_attachments = dmsf_attachments.map(&:last)
+ dmsf_attachments.each do |dmsf_attachment|
+ a = Attachment.find_by_token(dmsf_attachment[:token])
+ @saved_dmsf_attachments << a if a
+ end
end
end
@@ -45,6 +47,21 @@ module RedmineDmsf
@saved_dmsf_attachments || []
end
+ def save_dmsf_links(dmsf_links)
+ @saved_dmsf_links = []
+ if dmsf_links
+ ids = dmsf_links.map(&:last)
+ ids.each do |id|
+ l = DmsfLink.find_by_id(id)
+ @saved_dmsf_links << l if l
+ end
+ end
+ end
+
+ def saved_dmsf_links
+ @saved_dmsf_links || []
+ end
+
def system_folder(create = false)
parent = DmsfFolder.system.where(:project_id => self.project_id, :title => '.Issues').first
if create && !parent
@@ -73,8 +90,21 @@ module RedmineDmsf
end
def dmsf_files
+ files = []
folder = self.system_folder
- folder.dmsf_files if folder
+ if folder
+ files = folder.dmsf_files.to_a
+ end
+ files
+ end
+
+ def dmsf_links
+ links = []
+ folder = self.system_folder
+ if folder
+ links = folder.dmsf_links
+ end
+ links
end
def delete_system_folder
@@ -105,6 +135,7 @@ module RedmineDmsf
)
current_journal.save
end
+
end
end
diff --git a/lib/tasks/dmsf_maintenance.rake b/lib/tasks/dmsf_maintenance.rake
index b69c7322..16b8f2d8 100644
--- a/lib/tasks/dmsf_maintenance.rake
+++ b/lib/tasks/dmsf_maintenance.rake
@@ -18,10 +18,11 @@
desc <<-END_DESC
DMSF maintenance task
- * Remove all files and folders with no database record from the document directory
+ * Remove all files with no database record from the document directory
+ * Remove all links project_id = -1 (added links to an issue which hasn't been created)
Available options:
- *dry_run - No physical deletion but to list of all unused files and folders only
+ *dry_run - No physical deletion but to list of all unused files only
Example:
rake redmine:dmsf_maintenance RAILS_ENV="production"
@@ -34,7 +35,7 @@ namespace :redmine do
begin
STDERR.puts "\n"
Dir.chdir(DmsfFile.storage_path)
- m.files
+ m.files
if m.dry_run
m.result
else
@@ -54,54 +55,41 @@ class DmsfMaintenance
def initialize
@dry_run = ENV['dry_run']
- @folders_to_delete = Array.new
@files_to_delete = Array.new
end
def files
Dir.glob("**/*").each do |f|
- if Dir.exist?(f)
- check_dir f
- else
+ unless Dir.exist?(f)
check_file f
end
end
end
- def result
- if (@files_to_delete.count == 0) && (@folders_to_delete.count == 0)
- puts "\nNo orphens!\n\n"
- return
- end
+ def result
# Files
size = 0
@files_to_delete.each{ |f| size += File.size(f) }
- puts "\n#{@files_to_delete.count} files havn't got a coresponding revision and can be deleted"
- puts "#{number_to_human_size(size)} can be released\n\n"
-
- # Projects
- puts "\n#{@folders_to_delete.count} directories havn't got coresponding projects and can be deleted\n\n" if(@folders_to_delete.count > 0)
+ puts "\n#{@files_to_delete.count} files havn't got a coresponding revision and can be deleted."
+ puts "#{number_to_human_size(size)} can be released.\n\n"
+ # Links
+ size = DmsfLink.where(:project_id => -1).count
+ puts "#{size} links can be deleted.\n\n"
end
- def clean
- if (@files_to_delete.count == 0) && (@folders_to_delete.count == 0)
- puts "\nNo orphens!\n\n"
- return
- end
+ def clean
# Files
size = 0
@files_to_delete.each do |f|
size += File.size(f)
File.delete f
end
- puts "\n#{@files_to_delete.count} files hadn't got a coresponding revision and have been be deleted" if(@files_to_delete.count > 0)
- puts "#{number_to_human_size(size)} has been released\n\n" if(@files_to_delete.count > 0)
-
- # Projects
- @folders_to_delete.each do |d|
- Dir.delete d
- end
- puts "\n#{@folders_to_delete.count} directories hadn't got a coresponding projects and have been deleted\n\n" if(@folders_to_delete.count > 0)
+ puts "\n#{@files_to_delete.count} files hadn't got a coresponding revision and have been be deleted."
+ puts "#{number_to_human_size(size)} has been released\n\n"
+ # Links
+ size = DmsfLink.where(:project_id => -1).count
+ DmsfLink.delete_all(:project_id => -1)
+ puts "#{size} links have been deleted.\n\n"
end
private
@@ -118,18 +106,5 @@ class DmsfMaintenance
STDERR.puts "\t#{file} doesn't seem to be a DMSF file!"
end
end
-
- def check_dir(directory)
- name = Pathname.new(directory).basename.to_s
- if name =~ /^p_(.*)/
- p = Project.find_by_identifier $1
- unless p
- @folders_to_delete << name
- puts "\t#{name}"
- end
- else
- STDERR.puts "\t#{directory} doesn't seem to be a DMSF folder!"
- end
- end
end
\ No newline at end of file