Linking Issues and DMSF Documents #48
This commit is contained in:
parent
94fad6275b
commit
65820f97f3
@ -66,7 +66,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(:project_id => @project.id)
|
||||
@files = DmsfFile.deleted.where(:container_id => @project.id, :container_type => 'Project')
|
||||
@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')
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
|
||||
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
|
||||
# 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
|
||||
@ -24,8 +24,9 @@ class DmsfUploadController < ApplicationController
|
||||
|
||||
menu_item :dmsf
|
||||
|
||||
before_filter :find_project
|
||||
before_filter :authorize
|
||||
before_filter :find_project, :except => [:upload]
|
||||
before_filter :authorize, :except => [:upload]
|
||||
before_filter :authorize_global, :only => [:upload]
|
||||
before_filter :find_folder, :except => [:upload_file, :upload, :commit]
|
||||
|
||||
helper :all
|
||||
@ -34,7 +35,7 @@ class DmsfUploadController < ApplicationController
|
||||
accept_api_auth :upload, :commit
|
||||
|
||||
def upload_files
|
||||
uploaded_files = params[:attachments]
|
||||
uploaded_files = params[:dmsf_attachments]
|
||||
@uploads = []
|
||||
if uploaded_files && uploaded_files.is_a?(Hash)
|
||||
# standard file input uploads
|
||||
@ -134,129 +135,12 @@ class DmsfUploadController < ApplicationController
|
||||
private
|
||||
|
||||
def commit_files_internal(commited_files)
|
||||
if commited_files && commited_files.is_a?(Hash)
|
||||
@files = []
|
||||
failed_uploads = []
|
||||
commited_files.each_value do |commited_file|
|
||||
name = commited_file[:name]
|
||||
|
||||
new_revision = DmsfFileRevision.new
|
||||
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
|
||||
end
|
||||
|
||||
unless file
|
||||
file = DmsfFile.new
|
||||
file.project = @project
|
||||
file.name = name
|
||||
file.dmsf_folder = @folder
|
||||
file.notification = Setting.plugin_redmine_dmsf[:dmsf_default_notifications].present?
|
||||
new_revision.minor_version = 0
|
||||
new_revision.major_version = 0
|
||||
else
|
||||
if file.last_revision
|
||||
last_revision = file.last_revision
|
||||
new_revision.source_revision = last_revision
|
||||
new_revision.major_version = last_revision.major_version
|
||||
new_revision.minor_version = last_revision.minor_version
|
||||
else
|
||||
new_revision.minor_version = 0
|
||||
new_revision.major_version = 0
|
||||
end
|
||||
end
|
||||
|
||||
if file.locked_for_user?
|
||||
failed_uploads.push(commited_file)
|
||||
next
|
||||
end
|
||||
|
||||
commited_disk_filepath = "#{DmsfHelper.temp_dir}/#{commited_file[:disk_filename].gsub(/[\/\\]/,'')}"
|
||||
|
||||
new_revision.dmsf_file = file
|
||||
new_revision.user = User.current
|
||||
new_revision.name = name
|
||||
new_revision.title = commited_file[:title]
|
||||
new_revision.description = commited_file[:description]
|
||||
new_revision.comment = commited_file[:comment]
|
||||
version = commited_file[:version].to_i
|
||||
if version == 3
|
||||
new_revision.major_version = commited_file[:custom_version_major].to_i
|
||||
new_revision.minor_version = commited_file[:custom_version_minor].to_i
|
||||
else
|
||||
new_revision.increase_version(version)
|
||||
end
|
||||
new_revision.mime_type = Redmine::MimeType.of(new_revision.name)
|
||||
new_revision.size = File.size(commited_disk_filepath)
|
||||
new_revision.digest = DmsfFileRevision.create_digest commited_disk_filepath
|
||||
|
||||
# Need to save file first to generate id for it in case of creation.
|
||||
# File id is needed to properly generate revision disk filename
|
||||
if commited_file[:dmsf_file_revision].present?
|
||||
commited_file[:dmsf_file_revision][:custom_field_values].each_with_index do |v, i|
|
||||
new_revision.custom_field_values[i].value = v[1]
|
||||
end
|
||||
end
|
||||
|
||||
if new_revision.valid? && file.save
|
||||
new_revision.disk_filename = new_revision.new_storage_filename
|
||||
else
|
||||
failed_uploads.push(commited_file)
|
||||
next
|
||||
end
|
||||
|
||||
if new_revision.save
|
||||
new_revision.assign_workflow(commited_file[:dmsf_workflow_id])
|
||||
begin
|
||||
FileUtils.mv(commited_disk_filepath, new_revision.disk_file)
|
||||
file.set_last_revision new_revision
|
||||
@files.push(file)
|
||||
rescue Exception => e
|
||||
Rails.logger.error e.message
|
||||
flash[:error] = e.message
|
||||
failed_uploads.push(file)
|
||||
end
|
||||
else
|
||||
failed_uploads.push(commited_file)
|
||||
end
|
||||
end
|
||||
unless @files.empty?
|
||||
@files.each { |file| log_activity(file, 'uploaded') if file }
|
||||
if (@folder && @folder.notification?) || (!@folder && @project.dmsf_notification?)
|
||||
begin
|
||||
recipients = DmsfMailer.get_notify_users(@project, @files)
|
||||
recipients.each do |u|
|
||||
DmsfMailer.files_updated(u, @project, @files).deliver
|
||||
end
|
||||
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
|
||||
unless recipients.empty?
|
||||
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
|
||||
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
|
||||
flash[:warning] = l(:warning_email_notifications, :to => to)
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
Rails.logger.error "Could not send email notifications: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
unless failed_uploads.empty?
|
||||
flash[:warning] = l(:warning_some_files_were_not_commited, :files => failed_uploads.map{|u| u['name']}.join(', '))
|
||||
end
|
||||
end
|
||||
DmsfUploadHelper.commit_files_internal(commited_files, @project, @folder)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.api {
|
||||
render_validation_errors(failed_uploads) unless failed_uploads.empty?
|
||||
}
|
||||
format.api { render_validation_errors(failed_uploads) unless failed_uploads.empty? }
|
||||
format.html { redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def log_activity(file, action)
|
||||
Rails.logger.info "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} #{User.current.login}@#{request.remote_ip}/#{request.env['HTTP_X_FORWARDED_FOR']}: #{action} dmsf://#{file.project.identifier}/#{file.id}/#{file.last_revision.id}"
|
||||
end
|
||||
|
||||
def find_folder
|
||||
|
||||
146
app/helpers/dmsf_upload_helper.rb
Normal file
146
app/helpers/dmsf_upload_helper.rb
Normal file
@ -0,0 +1,146 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2011-17 Karel Pičman <karel.picman@lbcfree.net>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module DmsfUploadHelper
|
||||
|
||||
def self.commit_files_internal(commited_files, container, folder = nil)
|
||||
if container.is_a?(Project)
|
||||
project = container
|
||||
else
|
||||
project = container.project
|
||||
end
|
||||
if commited_files && commited_files.is_a?(Hash)
|
||||
files = []
|
||||
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)
|
||||
unless file
|
||||
link = DmsfLink.find_link_by_file_name(project, folder, name)
|
||||
file = link.target_file if link
|
||||
end
|
||||
|
||||
unless file
|
||||
file = DmsfFile.new
|
||||
file.container_type = container.class.name.demodulize
|
||||
file.container_id = container.id
|
||||
#file.project = project if container_type == 'Project'
|
||||
file.name = name
|
||||
file.dmsf_folder = folder
|
||||
file.notification = Setting.plugin_redmine_dmsf[:dmsf_default_notifications].present?
|
||||
new_revision.minor_version = 0
|
||||
new_revision.major_version = 0
|
||||
else
|
||||
if file.last_revision
|
||||
last_revision = file.last_revision
|
||||
new_revision.source_revision = last_revision
|
||||
new_revision.major_version = last_revision.major_version
|
||||
new_revision.minor_version = last_revision.minor_version
|
||||
else
|
||||
new_revision.minor_version = 0
|
||||
new_revision.major_version = 0
|
||||
end
|
||||
end
|
||||
|
||||
if file.locked_for_user?
|
||||
failed_uploads.push(commited_file)
|
||||
next
|
||||
end
|
||||
|
||||
commited_disk_filepath = "#{DmsfHelper.temp_dir}/#{commited_file[:disk_filename].gsub(/[\/\\]/,'')}"
|
||||
|
||||
new_revision.dmsf_file = file
|
||||
new_revision.user = User.current
|
||||
new_revision.name = name
|
||||
new_revision.title = commited_file[:title]
|
||||
new_revision.description = commited_file[:description]
|
||||
new_revision.comment = commited_file[:comment]
|
||||
version = commited_file[:version].to_i
|
||||
if version == 3
|
||||
new_revision.major_version = commited_file[:custom_version_major].to_i
|
||||
new_revision.minor_version = commited_file[:custom_version_minor].to_i
|
||||
else
|
||||
new_revision.increase_version(version)
|
||||
end
|
||||
new_revision.mime_type = Redmine::MimeType.of(new_revision.name)
|
||||
new_revision.size = File.size(commited_disk_filepath)
|
||||
new_revision.digest = DmsfFileRevision.create_digest commited_disk_filepath
|
||||
|
||||
# Need to save file first to generate id for it in case of creation.
|
||||
# File id is needed to properly generate revision disk filename
|
||||
if commited_file[:dmsf_file_revision].present?
|
||||
commited_file[:dmsf_file_revision][:custom_field_values].each_with_index do |v, i|
|
||||
new_revision.custom_field_values[i].value = v[1]
|
||||
end
|
||||
end
|
||||
|
||||
if new_revision.valid? && file.save
|
||||
new_revision.disk_filename = new_revision.new_storage_filename
|
||||
else
|
||||
Rails.logger.error (new_revision.errors + file.errors).full_messages.to_sentence
|
||||
failed_uploads.push(commited_file)
|
||||
next
|
||||
end
|
||||
|
||||
if new_revision.save
|
||||
new_revision.assign_workflow(commited_file[:dmsf_workflow_id])
|
||||
begin
|
||||
FileUtils.mv(commited_disk_filepath, new_revision.disk_file)
|
||||
file.set_last_revision new_revision
|
||||
files.push(file)
|
||||
rescue Exception => e
|
||||
Rails.logger.error e.message
|
||||
#flash[:error] = e.message
|
||||
failed_uploads.push(file)
|
||||
end
|
||||
else
|
||||
failed_uploads.push(commited_file)
|
||||
end
|
||||
end
|
||||
#unless files.empty?
|
||||
#files.each do |file|
|
||||
#Rails.logger.info "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} #{User.current.login}: uploaded dmsf://#{file.project.identifier}/#{file.id}/#{file.last_revision.id}"
|
||||
#end
|
||||
#end
|
||||
if container.is_a?(Project) && ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
|
||||
begin
|
||||
recipients = DmsfMailer.get_notify_users(project, files)
|
||||
recipients.each do |u|
|
||||
DmsfMailer.files_updated(u, project, files).deliver
|
||||
end
|
||||
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
|
||||
unless recipients.empty?
|
||||
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
|
||||
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
|
||||
#flash[:warning] = l(:warning_email_notifications, :to => to)
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
Rails.logger.error "Could not send email notifications: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
unless failed_uploads.empty?
|
||||
#flash[:warning] = l(:warning_some_files_were_not_commited, :files => failed_uploads.map{|u| u['name']}.join(', '))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@ -3,7 +3,7 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
|
||||
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
|
||||
# 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
|
||||
@ -32,7 +32,6 @@ 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'
|
||||
|
||||
@ -56,10 +55,11 @@ class DmsfFile < ActiveRecord::Base
|
||||
|
||||
validate :validates_name_uniqueness
|
||||
|
||||
attr_accessible :project, :project_id
|
||||
|
||||
def validates_name_uniqueness
|
||||
existing_file = DmsfFile.visible.find_file_by_name(self.project, self.dmsf_folder, self.name)
|
||||
errors.add(:name, l('activerecord.errors.messages.taken')) unless
|
||||
existing_file.nil? || existing_file.id == self.id
|
||||
existing_file = DmsfFile.visible.findn_file_by_name(self.container_id, self.container_type, self.dmsf_folder, self.name)
|
||||
errors.add(:name, l('activerecord.errors.messages.taken')) unless (existing_file.nil? || existing_file.id == self.id)
|
||||
end
|
||||
|
||||
acts_as_event :title => Proc.new { |o| o.name },
|
||||
@ -115,9 +115,14 @@ class DmsfFile < ActiveRecord::Base
|
||||
@@storage_path = path
|
||||
end
|
||||
|
||||
def self.find_file_by_name(project, folder, name)
|
||||
def self.find_file_by_name(container, folder, name)
|
||||
self.findn_file_by_name(container.id, container.class.name.demodulize, folder, name)
|
||||
end
|
||||
|
||||
def self.findn_file_by_name(container_id, container_type, folder, name)
|
||||
where(
|
||||
:project_id => project,
|
||||
:container_id => container_id,
|
||||
:container_type => container_type,
|
||||
:dmsf_folder_id => folder ? folder.id : nil,
|
||||
:name => name).visible.first
|
||||
end
|
||||
@ -273,6 +278,7 @@ class DmsfFile < ActiveRecord::Base
|
||||
|
||||
file = DmsfFile.new
|
||||
file.dmsf_folder = folder
|
||||
file.container_type = 'Project'
|
||||
file.project = project
|
||||
file.name = self.name
|
||||
file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present?
|
||||
@ -533,4 +539,39 @@ 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 project=(project)
|
||||
case self.container_type
|
||||
when 'Project'
|
||||
self.container_id = project.id
|
||||
else
|
||||
raise Exception.new('The container type is not project!')
|
||||
end
|
||||
end
|
||||
|
||||
def project_id
|
||||
self.project.id if self.project
|
||||
end
|
||||
|
||||
def project_id=(project_id)
|
||||
case self.container_type
|
||||
when 'Project'
|
||||
self.container_id = project_id
|
||||
else
|
||||
raise Exception.new('The container type is not project!')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -51,8 +51,8 @@ class DmsfFileRevision < ActiveRecord::Base
|
||||
:scope => select("#{DmsfFileRevision.table_name}.*").
|
||||
joins(
|
||||
"INNER JOIN #{DmsfFile.table_name} ON #{DmsfFileRevision.table_name}.dmsf_file_id = #{DmsfFile.table_name}.id " +
|
||||
"INNER JOIN #{Project.table_name} ON #{DmsfFile.table_name}.project_id = #{Project.table_name}.id").
|
||||
where("#{DmsfFile.table_name}.deleted = ?", STATUS_ACTIVE)
|
||||
"INNER 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 = ?", STATUS_ACTIVE, 'Project')
|
||||
|
||||
validates :title, :presence => true
|
||||
validates_format_of :name, :with => DmsfFolder::INVALID_CHARACTERS,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
|
||||
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
|
||||
# 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
|
||||
@ -44,6 +44,6 @@ class DmsfFileRevisionAccess < ActiveRecord::Base
|
||||
joins(
|
||||
"INNER JOIN #{DmsfFileRevision.table_name} ON #{DmsfFileRevisionAccess.table_name}.dmsf_file_revision_id = #{DmsfFileRevision.table_name}.id " +
|
||||
"INNER JOIN #{DmsfFile.table_name} ON #{DmsfFileRevision.table_name}.dmsf_file_id = #{DmsfFile.table_name}.id " +
|
||||
"INNER JOIN #{Project.table_name} ON #{DmsfFile.table_name}.project_id = #{Project.table_name}.id").
|
||||
where("#{DmsfFile.table_name}.deleted = ?", DmsfFile::STATUS_ACTIVE)
|
||||
"INNER 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')
|
||||
end
|
||||
|
||||
@ -76,7 +76,8 @@ class DmsfUpload
|
||||
@minor_version = 0
|
||||
@workflow = nil
|
||||
file = DmsfFile.new
|
||||
file.project = @project
|
||||
file.container_type = 'Project'
|
||||
file.project = project
|
||||
revision = DmsfFileRevision.new
|
||||
revision.dmsf_file = file
|
||||
@custom_values = revision.custom_field_values
|
||||
|
||||
@ -106,9 +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.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]
|
||||
'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']
|
||||
elsif project
|
||||
sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?)', project.id]
|
||||
else
|
||||
|
||||
@ -178,7 +178,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(:project_id => @project.id).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(: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}" %>";
|
||||
<% 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}" %>";
|
||||
|
||||
44
app/views/dmsf_files/_links.html.erb
Normal file
44
app/views/dmsf_files/_links.html.erb
Normal file
@ -0,0 +1,44 @@
|
||||
<%
|
||||
# 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.
|
||||
%>
|
||||
|
||||
<hr/>
|
||||
<div class="attachments">
|
||||
<% for dmsf_file in dmsf_files %>
|
||||
<p>
|
||||
<% file_view_url = url_for({:controller => :dmsf_files, :action => 'view', :id => dmsf_file}) %>
|
||||
<%= link_to(h(dmsf_file.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}") %>
|
||||
<%= " - #{dmsf_file.description}" unless dmsf_file.description.blank? %>
|
||||
<span class="size">(<%= number_to_human_size dmsf_file.last_revision.size %>)</span>
|
||||
<%= link_to(image_tag('delete.png'),
|
||||
dmsf_file_path(:id => dmsf_file),
|
||||
:data => {:confirm => l(:text_are_you_sure)},
|
||||
:method => :delete,
|
||||
:title => l(:title_delete)) %>
|
||||
<span class="author"><%= dmsf_file.last_revision.user %>, <%= format_time(dmsf_file.last_revision.updated_at) %></span>
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
@ -1,36 +0,0 @@
|
||||
<% hide = false %>
|
||||
|
||||
<span id="attachments_fields">
|
||||
<% if defined?(container) && container && container.saved_attachments %>
|
||||
<% container.saved_attachments.each_with_index do |attachment, i| %>
|
||||
<span id="attachments_p<%= i %>">
|
||||
<%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename') %>
|
||||
<%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %>
|
||||
<% hide = true %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<% unless hide %>
|
||||
<span class="add_attachment">
|
||||
<%= file_field_tag 'attachments[dummy][file]',
|
||||
:id => nil,
|
||||
:class => 'file_selector',
|
||||
:multiple => false,
|
||||
:onchange => 'addInputFile(this);',
|
||||
:data => {
|
||||
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
|
||||
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
|
||||
:max_file_count_message => l(:error_maximum_upload_filecount, :filecount => 1),
|
||||
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
|
||||
:upload_path => uploads_path(:format => 'js'),
|
||||
:description_placeholder => l(:label_optional_description)
|
||||
} %>
|
||||
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'attachments_dmsf', :plugin => 'redmine_dmsf' %>
|
||||
<% end %>
|
||||
49
app/views/dmsf_upload/_form.html.erb
Normal file
49
app/views/dmsf_upload/_form.html.erb
Normal file
@ -0,0 +1,49 @@
|
||||
<%
|
||||
# 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.
|
||||
%>
|
||||
|
||||
<span id="dmsf_attachments_fields">
|
||||
<% if defined?(container) && container && container.saved_attachments %>
|
||||
<% container.saved_attachments.each_with_index do |attachment, i| %>
|
||||
<span id="dmsf_attachments_p<%= i %>">
|
||||
<%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') +
|
||||
text_field_tag("dmsf_attachments[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description') +
|
||||
link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %>
|
||||
<%= hidden_field_tag "dmsf_attachments[p#{i}][token]", "#{attachment.token}" %>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</span>
|
||||
<span class="dmsf_add_attachment">
|
||||
<%= file_field_tag 'dmsf_attachments[dummy][file]',
|
||||
:id => nil,
|
||||
:class => 'file_selector',
|
||||
:multiple => true,
|
||||
:onchange => 'dmsfAddInputFiles(this);',
|
||||
:data => {
|
||||
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
|
||||
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
|
||||
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
|
||||
:upload_path => dmsf_uploads_path(:format => 'js'),
|
||||
:description_placeholder => l(:label_optional_description)
|
||||
} %>
|
||||
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
|
||||
</span>
|
||||
@ -36,11 +36,11 @@
|
||||
|
||||
<%= form_tag({:controller => 'dmsf_upload', :action => 'upload_files', :id => @project, :folder_id => @folder},
|
||||
:id => 'uploadform', :method => :post, :multipart => true) do %>
|
||||
<div id="uploader">
|
||||
<div class="box">
|
||||
<div id="dmsf_uploader">
|
||||
<div class="dmsf_uploader">
|
||||
<p>
|
||||
<label><%= l(:label_attachment_plural) %></label>
|
||||
<%= render :partial => 'attachments/form' %>
|
||||
<label><%= l(:label_document_plural) %></label>
|
||||
<%= render :partial => 'dmsf_upload/form' %>
|
||||
</p>
|
||||
</div>
|
||||
<%= submit_tag l(:label_upload) %>
|
||||
@ -49,14 +49,14 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
var originalUploaderContent;
|
||||
var uploader = $('#uploader');
|
||||
var uploader = $('#dmsf_uploader');
|
||||
|
||||
originalUploaderContent = uploader.html();
|
||||
|
||||
$('#uploader_select').change(function() {
|
||||
if($(this).val() === '2') {
|
||||
uploader.html(originalUploaderContent);
|
||||
setupFileDrop();
|
||||
dmsfSetupFileDrop();
|
||||
} else {
|
||||
initPlUploader(uploader);
|
||||
}
|
||||
|
||||
36
app/views/dmsf_upload/upload.js.erb
Normal file
36
app/views/dmsf_upload/upload.js.erb
Normal file
@ -0,0 +1,36 @@
|
||||
<%
|
||||
# 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.
|
||||
%>
|
||||
|
||||
var fileSpan = $('#dmsf_attachments_<%= j params[:attachment_id] %>');
|
||||
<% if @attachment.new_record? %>
|
||||
fileSpan.hide();
|
||||
alert("<%= escape_javascript @attachment.errors.full_messages.join(', ') %>");
|
||||
<% else %>
|
||||
$('<input>', { type: 'hidden', name: 'dmsf_attachments[<%= j params[:attachment_id] %>][token]' } ).val('<%= j @attachment.token %>').appendTo(fileSpan);
|
||||
fileSpan.find('a.remove-upload')
|
||||
.attr({
|
||||
"data-remote": true,
|
||||
"data-method": 'delete',
|
||||
href: '<%= j attachment_path(@attachment, :attachment_id => params[:attachment_id], :format => 'js') %>'
|
||||
})
|
||||
.off('click');
|
||||
<% end %>
|
||||
@ -1,206 +1,191 @@
|
||||
/* Redmine - project management software
|
||||
Copyright (C) 2006-2016 Jean-Philippe Lang */
|
||||
Copyright (C) 2006-2016 Jean-Philippe Lang */
|
||||
|
||||
function addFile(inputEl, file, eagerUpload) {
|
||||
function dmsfAddFile(inputEl, file, eagerUpload) {
|
||||
|
||||
if ($('#attachments_fields').children().length < 10) {
|
||||
if ($('#dmsf_attachments_fields').children().length < 10) {
|
||||
|
||||
var attachmentId = addFile.nextAttachmentId++;
|
||||
var attachmentId = dmsfAddFile.nextAttachmentId++;
|
||||
|
||||
var fileSpan = $('<span>', { id: 'attachments_' + attachmentId });
|
||||
var fileSpan = $('<span>', { id: 'dmsf_attachments_' + attachmentId });
|
||||
|
||||
fileSpan.append(
|
||||
$('<input>', { type: 'text', 'class': 'filename readonly', name: 'attachments[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name)
|
||||
).appendTo('#attachments_fields');
|
||||
fileSpan.append(
|
||||
$('<input>', { type: 'text', 'class': 'filename readonly', name: 'dmsf_attachments[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name),
|
||||
$('<input>', { type: 'text', 'class': 'description', name: 'dmsf_attachments[' + attachmentId + '][description]', maxlength: 255, placeholder: $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload),
|
||||
$('<a> </a>').attr({ href: "#", 'class': 'remove-upload' }).click(dmsfRemoveFile).toggle(!eagerUpload)
|
||||
).appendTo('#dmsf_attachments_fields');
|
||||
|
||||
if(eagerUpload) {
|
||||
ajaxUpload(file, attachmentId, fileSpan, inputEl);
|
||||
}
|
||||
|
||||
toggleFileAdding(false);
|
||||
$('#dmsf_file_revision_name').val(file.name);
|
||||
|
||||
return attachmentId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
addFile.nextAttachmentId = 1;
|
||||
|
||||
function ajaxUpload(file, attachmentId, fileSpan, inputEl) {
|
||||
|
||||
function onLoadstart(e) {
|
||||
fileSpan.removeClass('ajax-waiting');
|
||||
fileSpan.addClass('ajax-loading');
|
||||
$('input:submit', $(this).parents('form')).attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
function onProgress(e) {
|
||||
if(e.lengthComputable) {
|
||||
this.progressbar( 'value', e.loaded * 100 / e.total );
|
||||
}
|
||||
}
|
||||
|
||||
function actualUpload(file, attachmentId, fileSpan, inputEl) {
|
||||
|
||||
ajaxUpload.uploading++;
|
||||
|
||||
uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, {
|
||||
loadstartEventHandler: onLoadstart.bind(progressSpan),
|
||||
progressEventHandler: onProgress.bind(progressSpan)
|
||||
})
|
||||
.done(function(result) {
|
||||
progressSpan.progressbar( 'value', 100 ).remove();
|
||||
fileSpan.find('input.description, a').css('display', 'inline-block');
|
||||
})
|
||||
.fail(function(result) {
|
||||
progressSpan.text(result.statusText);
|
||||
}).always(function() {
|
||||
ajaxUpload.uploading--;
|
||||
fileSpan.removeClass('ajax-loading');
|
||||
var form = fileSpan.parents('form');
|
||||
if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) {
|
||||
$('input:submit', form).removeAttr('disabled');
|
||||
if(eagerUpload) {
|
||||
dmsfAjaxUpload(file, attachmentId, fileSpan, inputEl);
|
||||
}
|
||||
form.dequeue('upload');
|
||||
});
|
||||
}
|
||||
|
||||
var progressSpan = $('<div>').insertAfter(fileSpan.find('input.filename'));
|
||||
progressSpan.progressbar();
|
||||
fileSpan.addClass('ajax-waiting');
|
||||
|
||||
var maxSyncUpload = $(inputEl).data('max-concurrent-uploads');
|
||||
|
||||
if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload)
|
||||
actualUpload(file, attachmentId, fileSpan, inputEl);
|
||||
else
|
||||
$(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl));
|
||||
}
|
||||
|
||||
ajaxUpload.uploading = 0;
|
||||
|
||||
function removeFile() {
|
||||
|
||||
$(this).parent('span').remove();
|
||||
toggleFileAdding(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
function uploadBlob(blob, uploadUrl, attachmentId, options) {
|
||||
|
||||
var actualOptions = $.extend({
|
||||
loadstartEventHandler: $.noop,
|
||||
progressEventHandler: $.noop
|
||||
}, options);
|
||||
|
||||
uploadUrl = uploadUrl + '?attachment_id=' + attachmentId;
|
||||
if (blob instanceof window.File) {
|
||||
uploadUrl += '&filename=' + encodeURIComponent(blob.name);
|
||||
uploadUrl += '&content_type=' + encodeURIComponent(blob.type);
|
||||
}
|
||||
|
||||
return $.ajax(uploadUrl, {
|
||||
type: 'POST',
|
||||
contentType: 'application/octet-stream',
|
||||
beforeSend: function(jqXhr, settings) {
|
||||
jqXhr.setRequestHeader('Accept', 'application/js');
|
||||
// attach proper File object
|
||||
settings.data = blob;
|
||||
},
|
||||
xhr: function() {
|
||||
var xhr = $.ajaxSettings.xhr();
|
||||
xhr.upload.onloadstart = actualOptions.loadstartEventHandler;
|
||||
xhr.upload.onprogress = actualOptions.progressEventHandler;
|
||||
return xhr;
|
||||
},
|
||||
data: blob,
|
||||
cache: false,
|
||||
processData: false
|
||||
});
|
||||
}
|
||||
|
||||
function addInputFile(inputEl) {
|
||||
var clearedFileInput = $(inputEl).clone().val('');
|
||||
|
||||
if ($.ajaxSettings.xhr().upload && inputEl.files) {
|
||||
// upload files using ajax
|
||||
uploadAndAttachFiles(inputEl.files, inputEl);
|
||||
$(inputEl).remove();
|
||||
} else {
|
||||
// browser not supporting the file API, upload on form submission
|
||||
var attachmentId;
|
||||
var aFilename = inputEl.value.split(/\/|\\/);
|
||||
attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false);
|
||||
if (attachmentId) {
|
||||
$(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId);
|
||||
return attachmentId;
|
||||
}
|
||||
}
|
||||
|
||||
clearedFileInput.insertAfter('#attachments_fields');
|
||||
|
||||
toggleFileAdding(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
function uploadAndAttachFiles(files, inputEl) {
|
||||
dmsfAddFile.nextAttachmentId = 1;
|
||||
|
||||
var maxFileSize = $(inputEl).data('max-file-size');
|
||||
var maxFileSizeExceeded = $(inputEl).data('max-file-size-message');
|
||||
var maxFileCountExceeded = $(inputEl).data('max-file-count-message');
|
||||
function dmsfAjaxUpload(file, attachmentId, fileSpan, inputEl) {
|
||||
|
||||
var sizeExceeded = false;
|
||||
$.each(files, function() {
|
||||
if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;}
|
||||
});
|
||||
if((files.length > 1) || (!$('input.file_selector').is(':visible'))){
|
||||
window.alert(maxFileCountExceeded);
|
||||
}
|
||||
else if (sizeExceeded) {
|
||||
window.alert(maxFileSizeExceeded);
|
||||
} else {
|
||||
$.each(files, function() {addFile(inputEl, this, true);});
|
||||
}
|
||||
function onLoadstart(e) {
|
||||
fileSpan.removeClass('ajax-waiting');
|
||||
fileSpan.addClass('ajax-loading');
|
||||
$('input:submit', $(this).parents('form')).attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
function onProgress(e) {
|
||||
if(e.lengthComputable) {
|
||||
this.progressbar( 'value', e.loaded * 100 / e.total );
|
||||
}
|
||||
}
|
||||
|
||||
function actualUpload(file, attachmentId, fileSpan, inputEl) {
|
||||
|
||||
dmsfAjaxUpload.uploading++;
|
||||
|
||||
dmsfUploadBlob(file, $(inputEl).data('upload-path'), attachmentId, {
|
||||
loadstartEventHandler: onLoadstart.bind(progressSpan),
|
||||
progressEventHandler: onProgress.bind(progressSpan)
|
||||
})
|
||||
.done(function(result) {
|
||||
progressSpan.progressbar( 'value', 100 ).remove();
|
||||
fileSpan.find('input.description, a').css('display', 'inline-block');
|
||||
})
|
||||
.fail(function(result) {
|
||||
progressSpan.text(result.statusText);
|
||||
}).always(function() {
|
||||
dmsfAjaxUpload.uploading--;
|
||||
fileSpan.removeClass('ajax-loading');
|
||||
var form = fileSpan.parents('form');
|
||||
if (form.queue('upload').length == 0 && dmsfAjaxUpload.uploading == 0) {
|
||||
$('input:submit', form).removeAttr('disabled');
|
||||
}
|
||||
form.dequeue('upload');
|
||||
});
|
||||
}
|
||||
|
||||
var progressSpan = $('<div>').insertAfter(fileSpan.find('input.filename'));
|
||||
progressSpan.progressbar();
|
||||
fileSpan.addClass('ajax-waiting');
|
||||
|
||||
var maxSyncUpload = $(inputEl).data('max-concurrent-uploads');
|
||||
|
||||
if(maxSyncUpload == null || maxSyncUpload <= 0 || dmsfAjaxUpload.uploading < maxSyncUpload)
|
||||
actualUpload(file, attachmentId, fileSpan, inputEl);
|
||||
else
|
||||
$(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl));
|
||||
}
|
||||
|
||||
function toggleFileAdding(toggle){
|
||||
dmsfAjaxUpload.uploading = 0;
|
||||
|
||||
$('input.file_selector').toggle(toggle);
|
||||
$('span.add_attachment').toggle(toggle);
|
||||
function dmsfRemoveFile() {
|
||||
$(this).parent('span').remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleFileDropEvent(e) {
|
||||
function dmsfUploadBlob(blob, uploadUrl, attachmentId, options) {
|
||||
|
||||
$(this).removeClass('fileover');
|
||||
blockEventPropagation(e);
|
||||
var actualOptions = $.extend({
|
||||
loadstartEventHandler: $.noop,
|
||||
progressEventHandler: $.noop
|
||||
}, options);
|
||||
|
||||
if ($.inArray('Files', e.dataTransfer.types) > -1) {
|
||||
uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector'));
|
||||
}
|
||||
uploadUrl = uploadUrl + '?attachment_id=' + attachmentId;
|
||||
if (blob instanceof window.File) {
|
||||
uploadUrl += '&filename=' + encodeURIComponent(blob.name);
|
||||
uploadUrl += '&content_type=' + encodeURIComponent(blob.type);
|
||||
}
|
||||
|
||||
return $.ajax(uploadUrl, {
|
||||
type: 'POST',
|
||||
contentType: 'application/octet-stream',
|
||||
beforeSend: function(jqXhr, settings) {
|
||||
jqXhr.setRequestHeader('Accept', 'application/js');
|
||||
// attach proper File object
|
||||
settings.data = blob;
|
||||
},
|
||||
xhr: function() {
|
||||
var xhr = $.ajaxSettings.xhr();
|
||||
xhr.upload.onloadstart = actualOptions.loadstartEventHandler;
|
||||
xhr.upload.onprogress = actualOptions.progressEventHandler;
|
||||
return xhr;
|
||||
},
|
||||
data: blob,
|
||||
cache: false,
|
||||
processData: false
|
||||
});
|
||||
}
|
||||
|
||||
function dragOverHandler(e) {
|
||||
function dmsfAddInputFiles(inputEl) {
|
||||
var clearedFileInput = $(inputEl).clone().val('');
|
||||
|
||||
if ($.ajaxSettings.xhr().upload && inputEl.files) {
|
||||
// upload files using ajax
|
||||
dmsfUploadAndAttachFiles(inputEl.files, inputEl);
|
||||
$(inputEl).remove();
|
||||
} else {
|
||||
// browser not supporting the file API, upload on form submission
|
||||
var attachmentId;
|
||||
var aFilename = inputEl.value.split(/\/|\\/);
|
||||
attachmentId = dmsfAddFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false);
|
||||
if (attachmentId) {
|
||||
$(inputEl).attr({ name: 'dmsf_attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#dmsf_attachments_' + attachmentId);
|
||||
}
|
||||
}
|
||||
|
||||
clearedFileInput.insertAfter('#dmsf_attachments_fields');
|
||||
}
|
||||
|
||||
function dmsfUploadAndAttachFiles(files, inputEl) {
|
||||
|
||||
var maxFileSize = $(inputEl).data('max-file-size');
|
||||
var maxFileSizeExceeded = $(inputEl).data('max-file-size-message');
|
||||
|
||||
var sizeExceeded = false;
|
||||
$.each(files, function() {
|
||||
if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;}
|
||||
});
|
||||
if (sizeExceeded) {
|
||||
window.alert(maxFileSizeExceeded);
|
||||
} else {
|
||||
$.each(files, function() {dmsfAddFile(inputEl, this, true);});
|
||||
}
|
||||
}
|
||||
|
||||
function dmsfHandleFileDropEvent(e) {
|
||||
|
||||
$(this).removeClass('fileover');
|
||||
blockEventPropagation(e);
|
||||
|
||||
if ($.inArray('Files', e.dataTransfer.types) > -1) {
|
||||
dmsfUploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector'));
|
||||
}
|
||||
}
|
||||
|
||||
function dmsfDragOverHandler(e) {
|
||||
$(this).addClass('fileover');
|
||||
blockEventPropagation(e);
|
||||
}
|
||||
|
||||
function dragOutHandler(e) {
|
||||
$(this).removeClass('fileover');
|
||||
blockEventPropagation(e);
|
||||
function dmsfDragOutHandler(e) {
|
||||
$(this).removeClass('fileover');
|
||||
blockEventPropagation(e);
|
||||
}
|
||||
|
||||
function setupFileDrop() {
|
||||
if (window.File && window.FileList && window.ProgressEvent && window.FormData) {
|
||||
function dmsfSetupFileDrop() {
|
||||
if (window.File && window.FileList && window.ProgressEvent && window.FormData) {
|
||||
|
||||
$.event.fixHooks.drop = { props: [ 'dataTransfer' ] };
|
||||
$.event.fixHooks.drop = { props: [ 'dataTransfer' ] };
|
||||
|
||||
$('form div.box').has('input:file').each(function() {
|
||||
$(this).on({
|
||||
dragover: dragOverHandler,
|
||||
dragleave: dragOutHandler,
|
||||
drop: handleFileDropEvent
|
||||
});
|
||||
});
|
||||
}
|
||||
$('form div.dmsf_uploader').has('input:file').each(function() {
|
||||
$(this).on({
|
||||
dragover: dmsfDragOverHandler,
|
||||
dragleave: dmsfDragOutHandler,
|
||||
drop: dmsfHandleFileDropEvent
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(setupFileDrop);
|
||||
$(document).ready(dmsfSetupFileDrop);
|
||||
|
||||
@ -252,12 +252,28 @@
|
||||
|
||||
.dmsf_parent_container {
|
||||
overflow: hidden;
|
||||
/*padding: 20px 0px 0px 0px;*/
|
||||
}
|
||||
|
||||
.dmsf_child_container {
|
||||
float: left;
|
||||
text-align: left;
|
||||
/*padding: 0px 10px 0px 0px;
|
||||
width: 200px;*/
|
||||
}
|
||||
|
||||
/* DMSF file upload */
|
||||
.dmsf_uploader{
|
||||
padding:6px;
|
||||
margin-bottom: 10px;
|
||||
background-color:#f6f6f6;
|
||||
color:#505050;
|
||||
line-height:1.5em;
|
||||
border: 1px solid #e4e4e4;
|
||||
word-wrap: break-word;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
#dmsf_attachments_fields input.description {margin-left:4px; width:340px;}
|
||||
#dmsf_attachments_fields span {display:block; white-space:nowrap;}
|
||||
#dmsf_attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../../../images/attachment.png) no-repeat 1px 50%; padding-left:18px;}
|
||||
#dmsf_attachments_fields .ajax-waiting input.filename {background:url(../../../images/hourglass.png) no-repeat 0px 50%;}
|
||||
#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; }
|
||||
|
||||
@ -64,6 +64,7 @@ RedmineApp::Application.routes.draw do
|
||||
post '/projects/:id/dmsf/upload', :controller => 'dmsf_upload', :action => 'upload'
|
||||
post '/projects/:id/dmsf/upload/commit', :controller => 'dmsf_upload', :action => 'commit_files'
|
||||
post '/projects/:id/dmsf/commit', :controller => 'dmsf_upload', :action => 'commit'
|
||||
match 'dmsf_uploads', :to => 'dmsf_upload#upload', :via => :post
|
||||
|
||||
#
|
||||
# dmsf_files controller
|
||||
|
||||
36
db/migrate/20170118142001_dmsf_file_container.rb
Normal file
36
db/migrate/20170118142001_dmsf_file_container.rb
Normal file
@ -0,0 +1,36 @@
|
||||
# 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 DmsfFileContainer < ActiveRecord::Migration
|
||||
def up
|
||||
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')
|
||||
add_index :dmsf_files, [:container_id, :container_type]
|
||||
end
|
||||
|
||||
def down
|
||||
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
|
||||
end
|
||||
end
|
||||
@ -4,7 +4,7 @@
|
||||
#
|
||||
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
|
||||
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
|
||||
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
|
||||
# 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
|
||||
@ -31,6 +31,7 @@ require 'redmine_dmsf/patches/project_patch'
|
||||
require 'redmine_dmsf/patches/project_tabs_extended'
|
||||
require 'redmine_dmsf/patches/user_preference_patch'
|
||||
require 'redmine_dmsf/patches/user_patch'
|
||||
require 'redmine_dmsf/patches/issue_patch'
|
||||
|
||||
# Load up classes that make up our WebDAV solution ontop of DAV4Rack
|
||||
require 'redmine_dmsf/webdav/base_resource'
|
||||
@ -51,10 +52,12 @@ require 'redmine_dmsf/errors/dmsf_lock_error.rb'
|
||||
require 'redmine_dmsf/errors/dmsf_zip_max_file_error.rb'
|
||||
|
||||
# Hooks
|
||||
require 'redmine_dmsf/hooks/controllers/search_controller_hooks'
|
||||
require 'redmine_dmsf/hooks/controllers/issues_controller_hooks'
|
||||
require 'redmine_dmsf/hooks/views/view_projects_form_hook'
|
||||
require 'redmine_dmsf/hooks/views/base_view_hooks'
|
||||
require 'redmine_dmsf/hooks/controllers/search_controller_hooks'
|
||||
require 'redmine_dmsf/hooks/views/my_account_view_hooks'
|
||||
require 'redmine_dmsf/hooks/views/issue_view_hooks'
|
||||
|
||||
# Macros
|
||||
require 'redmine_dmsf/macros'
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
# 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.
|
||||
|
||||
module RedmineDmsf
|
||||
module Hooks
|
||||
include Redmine::Hook
|
||||
#include ::DmsfUploadHelper
|
||||
#helper :dmsf_upload
|
||||
|
||||
class ControllerIssuesHook < RedmineDmsf::Hooks::Listener
|
||||
|
||||
def controller_issues_new_after_save(context={})
|
||||
if context.is_a?(Hash)
|
||||
issue = context[:issue]
|
||||
params = context[:params]
|
||||
uploaded_files = params[:dmsf_attachments]
|
||||
uploads = []
|
||||
if uploaded_files && uploaded_files.is_a?(Hash)
|
||||
# standard file input uploads
|
||||
uploaded_files.each_value do |uploaded_file|
|
||||
upload = DmsfUpload.create_from_uploaded_attachment(issue.project, nil, uploaded_file)
|
||||
#uploads.push(upload) if upload
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Redmine plugin for Document Management System "Features"
|
||||
#
|
||||
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
|
||||
# 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
|
||||
@ -28,7 +28,8 @@ module RedmineDmsf
|
||||
"\n".html_safe + stylesheet_link_tag('redmine_dmsf.css', :plugin => :redmine_dmsf) +
|
||||
"\n".html_safe + stylesheet_link_tag('select2.min.css', :plugin => :redmine_dmsf) +
|
||||
"\n".html_safe + javascript_include_tag('select2.min.js', :plugin => :redmine_dmsf) +
|
||||
"\n".html_safe + javascript_include_tag('redmine_dmsf.js', :plugin => :redmine_dmsf)
|
||||
"\n".html_safe + javascript_include_tag('redmine_dmsf.js', :plugin => :redmine_dmsf) +
|
||||
"\n".html_safe + javascript_include_tag('attachments_dmsf.js', :plugin => :redmine_dmsf)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
51
lib/redmine_dmsf/hooks/views/issue_view_hooks.rb
Normal file
51
lib/redmine_dmsf/hooks/views/issue_view_hooks.rb
Normal file
@ -0,0 +1,51 @@
|
||||
# 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.
|
||||
|
||||
module RedmineDmsf
|
||||
module Hooks
|
||||
include Redmine::Hook
|
||||
|
||||
class DmsfViewListener < Redmine::Hook::ViewListener
|
||||
|
||||
def view_issues_form_details_bottom(context={})
|
||||
if context.is_a?(Hash) && context[:issue]
|
||||
issue = context[:issue]
|
||||
# Add Dmsf upload form
|
||||
html = "<div class=\"dmsf_uploader\">"
|
||||
html << '<p>'
|
||||
html << "<label>#{l(:label_document_plural)}</label>"
|
||||
html << context[:controller].send(:render_to_string, {:partial => 'dmsf_upload/form', :locals => context})
|
||||
html << '</p>'
|
||||
html << '</div>'
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def view_issues_show_description_bottom(context={})
|
||||
if context.is_a?(Hash) && context[:issue]
|
||||
issue = context[:issue]
|
||||
context[:controller].send(:render_to_string, {:partial => 'dmsf_files/links',
|
||||
:locals => { :dmsf_files => issue.dmsf_files.to_a }})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
44
lib/redmine_dmsf/patches/issue_patch.rb
Normal file
44
lib/redmine_dmsf/patches/issue_patch.rb
Normal file
@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
require_dependency 'issue'
|
||||
|
||||
module RedmineDmsf
|
||||
module Patches
|
||||
module IssuePatch
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
unloadable
|
||||
has_many :dmsf_files, -> { where(dmsf_folder_id: nil, container_type: 'Issue').order(:name) },
|
||||
:class_name => 'DmsfFile', :foreign_key => 'container_id', :dependent => :destroy
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Apply patch
|
||||
Rails.configuration.to_prepare do
|
||||
unless Issue.included_modules.include?(RedmineDmsf::Patches::IssuePatch)
|
||||
Issue.send(:include, RedmineDmsf::Patches::IssuePatch)
|
||||
end
|
||||
end
|
||||
@ -32,8 +32,8 @@ module RedmineDmsf
|
||||
unloadable
|
||||
alias_method_chain :copy, :dmsf
|
||||
|
||||
has_many :dmsf_files, -> { where(dmsf_folder_id: nil).order(:name) },
|
||||
:class_name => 'DmsfFile', :foreign_key => 'project_id', :dependent => :destroy
|
||||
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
|
||||
|
||||
@ -566,6 +566,7 @@ module RedmineDmsf
|
||||
else
|
||||
raise BadRequest unless (parent.projectless_path == '/' || (parent.exist? && parent.folder))
|
||||
f = DmsfFile.new
|
||||
f.container_type = 'Project'
|
||||
f.project = project
|
||||
f.name = basename
|
||||
f.dmsf_folder = parent.folder
|
||||
|
||||
@ -111,6 +111,7 @@ class DmsfConvertDocuments
|
||||
document.attachments.each do |attachment|
|
||||
begin
|
||||
file = DmsfFile.new
|
||||
file.container_type = 'Project'
|
||||
file.project = project
|
||||
file.dmsf_folder = folder
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user