#9 Active Storage - Duplicated columns removed
This commit is contained in:
parent
54ead3ded4
commit
3a50485653
@ -67,7 +67,7 @@ class DmsfFilesController < ApplicationController
|
|||||||
Rails.logger.error "Could not send email notifications: #{e.message}"
|
Rails.logger.error "Could not send email notifications: #{e.message}"
|
||||||
end
|
end
|
||||||
# Allow a preview of the file by an external plugin
|
# Allow a preview of the file by an external plugin
|
||||||
results = call_hook(:dmsf_files_controller_before_view, { file: @revision.disk_file })
|
results = call_hook(:dmsf_files_controller_before_view, { file: @revision.file.download })
|
||||||
return if results.first == true
|
return if results.first == true
|
||||||
|
|
||||||
member = Member.find_by(user_id: User.current.id, project_id: @file.project.id)
|
member = Member.find_by(user_id: User.current.id, project_id: @file.project.id)
|
||||||
@ -89,7 +89,7 @@ class DmsfFilesController < ApplicationController
|
|||||||
params[:disposition] = 'attachment' if params[:filename].present?
|
params[:disposition] = 'attachment' if params[:filename].present?
|
||||||
send_data @revision.file.download,
|
send_data @revision.file.download,
|
||||||
filename: filename,
|
filename: filename,
|
||||||
type: @revision.detect_content_type,
|
type: @revision.content_type,
|
||||||
disposition: params[:disposition].presence || @revision.dmsf_file.disposition
|
disposition: params[:disposition].presence || @revision.dmsf_file.disposition
|
||||||
end
|
end
|
||||||
rescue DmsfAccessError => e
|
rescue DmsfAccessError => e
|
||||||
@ -139,21 +139,18 @@ class DmsfFilesController < ApplicationController
|
|||||||
upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, file_upload)
|
upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, file_upload)
|
||||||
if upload
|
if upload
|
||||||
revision.size = upload.size
|
revision.size = upload.size
|
||||||
revision.disk_filename = revision.new_storage_filename
|
|
||||||
revision.file.attach(
|
revision.file.attach(
|
||||||
io: File.open(upload.tempfile_path),
|
io: File.open(upload.tempfile_path),
|
||||||
filename: revision.disk_filename,
|
filename: file_upload.filename,
|
||||||
content_type: revision.mime_type,
|
content_type: Redmine::MimeType.of(file_upload.filename),
|
||||||
identify: false
|
identify: false
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
revision.size = last_revision.size
|
revision.size = last_revision.size
|
||||||
revision.disk_filename = last_revision.disk_filename
|
|
||||||
end
|
end
|
||||||
# Custom fields
|
# Custom fields
|
||||||
revision.copy_custom_field_values(params[:dmsf_file_revision][:custom_field_values], last_revision)
|
revision.copy_custom_field_values(params[:dmsf_file_revision][:custom_field_values], last_revision)
|
||||||
@file.name = revision.name
|
|
||||||
ok = true
|
ok = true
|
||||||
if revision.save
|
if revision.save
|
||||||
revision.assign_workflow params[:dmsf_workflow_id]
|
revision.assign_workflow params[:dmsf_workflow_id]
|
||||||
@ -330,8 +327,8 @@ class DmsfFilesController < ApplicationController
|
|||||||
if tbnail
|
if tbnail
|
||||||
if stale?(etag: tbnail)
|
if stale?(etag: tbnail)
|
||||||
send_file tbnail,
|
send_file tbnail,
|
||||||
filename: filename_for_content_disposition(@file.last_revision.disk_file),
|
filename: filename_for_content_disposition(@file.name),
|
||||||
type: @file.last_revision.detect_content_type,
|
type: @file.last_revision.content_type,
|
||||||
disposition: 'inline'
|
disposition: 'inline'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class DmsfPublicUrlsController < ApplicationController
|
|||||||
expires_in 0.years, 'must-revalidate' => true
|
expires_in 0.years, 'must-revalidate' => true
|
||||||
send_data(revision.file.download,
|
send_data(revision.file.download,
|
||||||
filename: filename_for_content_disposition(revision.name),
|
filename: filename_for_content_disposition(revision.name),
|
||||||
type: revision.detect_content_type,
|
type: revision.content_type,
|
||||||
disposition: dmsf_public_url.dmsf_file.disposition)
|
disposition: dmsf_public_url.dmsf_file.disposition)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
Rails.logger.error e.message
|
Rails.logger.error e.message
|
||||||
|
|||||||
@ -42,7 +42,6 @@ module DmsfUploadHelper
|
|||||||
else
|
else
|
||||||
file = DmsfFile.new
|
file = DmsfFile.new
|
||||||
file.project_id = project.id
|
file.project_id = project.id
|
||||||
file.name = name
|
|
||||||
file.dmsf_folder = folder
|
file.dmsf_folder = folder
|
||||||
file.notification = RedmineDmsf.dmsf_default_notifications?
|
file.notification = RedmineDmsf.dmsf_default_notifications?
|
||||||
end
|
end
|
||||||
@ -84,8 +83,6 @@ module DmsfUploadHelper
|
|||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
new_revision.disk_filename = new_revision.new_storage_filename
|
|
||||||
|
|
||||||
if new_revision.save
|
if new_revision.save
|
||||||
new_revision.assign_workflow committed_file[:dmsf_workflow_id]
|
new_revision.assign_workflow committed_file[:dmsf_workflow_id]
|
||||||
begin
|
begin
|
||||||
@ -97,7 +94,7 @@ module DmsfUploadHelper
|
|||||||
new_revision.file.attach(
|
new_revision.file.attach(
|
||||||
io: File.open(committed_file[:tempfile_path]),
|
io: File.open(committed_file[:tempfile_path]),
|
||||||
filename: new_revision.name,
|
filename: new_revision.name,
|
||||||
content_type: new_revision.mime_type,
|
content_type: new_revision.content_type,
|
||||||
identify: false
|
identify: false
|
||||||
)
|
)
|
||||||
file.last_revision = new_revision
|
file.last_revision = new_revision
|
||||||
|
|||||||
@ -42,15 +42,6 @@ class DmsfFile < ApplicationRecord
|
|||||||
scope :visible, -> { where(deleted: STATUS_ACTIVE) }
|
scope :visible, -> { where(deleted: STATUS_ACTIVE) }
|
||||||
scope :deleted, -> { where(deleted: STATUS_DELETED) }
|
scope :deleted, -> { where(deleted: STATUS_DELETED) }
|
||||||
|
|
||||||
validates :name, dmsf_file_name: true
|
|
||||||
validates :name, length: { maximum: 255 }
|
|
||||||
validates :name,
|
|
||||||
uniqueness: {
|
|
||||||
scope: %i[dmsf_folder_id project_id deleted],
|
|
||||||
conditions: -> { where(deleted: STATUS_ACTIVE) },
|
|
||||||
case_sensitive: true
|
|
||||||
}
|
|
||||||
|
|
||||||
acts_as_event(
|
acts_as_event(
|
||||||
title: proc { |o|
|
title: proc { |o|
|
||||||
@searched_revision = nil
|
@searched_revision = nil
|
||||||
@ -81,7 +72,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
url: proc { |o|
|
url: proc { |o|
|
||||||
if @searched_revision
|
if @searched_revision
|
||||||
{ controller: 'dmsf_files', action: 'view', id: o.id, download: @searched_revision.id,
|
{ controller: 'dmsf_files', action: 'view', id: o.id, download: @searched_revision.id,
|
||||||
filename: o.name }
|
filename: @searched_revision.name }
|
||||||
else
|
else
|
||||||
{ controller: 'dmsf_files', action: 'view', id: o.id, filename: o.name }
|
{ controller: 'dmsf_files', action: 'view', id: o.id, filename: o.name }
|
||||||
end
|
end
|
||||||
@ -104,7 +95,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
acts_as_watchable
|
acts_as_watchable
|
||||||
acts_as_searchable(
|
acts_as_searchable(
|
||||||
columns: [
|
columns: [
|
||||||
"#{table_name}.name",
|
"#{DmsfFileRevision.table_name}.name",
|
||||||
"#{DmsfFileRevision.table_name}.title",
|
"#{DmsfFileRevision.table_name}.title",
|
||||||
"#{DmsfFileRevision.table_name}.description",
|
"#{DmsfFileRevision.table_name}.description",
|
||||||
"#{DmsfFileRevision.table_name}.comment"
|
"#{DmsfFileRevision.table_name}.comment"
|
||||||
@ -143,11 +134,19 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.find_file_by_name(project, folder, name)
|
def self.find_file_by_name(project, folder, name)
|
||||||
findn_file_by_name project&.id, folder, name
|
dmsf_files = visible.where(dmsf_files: { project_id: project&.id, dmsf_folder_id: folder&.id })
|
||||||
|
dmsf_files.each do |file|
|
||||||
|
return file if file.name == name
|
||||||
|
end
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.findn_file_by_name(project_id, folder, name)
|
def self.find_file_by_title(project, folder, name)
|
||||||
visible.find_by project_id: project_id, dmsf_folder_id: folder&.id, name: name
|
dmsf_files = visible.where(dmsf_files: { project_id: project&.id, dmsf_folder_id: folder&.id })
|
||||||
|
dmsf_files.each do |file|
|
||||||
|
return file if file.title == name
|
||||||
|
end
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def approval_allowed_zero_minor
|
def approval_allowed_zero_minor
|
||||||
@ -155,10 +154,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def last_revision
|
def last_revision
|
||||||
unless defined?(@last_revision)
|
@last_revision ||= deleted? ? dmsf_file_revisions.first : dmsf_file_revisions.visible.first
|
||||||
@last_revision = deleted? ? dmsf_file_revisions.first : dmsf_file_revisions.visible.first
|
|
||||||
end
|
|
||||||
@last_revision
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def deleted?
|
def deleted?
|
||||||
@ -211,16 +207,20 @@ class DmsfFile < ApplicationRecord
|
|||||||
save
|
save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
last_revision&.name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
def title
|
def title
|
||||||
last_revision ? last_revision.title : name
|
last_revision&.title.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def description
|
def description
|
||||||
last_revision ? last_revision.description : ''
|
last_revision&.description.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def version
|
def version
|
||||||
last_revision ? last_revision.version : '0'
|
last_revision&.version.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def workflow
|
def workflow
|
||||||
@ -228,7 +228,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def size
|
def size
|
||||||
last_revision ? last_revision.size : 0
|
last_revision&.size.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def dmsf_path
|
def dmsf_path
|
||||||
@ -313,28 +313,12 @@ class DmsfFile < ApplicationRecord
|
|||||||
file = DmsfFile.new
|
file = DmsfFile.new
|
||||||
file.dmsf_folder_id = folder.id if folder
|
file.dmsf_folder_id = folder.id if folder
|
||||||
file.project_id = project.id
|
file.project_id = project.id
|
||||||
title = last_revision&.title
|
|
||||||
if DmsfFile.visible.exists?(project_id: file.project_id, dmsf_folder_id: file.dmsf_folder_id, name: filename)
|
|
||||||
basename = File.basename(filename, '.*')
|
|
||||||
extname = File.extname(filename)
|
|
||||||
1.step do |i|
|
|
||||||
title = "#{basename} (#{i})"
|
|
||||||
gen_filename = "#{title}#{extname}"
|
|
||||||
unless DmsfFile.visible.exists?(project_id: file.project_id, dmsf_folder_id: file.dmsf_folder_id,
|
|
||||||
name: gen_filename)
|
|
||||||
filename = gen_filename
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
file.name = filename
|
|
||||||
file.notification = RedmineDmsf.dmsf_default_notifications?
|
file.notification = RedmineDmsf.dmsf_default_notifications?
|
||||||
if file.save && last_revision
|
if file.save && last_revision
|
||||||
new_revision = last_revision.clone
|
new_revision = last_revision.clone
|
||||||
new_revision.name = filename
|
new_revision.name = filename
|
||||||
new_revision.title = title
|
new_revision.title = File.basename(filename, '.*')
|
||||||
new_revision.dmsf_file = file
|
new_revision.dmsf_file = file
|
||||||
new_revision.disk_filename = new_revision.new_storage_filename
|
|
||||||
# Assign the same workflow if it's a global one, or we are in the same project
|
# Assign the same workflow if it's a global one, or we are in the same project
|
||||||
new_revision.workflow = nil
|
new_revision.workflow = nil
|
||||||
new_revision.dmsf_workflow_id = nil
|
new_revision.dmsf_workflow_id = nil
|
||||||
@ -350,7 +334,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
if last_revision.file.attached?
|
if last_revision.file.attached?
|
||||||
begin
|
begin
|
||||||
new_revision.file.attach(
|
new_revision.file.attach(
|
||||||
io: StringIO.new(last_revision.file.blob.download),
|
io: StringIO.new(last_revision.file.download),
|
||||||
filename: filename,
|
filename: filename,
|
||||||
content_type: new_revision.file.content_type,
|
content_type: new_revision.file.content_type,
|
||||||
identify: false
|
identify: false
|
||||||
@ -367,10 +351,18 @@ class DmsfFile < ApplicationRecord
|
|||||||
v.value = cv.value
|
v.value = cv.value
|
||||||
new_revision.custom_values << v
|
new_revision.custom_values << v
|
||||||
end
|
end
|
||||||
|
# Check the name and title
|
||||||
|
basename = File.basename(filename, '.*')
|
||||||
|
extname = File.extname(filename)
|
||||||
|
i = 1
|
||||||
|
while new_revision.invalid? && i < 1_000
|
||||||
|
new_revision.title = "#{basename} (#{i})"
|
||||||
|
new_revision.name = "#{new_revision.title}#{extname}"
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
if new_revision.save
|
if new_revision.save
|
||||||
file.last_revision = new_revision
|
file.last_revision = new_revision
|
||||||
else
|
else
|
||||||
errors.add :base, new_revision.errors.full_messages.to_sentence
|
|
||||||
Rails.logger.error new_revision.errors.full_messages.to_sentence
|
Rails.logger.error new_revision.errors.full_messages.to_sentence
|
||||||
file.delete commit: true
|
file.delete commit: true
|
||||||
file = nil
|
file = nil
|
||||||
@ -504,29 +496,34 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def text?
|
def text?
|
||||||
filename = last_revision&.disk_filename
|
return false unless last_revision
|
||||||
Redmine::MimeType.is_type?('text', filename) ||
|
|
||||||
Redmine::SyntaxHighlighting.filename_supported?(filename)
|
filename = last_revision.file&.blob&.filename.to_s
|
||||||
|
last_revision.file&.blob&.text? || Redmine::SyntaxHighlighting.filename_supported?(filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
def image?
|
def image?
|
||||||
Redmine::MimeType.is_type?('image', last_revision&.disk_filename)
|
last_revision && last_revision.file&.blob&.image?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pdf?
|
def pdf?
|
||||||
Redmine::MimeType.of(last_revision&.disk_filename) == 'application/pdf'
|
last_revision&.content_type == 'application/pdf'
|
||||||
end
|
end
|
||||||
|
|
||||||
def video?
|
def video?
|
||||||
Redmine::MimeType.is_type?('video', last_revision&.disk_filename)
|
return false unless last_revision
|
||||||
|
|
||||||
|
Redmine::MimeType.is_type?('video', last_revision.file.blob&.filename&.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
def html?
|
def html?
|
||||||
Redmine::MimeType.of(last_revision&.disk_filename) == 'text/html'
|
last_revision&.content_type == 'text/html'
|
||||||
end
|
end
|
||||||
|
|
||||||
def office_doc?
|
def office_doc?
|
||||||
case File.extname(last_revision&.disk_filename)
|
return false unless last_revision
|
||||||
|
|
||||||
|
case File.extname(last_revision.file.blob&.filename&.to_s)
|
||||||
when '.odt', '.ods', '.odp', '.odg', # LibreOffice
|
when '.odt', '.ods', '.odp', '.odg', # LibreOffice
|
||||||
'.doc', '.docx', '.docm', '.xls', '.xlsx', '.xlsm', '.ppt', '.pptx', '.pptm', # MS Office
|
'.doc', '.docx', '.docm', '.xls', '.xlsx', '.xlsm', '.ppt', '.pptx', '.pptm', # MS Office
|
||||||
'.rtf' # Universal
|
'.rtf' # Universal
|
||||||
@ -537,11 +534,11 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def markdown?
|
def markdown?
|
||||||
Redmine::MimeType.of(last_revision&.disk_filename) == 'text/markdown'
|
last_revision&.content_type == 'text/markdown'
|
||||||
end
|
end
|
||||||
|
|
||||||
def textile?
|
def textile?
|
||||||
Redmine::MimeType.of(last_revision&.disk_filename) == 'text/x-textile'
|
last_revision&.content_type == 'text/textile'
|
||||||
end
|
end
|
||||||
|
|
||||||
def disposition
|
def disposition
|
||||||
@ -573,8 +570,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
Rails.logger.error do
|
Rails.logger.error do
|
||||||
%(An error occurred while generating preview for #{last_revision.file.name} to #{target}\n
|
%(An error occurred while generating preview for #{name} to #{target}\nException was: #{e.message})
|
||||||
Exception was: #{e.message})
|
|
||||||
end
|
end
|
||||||
''
|
''
|
||||||
end
|
end
|
||||||
@ -604,11 +600,7 @@ class DmsfFile < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def formatted_name(member)
|
def formatted_name(member)
|
||||||
if last_revision
|
last_revision&.formatted_name(member)
|
||||||
last_revision.formatted_name(member)
|
|
||||||
else
|
|
||||||
name
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def owner?(user)
|
def owner?(user)
|
||||||
@ -640,10 +632,6 @@ class DmsfFile < ApplicationRecord
|
|||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def extension
|
|
||||||
File.extname(last_revision.disk_filename).strip.downcase[1..] if last_revision
|
|
||||||
end
|
|
||||||
|
|
||||||
def thumbnail(options = {})
|
def thumbnail(options = {})
|
||||||
size = options[:size].to_i
|
size = options[:size].to_i
|
||||||
if size.positive?
|
if size.positive?
|
||||||
@ -657,10 +645,10 @@ class DmsfFile < ApplicationRecord
|
|||||||
size = 100 unless size.positive?
|
size = 100 unless size.positive?
|
||||||
target = File.join(Attachment.thumbnails_storage_path, "#{id}_#{last_revision.digest}_#{size}.thumb")
|
target = File.join(Attachment.thumbnails_storage_path, "#{id}_#{last_revision.digest}_#{size}.thumb")
|
||||||
begin
|
begin
|
||||||
Redmine::Thumbnail.generate last_revision.disk_file.to_s, target, size, pdf?
|
Redmine::Thumbnail.generate last_revision.file.download, target, size, pdf?
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
Rails.logger.error do
|
Rails.logger.error do
|
||||||
%(An error occured while generating thumbnail for #{last_revision.disk_file} to #{target}\n
|
%(An error occured while generating thumbnail for #{last_revision.file&.blob&.filename} to #{target}\n
|
||||||
Exception was: #{e.message})
|
Exception was: #{e.message})
|
||||||
end
|
end
|
||||||
nil
|
nil
|
||||||
|
|||||||
@ -90,13 +90,9 @@ class DmsfFileRevision < ApplicationRecord
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
validates :title, presence: true
|
validates :title, presence: true, dmsf_file_name: true, length: { maximum: 255 }
|
||||||
validates :title, length: { maximum: 255 }
|
|
||||||
validates :major_version, presence: true
|
validates :major_version, presence: true
|
||||||
validates :name, dmsf_file_name: true
|
validates :name, presence: true, dmsf_file_name: true, length: { maximum: 255 }, dmsf_file_extension: true
|
||||||
validates :name, length: { maximum: 255 }
|
|
||||||
validates :disk_filename, length: { maximum: 255 }
|
|
||||||
validates :name, dmsf_file_extension: true
|
|
||||||
validates :description, length: { maximum: 1.kilobyte }
|
validates :description, length: { maximum: 1.kilobyte }
|
||||||
validates :size, dmsf_max_file_size: true
|
validates :size, dmsf_max_file_size: true
|
||||||
|
|
||||||
@ -118,8 +114,11 @@ class DmsfFileRevision < ApplicationRecord
|
|||||||
file.blob&.checksum
|
file.blob&.checksum
|
||||||
end
|
end
|
||||||
|
|
||||||
def mime_type
|
def content_type
|
||||||
file.blob&.content_type
|
res = file.blob&.content_type
|
||||||
|
res = Redmine::MimeType.of(file.blob&.filename) if res.blank?
|
||||||
|
res = 'application/octet-stream' if res.blank?
|
||||||
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
def visible?(_user = nil)
|
def visible?(_user = nil)
|
||||||
@ -191,49 +190,9 @@ class DmsfFileRevision < ApplicationRecord
|
|||||||
ver
|
ver
|
||||||
end
|
end
|
||||||
|
|
||||||
def storage_base_path
|
|
||||||
time = created_at || DateTime.current
|
|
||||||
DmsfFile.storage_path.join(time.strftime('%Y')).join time.strftime('%m')
|
|
||||||
end
|
|
||||||
|
|
||||||
def disk_file(search_if_not_exists: true)
|
|
||||||
path = storage_base_path
|
|
||||||
begin
|
|
||||||
FileUtils.mkdir_p(path)
|
|
||||||
rescue StandardError => e
|
|
||||||
Rails.logger.error e.message
|
|
||||||
end
|
|
||||||
filename = path.join(disk_filename)
|
|
||||||
if search_if_not_exists && !File.exist?(filename)
|
|
||||||
# Let's search for the physical file in source revisions
|
|
||||||
dmsf_file.dmsf_file_revisions.where(created_at: ...created_at).order(created_at: :desc).each do |rev|
|
|
||||||
filename = rev.disk_file
|
|
||||||
break if File.exist?(filename)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
filename.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def new_storage_filename
|
|
||||||
raise DmsfAccessError, 'File id is not set' unless dmsf_file&.id
|
|
||||||
|
|
||||||
filename = DmsfHelper.sanitize_filename(name)
|
|
||||||
timestamp = DateTime.current.strftime('%y%m%d%H%M%S')
|
|
||||||
timestamp.succ! while File.exist? storage_base_path.join("#{timestamp}_#{dmsf_file.id}_#{filename}")
|
|
||||||
"#{timestamp}_#{dmsf_file.id}_#{filename}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def detect_content_type
|
|
||||||
content_type = mime_type
|
|
||||||
content_type = Redmine::MimeType.of(disk_filename) if content_type.blank?
|
|
||||||
content_type = 'application/octet-stream' if content_type.blank?
|
|
||||||
content_type
|
|
||||||
end
|
|
||||||
|
|
||||||
def clone
|
def clone
|
||||||
new_revision = DmsfFileRevision.new
|
new_revision = DmsfFileRevision.new
|
||||||
new_revision.dmsf_file = dmsf_file
|
new_revision.dmsf_file = dmsf_file
|
||||||
new_revision.disk_filename = disk_filename
|
|
||||||
new_revision.size = size
|
new_revision.size = size
|
||||||
new_revision.title = title
|
new_revision.title = title
|
||||||
new_revision.description = description
|
new_revision.description = description
|
||||||
@ -325,7 +284,7 @@ class DmsfFileRevision < ApplicationRecord
|
|||||||
file.attach(
|
file.attach(
|
||||||
io: open_file,
|
io: open_file,
|
||||||
filename: dmsf_file.name,
|
filename: dmsf_file.name,
|
||||||
content_type: mime_type.presence || Redmine::MimeType.of(disk_filename),
|
content_type: content_type,
|
||||||
identify: false
|
identify: false
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@ -396,7 +355,7 @@ class DmsfFileRevision < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def protocol
|
def protocol
|
||||||
@protocol ||= PROTOCOLS[mime_type.downcase] if mime_type
|
@protocol ||= PROTOCOLS[content_type.downcase] if content_type.present?
|
||||||
@protocol
|
@protocol
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -28,9 +28,9 @@ class DmsfFolder < ApplicationRecord
|
|||||||
belongs_to :deleted_by_user, class_name: 'User'
|
belongs_to :deleted_by_user, class_name: 'User'
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
has_many :dmsf_folders, -> { order :title }, dependent: :destroy, inverse_of: :dmsf_folder
|
has_many :dmsf_folders, dependent: :destroy, inverse_of: :dmsf_folder
|
||||||
has_many :dmsf_files, dependent: :destroy
|
has_many :dmsf_files, dependent: :destroy
|
||||||
has_many :folder_links, -> { where(target_type: 'DmsfFolder').order(:name) },
|
has_many :folder_links, -> { where(target_type: 'DmsfFolder') },
|
||||||
class_name: 'DmsfLink', foreign_key: 'dmsf_folder_id', dependent: :destroy, inverse_of: :dmsf_folder
|
class_name: 'DmsfLink', foreign_key: 'dmsf_folder_id', dependent: :destroy, inverse_of: :dmsf_folder
|
||||||
has_many :file_links, -> { where(target_type: 'DmsfFile') },
|
has_many :file_links, -> { where(target_type: 'DmsfFile') },
|
||||||
class_name: 'DmsfLink', foreign_key: 'dmsf_folder_id', dependent: :destroy, inverse_of: :dmsf_folder
|
class_name: 'DmsfLink', foreign_key: 'dmsf_folder_id', dependent: :destroy, inverse_of: :dmsf_folder
|
||||||
@ -91,7 +91,7 @@ class DmsfFolder < ApplicationRecord
|
|||||||
datetime: proc { |o| o.updated_at },
|
datetime: proc { |o| o.updated_at },
|
||||||
author: proc { |o| o.user }
|
author: proc { |o| o.user }
|
||||||
|
|
||||||
validates :title, presence: true, dmsf_file_name: true
|
validates :title, presence: true, length: { maximum: 255 }, dmsf_folder_name: true
|
||||||
validates :title, uniqueness: { scope: %i[dmsf_folder_id project_id deleted],
|
validates :title, uniqueness: { scope: %i[dmsf_folder_id project_id deleted],
|
||||||
conditions: -> { where(deleted: STATUS_ACTIVE) }, case_sensitive: true }
|
conditions: -> { where(deleted: STATUS_ACTIVE) }, case_sensitive: true }
|
||||||
validates :description, length: { maximum: 65_535 }
|
validates :description, length: { maximum: 65_535 }
|
||||||
|
|||||||
@ -26,7 +26,9 @@ class DmsfLink < ApplicationRecord
|
|||||||
belongs_to :deleted_by_user, class_name: 'User'
|
belongs_to :deleted_by_user, class_name: 'User'
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
validates :name, presence: true, length: { maximum: 255 }
|
validates :name, presence: true, length: { maximum: 255 }, dmsf_link_name: true
|
||||||
|
validates :name, uniqueness: { scope: %i[dmsf_folder_id project_id deleted],
|
||||||
|
conditions: -> { where(deleted: STATUS_ACTIVE) }, case_sensitive: true }
|
||||||
# There can be project_id = -1 when attaching links to an issue. The project_id is assigned later when saving the
|
# There can be project_id = -1 when attaching links to an issue. The project_id is assigned later when saving the
|
||||||
# issue.
|
# issue.
|
||||||
validates :external_url, length: { maximum: 255 }
|
validates :external_url, length: { maximum: 255 }
|
||||||
|
|||||||
@ -22,6 +22,38 @@ class DmsfFileNameValidator < ActiveModel::EachValidator
|
|||||||
ALL_INVALID_CHARACTERS = /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/
|
ALL_INVALID_CHARACTERS = /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/
|
||||||
|
|
||||||
def validate_each(record, attribute, value)
|
def validate_each(record, attribute, value)
|
||||||
|
# Check invalid characters
|
||||||
record.errors.add attribute, :error_contains_invalid_character unless ALL_INVALID_CHARACTERS.match?(value)
|
record.errors.add attribute, :error_contains_invalid_character unless ALL_INVALID_CHARACTERS.match?(value)
|
||||||
|
|
||||||
|
# Check name uniqueness among files
|
||||||
|
project_id = record.dmsf_file.project_id
|
||||||
|
dmsf_folder_id = record.dmsf_file.dmsf_folder_id
|
||||||
|
id = record.dmsf_file_id
|
||||||
|
DmsfFile
|
||||||
|
.visible
|
||||||
|
.where(project_id: project_id, dmsf_folder_id: dmsf_folder_id)
|
||||||
|
.where.not(id: id)
|
||||||
|
.find_each do |file|
|
||||||
|
if file.name == value || file.title == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check name uniqueness among folders
|
||||||
|
DmsfFolder.visible.where(project_id: project_id, dmsf_folder_id: dmsf_folder_id).find_each do |folder|
|
||||||
|
if folder.title == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check name uniqueness among links
|
||||||
|
DmsfLink.visible.where(project_id: project_id, dmsf_folder_id: dmsf_folder_id).find_each do |link|
|
||||||
|
if link.name == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
44
app/validators/dmsf_folder_name_validator.rb
Normal file
44
app/validators/dmsf_folder_name_validator.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Redmine plugin for Document Management System "Features"
|
||||||
|
#
|
||||||
|
# Vít Jonáš <vit.jonas@gmail.com>, Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This file is part of Redmine DMSF plugin.
|
||||||
|
#
|
||||||
|
# Redmine DMSF plugin 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 3 of the License, or (at your option) any
|
||||||
|
# later version.
|
||||||
|
#
|
||||||
|
# Redmine DMSF plugin 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 Redmine DMSF plugin. If not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# File name validator
|
||||||
|
class DmsfFolderNameValidator < ActiveModel::EachValidator
|
||||||
|
ALL_INVALID_CHARACTERS = /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/
|
||||||
|
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
# Check invalid characters
|
||||||
|
record.errors.add attribute, :error_contains_invalid_character unless ALL_INVALID_CHARACTERS.match?(value)
|
||||||
|
|
||||||
|
# Check name uniqueness among files
|
||||||
|
DmsfFile.visible.where(project_id: record.project_id, dmsf_folder_id: record.dmsf_folder_id).find_each do |file|
|
||||||
|
if file.name == value || file.title == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check name uniqueness among links
|
||||||
|
DmsfLink.visible.where(project_id: record.project_id, dmsf_folder_id: record.dmsf_folder_id).find_each do |link|
|
||||||
|
if link.name == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
44
app/validators/dmsf_link_name_validator.rb
Normal file
44
app/validators/dmsf_link_name_validator.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Redmine plugin for Document Management System "Features"
|
||||||
|
#
|
||||||
|
# Vít Jonáš <vit.jonas@gmail.com>, Karel Pičman <karel.picman@kontron.com>
|
||||||
|
#
|
||||||
|
# This file is part of Redmine DMSF plugin.
|
||||||
|
#
|
||||||
|
# Redmine DMSF plugin 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 3 of the License, or (at your option) any
|
||||||
|
# later version.
|
||||||
|
#
|
||||||
|
# Redmine DMSF plugin 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 Redmine DMSF plugin. If not, see
|
||||||
|
# <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# File name validator
|
||||||
|
class DmsfLinkNameValidator < ActiveModel::EachValidator
|
||||||
|
ALL_INVALID_CHARACTERS = /\A[^#{DmsfFolder::INVALID_CHARACTERS}]*\z/
|
||||||
|
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
# Check invalid characters
|
||||||
|
record.errors.add attribute, :error_contains_invalid_character unless ALL_INVALID_CHARACTERS.match?(value)
|
||||||
|
|
||||||
|
# Check name uniqueness among files
|
||||||
|
DmsfFile.visible.where(project_id: record.project_id, dmsf_folder_id: record.dmsf_folder_id).find_each do |file|
|
||||||
|
if file.name == value || file.title == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check name uniqueness among folders
|
||||||
|
DmsfFolder.visible.where(project_id: record.project_id, dmsf_folder_id: record.dmsf_folder_id).find_each do |folder|
|
||||||
|
if folder.title == value
|
||||||
|
record.errors.add attribute, :taken
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -71,7 +71,7 @@
|
|||||||
<% member = Member.find_by(user_id: User.current.id, project_id: dmsf_file.project.id) %>
|
<% member = Member.find_by(user_id: User.current.id, project_id: dmsf_file.project.id) %>
|
||||||
<% filename = dmsf_file.last_revision&.formatted_name(member) %>
|
<% filename = dmsf_file.last_revision&.formatted_name(member) %>
|
||||||
<%= context_menu_link sprite_icon('download', l(:button_download)),
|
<%= context_menu_link sprite_icon('download', l(:button_download)),
|
||||||
static_dmsf_file_path(dmsf_file, filename: filename),
|
static_dmsf_file_path(dmsf_file, filename: filename, download: dmsf_file.last_revision&.id),
|
||||||
class: 'icon icon-download', data: { cy: "icon__download--dmsf_file_#{dmsf_file.id}" },
|
class: 'icon icon-download', data: { cy: "icon__download--dmsf_file_#{dmsf_file.id}" },
|
||||||
disabled: false %>
|
disabled: false %>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -40,7 +40,8 @@
|
|||||||
<% member = Member.find_by(user_id: User.current.id, project_id: file.project.id) %>
|
<% member = Member.find_by(user_id: User.current.id, project_id: file.project.id) %>
|
||||||
<% filename = file.last_revision&.formatted_name(member) %>
|
<% filename = file.last_revision&.formatted_name(member) %>
|
||||||
<%= link_to sprite_icon('download', l(:button_download)),
|
<%= link_to sprite_icon('download', l(:button_download)),
|
||||||
static_dmsf_file_path(file, filename: filename), class: 'icon icon-download', disabled: false %>
|
static_dmsf_file_path(file, filename: filename, download: file.last_revision&.id),
|
||||||
|
class: 'icon icon-download', disabled: false %>
|
||||||
<%= render partial: 'dmsf_context_menus/watch', locals: { object: file } %>
|
<%= render partial: 'dmsf_context_menus/watch', locals: { object: file } %>
|
||||||
<%= delete_link(dmsf_file_path(id: file, details: true),
|
<%= delete_link(dmsf_file_path(id: file, details: true),
|
||||||
back_url: dmsf_folder_path(id: file.project, folder_id: file.dmsf_folder)) if file_delete_allowed %>
|
back_url: dmsf_folder_path(id: file.project, folder_id: file.dmsf_folder)) if file_delete_allowed %>
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(dmsf_file.last_revision.try(:tooltip)),
|
title: h(dmsf_file.last_revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{dmsf_file.last_revision.detect_content_type}:#{h(dmsf_file.name)}:#{file_view_url}" %>
|
'data-downloadurl' => "#{dmsf_file.last_revision.content_type}:#{h(dmsf_file.name)}:#{file_view_url}" %>
|
||||||
</td>
|
</td>
|
||||||
<td class="<%= cls %>">
|
<td class="<%= cls %>">
|
||||||
<span class="size">(<%= number_to_human_size dmsf_file.last_revision.size %>)</span>
|
<span class="size">(<%= number_to_human_size dmsf_file.last_revision.size %>)</span>
|
||||||
|
|||||||
@ -14,7 +14,7 @@ api.dmsf_file do
|
|||||||
api.dmsf_string "{{dmsf(#{@file.id},#{@file.name},#{r.id})}}"
|
api.dmsf_string "{{dmsf(#{@file.id},#{@file.name},#{r.id})}}"
|
||||||
api.content_url view_dmsf_file_url(@file, download: r)
|
api.content_url view_dmsf_file_url(@file, download: r)
|
||||||
api.size r.size
|
api.size r.size
|
||||||
api.mime_type r.mime_type
|
api.mime_type r.content_type
|
||||||
api.title r.title
|
api.title r.title
|
||||||
api.description r.description
|
api.description r.description
|
||||||
api.workflow r.workflow
|
api.workflow r.workflow
|
||||||
|
|||||||
@ -133,7 +133,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="status attribute">
|
<div class="status attribute">
|
||||||
<%= content_tag :div, l(:label_mime), class: 'label' %>
|
<%= content_tag :div, l(:label_mime), class: 'label' %>
|
||||||
<%= content_tag :div, revision.mime_type, class: 'value' %>
|
<%= content_tag :div, revision.content_type, class: 'value' %>
|
||||||
</div>
|
</div>
|
||||||
<% if revision.checksum.present? %>
|
<% if revision.checksum.present? %>
|
||||||
<div class="status attribute">
|
<div class="status attribute">
|
||||||
|
|||||||
@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to "#{l(:button_download)} (#{number_to_human_size(@file.size)})",
|
<%= link_to "#{l(:button_download)} (#{number_to_human_size(@file.size)})",
|
||||||
static_dmsf_file_path(@file, download: @file.last_revision, filename: @file.last_revision.disk_filename),
|
static_dmsf_file_path(@file, download: @file.last_revision,
|
||||||
|
filename: @file.last_revision.file&.blob&.filename),
|
||||||
class: 'icon icon-download', disabled: false %>
|
class: 'icon icon-download', disabled: false %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class ActiveStorageMigration < ActiveRecord::Migration[7.0]
|
|||||||
r.file.attach(
|
r.file.attach(
|
||||||
io: File.open(path),
|
io: File.open(path),
|
||||||
filename: r.name,
|
filename: r.name,
|
||||||
content_type: r.mime_type,
|
content_type: r.content_type,
|
||||||
identify: false
|
identify: false
|
||||||
)
|
)
|
||||||
# Remove the original file
|
# Remove the original file
|
||||||
@ -60,18 +60,51 @@ class ActiveStorageMigration < ActiveRecord::Migration[7.0]
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# Remove columns duplicated in ActiveStorage
|
||||||
|
remove_column :dmsf_file_revisions, :digest
|
||||||
|
remove_column :dmsf_file_revisions, :mime_type
|
||||||
|
remove_column :dmsf_file_revisions, :disk_filename
|
||||||
|
remove_column :dmsf_files, :name
|
||||||
|
# We need to keep the size despite the fact that it's duplicated in active_storage_blobs to speed up the main
|
||||||
|
# document view
|
||||||
|
# Restore updated_at column
|
||||||
|
DmsfFileRevision.update_all 'updated_at = temp_updated_at'
|
||||||
|
remove_column :dmsf_file_revisions, :temp_updated_at
|
||||||
$stdout.puts 'Done'
|
$stdout.puts 'Done'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Active Storage -> File system
|
# Active Storage -> File system
|
||||||
def down
|
def down
|
||||||
$stdout.puts 'It could be a very long process. Be patient...'
|
$stdout.puts 'It could be a very long process. Be patient...'
|
||||||
|
# Restore removed columns
|
||||||
|
add_column :dmsf_file_revisions, :digest, :string, limit: 64, default: '', null: false
|
||||||
|
add_column :dmsf_file_revisions, :mime_type, :string
|
||||||
|
add_column :dmsf_file_revisions, :disk_filename, :string, default: '', null: false
|
||||||
|
add_column :dmsf_files, :name, :string, default: '', null: false
|
||||||
|
# Migrate attachments
|
||||||
ActiveStorage::Attachment.find_each do |a|
|
ActiveStorage::Attachment.find_each do |a|
|
||||||
r = a.record
|
r = a.record
|
||||||
new_path = r.disk_file(search_if_not_exists: false)
|
new_path = disk_file
|
||||||
unless File.exist?(new_path)
|
unless File.exist?(new_path)
|
||||||
a.blob.open do |f|
|
a.blob.open do |f|
|
||||||
|
# Move the attachment
|
||||||
FileUtils.mv f.path, new_path
|
FileUtils.mv f.path, new_path
|
||||||
|
r.record_timestamps = false # Do not modify updated_at column
|
||||||
|
DmsfFileRevision.no_touching do
|
||||||
|
# Mime type
|
||||||
|
r.mime_type = f.content_type
|
||||||
|
# Disk filename
|
||||||
|
r.disk_filename = File.basename(new_path)
|
||||||
|
# Digest
|
||||||
|
# We leave the digest calculation to dmsf_create_digests.rake task
|
||||||
|
r.save
|
||||||
|
end
|
||||||
|
r.dmsf_file.record_timestamps = false # Do not modify updated_at column
|
||||||
|
DmsfFile.no_touching do
|
||||||
|
# Filename
|
||||||
|
r.dmsf_file.name = r.dmsf_file.last_revision.name
|
||||||
|
r.dmsf_file.save
|
||||||
|
end
|
||||||
end
|
end
|
||||||
key = a.blob.key
|
key = a.blob.key
|
||||||
$stdout.puts "#{File.join(key[0..1], key[2..3], key)} (#{a.blob.filename}) => #{new_path}"
|
$stdout.puts "#{File.join(key[0..1], key[2..3], key)} (#{a.blob.filename}) => #{new_path}"
|
||||||
@ -100,4 +133,19 @@ class ActiveStorageMigration < ActiveRecord::Migration[7.0]
|
|||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def storage_base_path(dmsf_file_revision)
|
||||||
|
time = dmsf_file_revision.created_at || DateTime.current
|
||||||
|
DmsfFile.storage_path.join(time.strftime('%Y')).join time.strftime('%m')
|
||||||
|
end
|
||||||
|
|
||||||
|
def disk_file(dmsf_file_revision)
|
||||||
|
path = storage_base_path
|
||||||
|
begin
|
||||||
|
FileUtils.mkdir_p path
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error e.message
|
||||||
|
end
|
||||||
|
path.join(dmsf_file_revision.disk_filename).to_s
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# Redmine plugin for Document Management System "Features"
|
|
||||||
#
|
|
||||||
# Karel Pičman <karel.picman@kontron.com>
|
|
||||||
#
|
|
||||||
# This file is part of Redmine DMSF plugin.
|
|
||||||
#
|
|
||||||
# Redmine DMSF plugin 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 3 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
#
|
|
||||||
# Redmine DMSF plugin 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 Redmine DMSF plugin. If not, see
|
|
||||||
# <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Restore DmsfFileRevision.updated_at from DmsfFileRevision.temp_updated_at column
|
|
||||||
class RestoreUpdatedAt < ActiveRecord::Migration[7.0]
|
|
||||||
# temp_updated_at => updated_at
|
|
||||||
def up
|
|
||||||
DmsfFileRevision.update_all 'updated_at = temp_updated_at'
|
|
||||||
remove_column :dmsf_file_revisions, :temp_updated_at
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# Redmine plugin for Document Management System "Features"
|
|
||||||
#
|
|
||||||
# Karel Pičman <karel.picman@kontron.com>
|
|
||||||
#
|
|
||||||
# This file is part of Redmine DMSF plugin.
|
|
||||||
#
|
|
||||||
# Redmine DMSF plugin 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 3 of the License, or (at your option) any
|
|
||||||
# later version.
|
|
||||||
#
|
|
||||||
# Redmine DMSF plugin 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 Redmine DMSF plugin. If not, see
|
|
||||||
# <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# Add column
|
|
||||||
class RemoveDuplicitiesFromRevision < ActiveRecord::Migration[7.0]
|
|
||||||
def up
|
|
||||||
remove_column :dmsf_file_revisions, :digest
|
|
||||||
remove_column :dmsf_file_revisions, :mime_type
|
|
||||||
# We need to keep the size despite the fact that it's duplicated in active_storage_blobs to speed up the main
|
|
||||||
# document view
|
|
||||||
end
|
|
||||||
|
|
||||||
def down
|
|
||||||
add_column :dmsf_file_revisions, :digest, :string, limit: 64, default: '', null: false
|
|
||||||
add_column :dmsf_file_revisions, :mime_type, :string
|
|
||||||
# Recalculation of these columns for all revisions is technically possible but costs are too high.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -91,7 +91,7 @@ module RedmineDmsf
|
|||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
class: 'icon icon-file',
|
class: 'icon icon-file',
|
||||||
title: h(revision.try(:tooltip)),
|
title: h(revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{revision.detect_content_type}:#{h(revision.dmsf_file.name)}:#{file_view_url}"
|
'data-downloadurl' => "#{revision.content_type}:#{h(revision.dmsf_file.name)}:#{file_view_url}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -49,7 +49,7 @@ module RedmineDmsf
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(revision.tooltip),
|
title: h(revision.tooltip),
|
||||||
'data-downloadurl' => "#{file.last_revision.detect_content_type}:#{h(file.name)}:#{url}"
|
'data-downloadurl' => "#{file.last_revision.content_type}:#{h(file.name)}:#{url}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# dmsff - link to a folder
|
# dmsff - link to a folder
|
||||||
@ -278,7 +278,7 @@ module RedmineDmsf
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(file.last_revision.try(:tooltip)),
|
title: h(file.last_revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{file.last_revision.detect_content_type}:#{h(file.name)}:#{url}")
|
'data-downloadurl' => "#{file.last_revision.content_type}:#{h(file.name)}:#{url}")
|
||||||
end
|
end
|
||||||
safe_join html
|
safe_join html
|
||||||
end
|
end
|
||||||
|
|||||||
@ -31,7 +31,7 @@ module RedmineDmsf
|
|||||||
def get_image_filename(attrname)
|
def get_image_filename(attrname)
|
||||||
if attrname =~ %r{/dmsf/files/(\d+)/}
|
if attrname =~ %r{/dmsf/files/(\d+)/}
|
||||||
file = DmsfFile.find_by(id: Regexp.last_match(1))
|
file = DmsfFile.find_by(id: Regexp.last_match(1))
|
||||||
file&.last_revision&.disk_file
|
file.last_revision.file&.blob&.filename if file&.last_revision
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|||||||
@ -49,9 +49,9 @@ module RedmineDmsf
|
|||||||
# New methods
|
# New methods
|
||||||
def self.prepended(base)
|
def self.prepended(base)
|
||||||
base.class_eval do
|
base.class_eval do
|
||||||
has_many :dmsf_files, -> { where(dmsf_folder_id: nil).order(:name) },
|
has_many :dmsf_files, -> { where(dmsf_folder_id: nil) },
|
||||||
class_name: 'DmsfFile', foreign_key: 'project_id', dependent: :destroy
|
class_name: 'DmsfFile', foreign_key: 'project_id', dependent: :destroy
|
||||||
has_many :dmsf_folders, -> { where(dmsf_folder_id: nil).order(:title) },
|
has_many :dmsf_folders, -> { where(dmsf_folder_id: nil) },
|
||||||
class_name: 'DmsfFolder', foreign_key: 'project_id', dependent: :destroy
|
class_name: 'DmsfFolder', foreign_key: 'project_id', dependent: :destroy
|
||||||
has_many :dmsf_workflows, dependent: :destroy
|
has_many :dmsf_workflows, dependent: :destroy
|
||||||
has_many :folder_links, -> { where dmsf_folder_id: nil, target_type: 'DmsfFolder' },
|
has_many :folder_links, -> { where dmsf_folder_id: nil, target_type: 'DmsfFolder' },
|
||||||
|
|||||||
@ -55,7 +55,7 @@ module RedmineDmsf
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Gather collection of objects that denote current entities child entities
|
# Gather collection of objects that denote current entities child entities
|
||||||
# Used for listing directories etc, implemented basic caching because otherwise
|
# Used for listing directories etc., implemented basic caching because otherwise
|
||||||
# Our already quite heavy usage of DB would just get silly every time we called
|
# Our already quite heavy usage of DB would just get silly every time we called
|
||||||
# this method.
|
# this method.
|
||||||
def children
|
def children
|
||||||
@ -63,12 +63,12 @@ module RedmineDmsf
|
|||||||
@children = []
|
@children = []
|
||||||
if folder
|
if folder
|
||||||
# Folders
|
# Folders
|
||||||
folder.dmsf_folders.visible.each do |f|
|
folder.dmsf_folders.visible.each do |folder|
|
||||||
@children.push child(f.title) if DmsfFolder.permissions?(f, allow_system: false)
|
@children.push child(folder.title) if DmsfFolder.permissions?(folder, allow_system: false)
|
||||||
end
|
end
|
||||||
# Files
|
# Files
|
||||||
folder.dmsf_files.visible.pluck(:name).each do |name|
|
folder.dmsf_files.visible.each do |file|
|
||||||
@children.push child(name)
|
@children.push child(file.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -92,7 +92,7 @@ module RedmineDmsf
|
|||||||
def content_type
|
def content_type
|
||||||
if file
|
if file
|
||||||
if file.last_revision
|
if file.last_revision
|
||||||
file.last_revision.detect_content_type
|
file.last_revision.content_type
|
||||||
else
|
else
|
||||||
'application/octet-stream'
|
'application/octet-stream'
|
||||||
end
|
end
|
||||||
@ -126,13 +126,7 @@ module RedmineDmsf
|
|||||||
end
|
end
|
||||||
|
|
||||||
def etag
|
def etag
|
||||||
ino = if file&.last_revision && File.exist?(file.last_revision.disk_file)
|
format '%<node>x-%<size>x-%<modified>x', node: 0, size: content_length, modified: last_modified.to_i
|
||||||
File.stat(file.last_revision.disk_file).ino
|
|
||||||
else
|
|
||||||
2
|
|
||||||
end
|
|
||||||
format '%<node>x-%<size>x-%<modified>x',
|
|
||||||
node: ino, size: content_length, modified: (last_modified ? last_modified.to_i : 0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def content_length
|
def content_length
|
||||||
@ -272,10 +266,8 @@ module RedmineDmsf
|
|||||||
new_revision = dest.resource.file.last_revision.clone
|
new_revision = dest.resource.file.last_revision.clone
|
||||||
new_revision.increase_version DmsfFileRevision::PATCH_VERSION
|
new_revision.increase_version DmsfFileRevision::PATCH_VERSION
|
||||||
end
|
end
|
||||||
# The file on disk must be renamed from .tmp to the correct filetype or else Xapian won't know how to index.
|
# Copy the file
|
||||||
# Copy file.last_revision.disk_file to new_revision.disk_file
|
|
||||||
new_revision.size = file.last_revision.size
|
new_revision.size = file.last_revision.size
|
||||||
new_revision.disk_filename = new_revision.new_storage_filename
|
|
||||||
new_revision.copy_file_content StringIO.new(file.last_revision.file.download)
|
new_revision.copy_file_content StringIO.new(file.last_revision.file.download)
|
||||||
# Save
|
# Save
|
||||||
new_revision.save && dest.resource.file.save
|
new_revision.save && dest.resource.file.save
|
||||||
@ -304,7 +296,6 @@ module RedmineDmsf
|
|||||||
file.last_revision.name = dest.resource.basename
|
file.last_revision.name = dest.resource.basename
|
||||||
file.last_revision.title = DmsfFileRevision.filename_to_title(dest.resource.basename)
|
file.last_revision.title = DmsfFileRevision.filename_to_title(dest.resource.basename)
|
||||||
end
|
end
|
||||||
file.name = dest.resource.basename
|
|
||||||
# Save Changes
|
# Save Changes
|
||||||
if file.last_revision.save && file.save
|
if file.last_revision.save && file.save
|
||||||
dest.exist? ? NoContent : Created
|
dest.exist? ? NoContent : Created
|
||||||
@ -376,7 +367,6 @@ module RedmineDmsf
|
|||||||
|
|
||||||
# Update Revision and names of file (We can link to old physical resource, as it's not changed)
|
# Update Revision and names of file (We can link to old physical resource, as it's not changed)
|
||||||
new_file.last_revision.name = dest.resource.basename
|
new_file.last_revision.name = dest.resource.basename
|
||||||
new_file.name = dest.resource.basename
|
|
||||||
# Save Changes
|
# Save Changes
|
||||||
unless new_file.last_revision.save && new_file.save
|
unless new_file.last_revision.save && new_file.save
|
||||||
new_file.delete commit: true
|
new_file.delete commit: true
|
||||||
@ -587,7 +577,6 @@ module RedmineDmsf
|
|||||||
else
|
else
|
||||||
f = DmsfFile.new
|
f = DmsfFile.new
|
||||||
f.project_id = project.id
|
f.project_id = project.id
|
||||||
f.name = basename
|
|
||||||
f.dmsf_folder = parent.folder
|
f.dmsf_folder = parent.folder
|
||||||
f.notification = RedmineDmsf.dmsf_default_notifications?
|
f.notification = RedmineDmsf.dmsf_default_notifications?
|
||||||
new_revision = DmsfFileRevision.new
|
new_revision = DmsfFileRevision.new
|
||||||
@ -627,7 +616,6 @@ module RedmineDmsf
|
|||||||
raise UnprocessableEntity
|
raise UnprocessableEntity
|
||||||
end
|
end
|
||||||
|
|
||||||
new_revision.disk_filename = new_revision.new_storage_filename unless reuse_revision
|
|
||||||
if new_revision.save
|
if new_revision.save
|
||||||
if request.body.respond_to?(:rewind)
|
if request.body.respond_to?(:rewind)
|
||||||
new_revision.copy_file_content request.body
|
new_revision.copy_file_content request.body
|
||||||
@ -775,7 +763,6 @@ module RedmineDmsf
|
|||||||
def create_empty_file
|
def create_empty_file
|
||||||
f = DmsfFile.new
|
f = DmsfFile.new
|
||||||
f.project_id = project.id
|
f.project_id = project.id
|
||||||
f.name = basename
|
|
||||||
f.dmsf_folder = parent.folder
|
f.dmsf_folder = parent.folder
|
||||||
if f.save(validate: false) # Skip validation due to invalid characters in the filename
|
if f.save(validate: false) # Skip validation due to invalid characters in the filename
|
||||||
r = DmsfFileRevision.new
|
r = DmsfFileRevision.new
|
||||||
@ -786,14 +773,18 @@ module RedmineDmsf
|
|||||||
r.user = User.current
|
r.user = User.current
|
||||||
r.name = basename
|
r.name = basename
|
||||||
r.size = 0
|
r.size = 0
|
||||||
r.disk_filename = r.new_storage_filename
|
|
||||||
r.available_custom_fields.each do |cf| # Add default value for CFs not existing
|
r.available_custom_fields.each do |cf| # Add default value for CFs not existing
|
||||||
next unless cf.default_value
|
next unless cf.default_value
|
||||||
|
|
||||||
r.custom_field_values << CustomValue.new({ custom_field: cf, value: cf.default_value })
|
r.custom_field_values << CustomValue.new({ custom_field: cf, value: cf.default_value })
|
||||||
end
|
end
|
||||||
if r.save(validate: false) # Skip validation due to invalid characters in the filename
|
if r.save(validate: false) # Skip validation due to invalid characters in the filename
|
||||||
FileUtils.touch r.disk_file(search_if_not_exists: false)
|
revision.file.attach(
|
||||||
|
io: File.new(upload.tempfile_path),
|
||||||
|
filename: file_upload.filename,
|
||||||
|
content_type: Redmine::MimeType.of(file_upload.filename),
|
||||||
|
identify: false
|
||||||
|
)
|
||||||
return f
|
return f
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -41,8 +41,8 @@ module RedmineDmsf
|
|||||||
end
|
end
|
||||||
# Files
|
# Files
|
||||||
if User.current.allowed_to?(:view_dmsf_files, project)
|
if User.current.allowed_to?(:view_dmsf_files, project)
|
||||||
project.dmsf_files.visible.pluck(:name).each do |name|
|
project.dmsf_files.visible.each do |file|
|
||||||
@children.push child(name)
|
@children.push child(file.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@children
|
@children
|
||||||
|
|||||||
16
test/fixtures/active_storage_attachments.yml
vendored
16
test/fixtures/active_storage_attachments.yml
vendored
@ -31,14 +31,6 @@ active_storage_attachment_4:
|
|||||||
blob_id: 4
|
blob_id: 4
|
||||||
created_at: <%= Time.now %>
|
created_at: <%= Time.now %>
|
||||||
|
|
||||||
#active_storage_attachment_5:
|
|
||||||
# id: 5
|
|
||||||
# name: 'shared_file'
|
|
||||||
# record_type: 'DmsfFileRevision'
|
|
||||||
# record_id: 5
|
|
||||||
# blob_id: 5
|
|
||||||
# created_at: <%= Time.now %>
|
|
||||||
|
|
||||||
active_storage_attachment_6:
|
active_storage_attachment_6:
|
||||||
id: 6
|
id: 6
|
||||||
name: 'shared_file'
|
name: 'shared_file'
|
||||||
@ -102,3 +94,11 @@ active_storage_attachment_13:
|
|||||||
record_id: 13
|
record_id: 13
|
||||||
blob_id: 13
|
blob_id: 13
|
||||||
created_at: <%= Time.now %>
|
created_at: <%= Time.now %>
|
||||||
|
|
||||||
|
active_storage_attachment_14:
|
||||||
|
id: 14
|
||||||
|
name: 'shared_file'
|
||||||
|
record_type: 'DmsfFileRevision'
|
||||||
|
record_id: 14
|
||||||
|
blob_id: 14
|
||||||
|
created_at: <%= Time.now %>
|
||||||
|
|||||||
11
test/fixtures/active_storage_blobs.yml
vendored
11
test/fixtures/active_storage_blobs.yml
vendored
@ -130,3 +130,14 @@ active_storage_blob_13:
|
|||||||
byte_size: 10179
|
byte_size: 10179
|
||||||
checksum : 'k08HeKksIVI7PXr1aEVbjg=='
|
checksum : 'k08HeKksIVI7PXr1aEVbjg=='
|
||||||
created_at: <%= Time.now %>
|
created_at: <%= Time.now %>
|
||||||
|
|
||||||
|
active_storage_blob_14:
|
||||||
|
id: 14
|
||||||
|
key: '5lge4yv88jwzt7xl76vri2be1v14'
|
||||||
|
filename: 'test.html'
|
||||||
|
content_type: 'text/html'
|
||||||
|
metadata: '{"identified":true,"analyzed":true}'
|
||||||
|
service_name: 'test'
|
||||||
|
byte_size: 10179
|
||||||
|
checksum : 'RV3RPuaIjvHzOXpvTLhI3w=='
|
||||||
|
created_at: <%= Time.now %>
|
||||||
|
|||||||
33
test/fixtures/dmsf_file_revisions.yml
vendored
33
test/fixtures/dmsf_file_revisions.yml
vendored
@ -4,7 +4,6 @@ dmsf_file_revisions_001:
|
|||||||
dmsf_file_id: 1
|
dmsf_file_id: 1
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: "test.txt"
|
name: "test.txt"
|
||||||
disk_filename: "test.txt"
|
|
||||||
size: 3
|
size: 3
|
||||||
title: "Test File"
|
title: "Test File"
|
||||||
description: 'Some file :-)'
|
description: 'Some file :-)'
|
||||||
@ -25,7 +24,6 @@ dmsf_file_revisions_002:
|
|||||||
dmsf_file_id: 2
|
dmsf_file_id: 2
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: "test2.txt"
|
name: "test2.txt"
|
||||||
disk_filename: "test2.txt"
|
|
||||||
size: 3
|
size: 3
|
||||||
title: "Test File"
|
title: "Test File"
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -46,7 +44,6 @@ dmsf_file_revisions_003:
|
|||||||
dmsf_file_id: 3
|
dmsf_file_id: 3
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'deleted.txt'
|
name: 'deleted.txt'
|
||||||
disk_filename: 'deleted.txt'
|
|
||||||
size: 3
|
size: 3
|
||||||
title: 'Test File'
|
title: 'Test File'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -66,7 +63,6 @@ dmsf_file_revisions_004:
|
|||||||
dmsf_file_id: 4
|
dmsf_file_id: 4
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test4.txt'
|
name: 'test4.txt'
|
||||||
disk_filename: 'test4.txt'
|
|
||||||
size: 3
|
size: 3
|
||||||
title: 'Test File'
|
title: 'Test File'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -86,7 +82,6 @@ dmsf_file_revisions_006:
|
|||||||
dmsf_file_id: 7
|
dmsf_file_id: 7
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.gif'
|
name: 'test.gif'
|
||||||
disk_filename: 'test.gif'
|
|
||||||
size: 310
|
size: 310
|
||||||
title: 'Test image'
|
title: 'Test image'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -106,7 +101,6 @@ dmsf_file_revisions_007:
|
|||||||
dmsf_file_id: 8
|
dmsf_file_id: 8
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.pdf'
|
name: 'test.pdf'
|
||||||
disk_filename: 'test.pdf'
|
|
||||||
size: 6942
|
size: 6942
|
||||||
title: 'Test PDF'
|
title: 'Test PDF'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -125,8 +119,7 @@ dmsf_file_revisions_008:
|
|||||||
id: 8
|
id: 8
|
||||||
dmsf_file_id: 9
|
dmsf_file_id: 9
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'myfile.txt'
|
name: 'myfile.txt' # The file is not physically present
|
||||||
disk_filename: 'myfile.txt' # The file is not physically present
|
|
||||||
size: 0
|
size: 0
|
||||||
title: 'My File'
|
title: 'My File'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -146,7 +139,6 @@ dmsf_file_revisions_009:
|
|||||||
dmsf_file_id: 10
|
dmsf_file_id: 10
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'zero.txt'
|
name: 'zero.txt'
|
||||||
disk_filename: 'zero.txt'
|
|
||||||
size: 0
|
size: 0
|
||||||
title: 'Zero Size File'
|
title: 'Zero Size File'
|
||||||
description: NULL
|
description: NULL
|
||||||
@ -166,7 +158,6 @@ dmsf_file_revisions_010:
|
|||||||
dmsf_file_id: 5
|
dmsf_file_id: 5
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.txt'
|
name: 'test.txt'
|
||||||
disk_filename: 'test.txt'
|
|
||||||
size: 4
|
size: 4
|
||||||
title: 'Test File'
|
title: 'Test File'
|
||||||
description: 'Some file :-)'
|
description: 'Some file :-)'
|
||||||
@ -186,7 +177,6 @@ dmsf_file_revisions_011:
|
|||||||
dmsf_file_id: 12
|
dmsf_file_id: 12
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.txt'
|
name: 'test.txt'
|
||||||
disk_filename: 'test.txt'
|
|
||||||
size: 4
|
size: 4
|
||||||
title: 'Test File'
|
title: 'Test File'
|
||||||
description: 'Some file :-)'
|
description: 'Some file :-)'
|
||||||
@ -206,7 +196,6 @@ dmsf_file_revisions_012:
|
|||||||
dmsf_file_id: 6
|
dmsf_file_id: 6
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.mp4'
|
name: 'test.mp4'
|
||||||
disk_filename: 'test.mp4'
|
|
||||||
size: 4
|
size: 4
|
||||||
title: 'test video'
|
title: 'test video'
|
||||||
description: 'A video :-)'
|
description: 'A video :-)'
|
||||||
@ -226,7 +215,6 @@ dmsf_file_revisions_013:
|
|||||||
dmsf_file_id: 13
|
dmsf_file_id: 13
|
||||||
source_dmsf_file_revision_id: NULL
|
source_dmsf_file_revision_id: NULL
|
||||||
name: 'test.odt'
|
name: 'test.odt'
|
||||||
disk_filename: 'test.odt'
|
|
||||||
size: 10445
|
size: 10445
|
||||||
title: 'Test office document'
|
title: 'Test office document'
|
||||||
description: 'LibreOffice text'
|
description: 'LibreOffice text'
|
||||||
@ -240,3 +228,22 @@ dmsf_file_revisions_013:
|
|||||||
dmsf_workflow_assigned_by_user_id: NULL
|
dmsf_workflow_assigned_by_user_id: NULL
|
||||||
dmsf_workflow_started_by_user_id: NULL
|
dmsf_workflow_started_by_user_id: NULL
|
||||||
created_at: 2017-04-01 08:54:00 +02:00
|
created_at: 2017-04-01 08:54:00 +02:00
|
||||||
|
|
||||||
|
dmsf_file_revisions_014:
|
||||||
|
id: 14
|
||||||
|
dmsf_file_id: 14
|
||||||
|
source_dmsf_file_revision_id: NULL
|
||||||
|
name: 'test.html'
|
||||||
|
size: 10445
|
||||||
|
title: 'Webpage'
|
||||||
|
description: 'HTML document'
|
||||||
|
workflow: 0
|
||||||
|
minor_version: 0
|
||||||
|
major_version: 1
|
||||||
|
comment: NULL
|
||||||
|
deleted: 0
|
||||||
|
deleted_by_user_id: NULL
|
||||||
|
user_id: 1
|
||||||
|
dmsf_workflow_assigned_by_user_id: NULL
|
||||||
|
dmsf_workflow_started_by_user_id: NULL
|
||||||
|
created_at: 2017-04-01 08:54:00 +02:00
|
||||||
20
test/fixtures/dmsf_files.yml
vendored
20
test/fixtures/dmsf_files.yml
vendored
@ -3,7 +3,6 @@ dmsf_files_001:
|
|||||||
id: 1
|
id: 1
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'test.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -13,7 +12,6 @@ dmsf_files_002:
|
|||||||
id: 2
|
id: 2
|
||||||
project_id: 2
|
project_id: 2
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'test.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -23,7 +21,6 @@ dmsf_files_003:
|
|||||||
id: 3
|
id: 3
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'deleted.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 1
|
deleted: 1
|
||||||
deleted_by_user_id: 1
|
deleted_by_user_id: 1
|
||||||
@ -32,7 +29,6 @@ dmsf_files_004:
|
|||||||
id: 4
|
id: 4
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: 2
|
dmsf_folder_id: 2
|
||||||
name: 'test.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -41,7 +37,6 @@ dmsf_files_005:
|
|||||||
id: 5
|
id: 5
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: 5
|
dmsf_folder_id: 5
|
||||||
name: 'test.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -50,7 +45,6 @@ dmsf_files_006:
|
|||||||
id: 6
|
id: 6
|
||||||
project_id: 2
|
project_id: 2
|
||||||
dmsf_folder_id: 3
|
dmsf_folder_id: 3
|
||||||
name: 'test.mp4'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -59,7 +53,6 @@ dmsf_files_007:
|
|||||||
id: 7
|
id: 7
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: 8
|
dmsf_folder_id: 8
|
||||||
name: 'test.gif'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -68,7 +61,6 @@ dmsf_files_008:
|
|||||||
id: 8
|
id: 8
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'test.pdf'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -77,7 +69,6 @@ dmsf_files_009:
|
|||||||
id: 9
|
id: 9
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'myfile.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -86,7 +77,6 @@ dmsf_files_010:
|
|||||||
id: 10
|
id: 10
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'zero.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -95,7 +85,6 @@ dmsf_files_011:
|
|||||||
id: 11
|
id: 11
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: 9
|
dmsf_folder_id: 9
|
||||||
name: 'zero.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -104,7 +93,6 @@ dmsf_files_012:
|
|||||||
id: 12
|
id: 12
|
||||||
project_id: 5
|
project_id: 5
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'test.txt'
|
|
||||||
notification: false
|
notification: false
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
@ -113,6 +101,12 @@ dmsf_files_013:
|
|||||||
id: 13
|
id: 13
|
||||||
project_id: 1
|
project_id: 1
|
||||||
dmsf_folder_id: NULL
|
dmsf_folder_id: NULL
|
||||||
name: 'test.odt'
|
deleted: 0
|
||||||
|
deleted_by_user_id: NULL
|
||||||
|
|
||||||
|
dmsf_files_014:
|
||||||
|
id: 14
|
||||||
|
project_id: 1
|
||||||
|
dmsf_folder_id: NULL
|
||||||
deleted: 0
|
deleted: 0
|
||||||
deleted_by_user_id: NULL
|
deleted_by_user_id: NULL
|
||||||
6
test/fixtures/files/5l/ge/5lge4yv88jwzt7xl76vri2be1v14
vendored
Normal file
6
test/fixtures/files/5l/ge/5lge4yv88jwzt7xl76vri2be1v14
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
Hello world!
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -142,9 +142,9 @@ class DmsfFilesControllerTest < RedmineDmsf::Test::TestCase
|
|||||||
version_major: @file1.last_revision.major_version,
|
version_major: @file1.last_revision.major_version,
|
||||||
version_minor: @file1.last_revision.minor_version + 1,
|
version_minor: @file1.last_revision.minor_version + 1,
|
||||||
dmsf_file_revision: {
|
dmsf_file_revision: {
|
||||||
title: @file1.last_revision.title,
|
title: @file1.title,
|
||||||
name: @file1.last_revision.name,
|
name: @file1.name,
|
||||||
description: @file1.last_revision.description,
|
description: @file1.description,
|
||||||
comment: 'New revision'
|
comment: 'New revision'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
# <name>test5.txt</name>
|
# <name>test5.txt</name>
|
||||||
# <content_url>http://www.example.com/dmsf/files/1/view?download=5</content_url>
|
# <content_url>http://www.example.com/dmsf/files/1/view?download=5</content_url>
|
||||||
# <size>4</size>
|
# <size>4</size>
|
||||||
# <mime_type>text/plain</mime_type>
|
# <content_type>text/plain</content_type>
|
||||||
# <title>Test File</title>
|
# <title>Test File</title>
|
||||||
# <description/>
|
# <description/>
|
||||||
# <workflow>1</workflow>
|
# <workflow>1</workflow>
|
||||||
@ -71,7 +71,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
# <name>test.txt</name>
|
# <name>test.txt</name>
|
||||||
# <content_url>http://www.example.com/dmsf/files/1/view?download=1</content_url>
|
# <content_url>http://www.example.com/dmsf/files/1/view?download=1</content_url>
|
||||||
# <size>4</size>
|
# <size>4</size>
|
||||||
# <mime_type>text/plain</mime_type>
|
# <content_type>text/plain</content_type>
|
||||||
# <title>Test File</title>
|
# <title>Test File</title>
|
||||||
# <description>Some file :-)</description>
|
# <description>Some file :-)</description>
|
||||||
# <workflow>1</workflow>
|
# <workflow>1</workflow>
|
||||||
@ -160,7 +160,7 @@ class DmsfFileApiTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
assert_response :success
|
assert_response :success
|
||||||
revision = DmsfFileRevision.order(:created_at).last
|
revision = DmsfFileRevision.order(:created_at).last
|
||||||
assert revision.present?
|
assert revision.present?
|
||||||
assert_equal 'text/plain', revision.mime_type
|
assert_equal 'text/plain', revision.content_type
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_upload_document_exceeded_attachment_max_size
|
def test_upload_document_exceeded_attachment_max_size
|
||||||
|
|||||||
@ -154,11 +154,11 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
folder = DmsfFolder.find_by(id: 1)
|
folder = DmsfFolder.find_by(id: 1)
|
||||||
assert_not_nil folder
|
assert_not_nil folder
|
||||||
assert response.body.match(@folder1.title),
|
assert response.body.match(@folder1.title),
|
||||||
"Expected to find #{folder.title} in return data"
|
"Expected to find #{folder.title} in the response"
|
||||||
file = DmsfFile.find_by(id: 1)
|
file = DmsfFile.find_by(id: 1)
|
||||||
assert_not_nil file
|
assert_not_nil file
|
||||||
assert response.body.match(file.name),
|
assert response.body.match(file.name),
|
||||||
"Expected to find #{file.name} in return data"
|
"Expected to find #{file.name} in the response"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_user_assigned_to_project_dmsf_module_not_enabled
|
def test_user_assigned_to_project_dmsf_module_not_enabled
|
||||||
|
|||||||
@ -308,7 +308,7 @@ class DmsfWebdavMoveTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
temp_file = DmsfFile.find_file_by_name @project1, nil, temp_file_name
|
temp_file = DmsfFile.find_file_by_name @project1, nil, temp_file_name
|
||||||
assert_not temp_file, "File '#{temp_file_name}' should not exist yet."
|
assert_not temp_file, "File '#{temp_file_name}' should not exist yet."
|
||||||
|
|
||||||
# Move the original file to AAAAAAAA.tmp. The original file should not changed but a new file should be created.
|
# Move the original file to AAAAAAAA.tmp. The original file should not be changed but a new file should be created.
|
||||||
assert_no_difference '@file1.dmsf_file_revisions.count' do
|
assert_no_difference '@file1.dmsf_file_revisions.count' do
|
||||||
process :move,
|
process :move,
|
||||||
"/dmsf/webdav/#{@project1.identifier}/#{@file1.name}",
|
"/dmsf/webdav/#{@project1.identifier}/#{@file1.name}",
|
||||||
|
|||||||
@ -255,7 +255,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
|
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", params: '1234', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", params: '1234', headers: credentials
|
||||||
assert_response :success
|
assert_response :success
|
||||||
file1 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder: nil, name: 'file1.tmp')
|
file1 = DmsfFile.find_file_by_name(@project1, nil, 'file1.tmp')
|
||||||
assert file1
|
assert file1
|
||||||
assert_difference 'file1.dmsf_file_revisions.count', 0 do
|
assert_difference 'file1.dmsf_file_revisions.count', 0 do
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", params: '5678', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/file1.tmp", params: '5678', headers: credentials
|
||||||
@ -268,7 +268,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
|
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", params: '1234', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", params: '1234', headers: credentials
|
||||||
assert_response :success
|
assert_response :success
|
||||||
file2 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder_id: nil, name: '~$file2.txt')
|
file2 = DmsfFile.find_file_by_name(@project1, nil, '~$file2.txt')
|
||||||
assert file2
|
assert file2
|
||||||
assert_difference 'file2.dmsf_file_revisions.count', 0 do
|
assert_difference 'file2.dmsf_file_revisions.count', 0 do
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", params: '5678', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/~$file2.txt", params: '5678', headers: credentials
|
||||||
@ -286,7 +286,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
'dmsf_webdav_strategy' => 'WEBDAV_READ_WRITE' } do
|
'dmsf_webdav_strategy' => 'WEBDAV_READ_WRITE' } do
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/file3.dump", params: '1234', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/file3.dump", params: '1234', headers: credentials
|
||||||
assert_response :success
|
assert_response :success
|
||||||
file3 = DmsfFile.find_by(project_id: @project1.id, dmsf_folder_id: nil, name: 'file3.dump')
|
file3 = DmsfFile.find_file_by_name(@project1, nil, 'file3.dump')
|
||||||
assert file3
|
assert file3
|
||||||
assert_difference 'file3.dmsf_file_revisions.count', 0 do
|
assert_difference 'file3.dmsf_file_revisions.count', 0 do
|
||||||
put "/dmsf/webdav/#{@project1.identifier}/file3.dump", params: '5678', headers: credentials
|
put "/dmsf/webdav/#{@project1.identifier}/file3.dump", params: '5678', headers: credentials
|
||||||
@ -304,7 +304,7 @@ class DmsfWebdavPutTest < RedmineDmsf::Test::IntegrationTest
|
|||||||
params: '1234',
|
params: '1234',
|
||||||
headers: @admin.merge!({ content_type: :text })
|
headers: @admin.merge!({ content_type: :text })
|
||||||
assert_response :created
|
assert_response :created
|
||||||
assert DmsfFile.find_by(project_id: @project5.id, dmsf_folder: nil, name: 'test-1234.txt')
|
assert DmsfFile.find_file_by_name(@project5, nil, 'test-1234.txt')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_put_keep_title
|
def test_put_keep_title
|
||||||
|
|||||||
@ -28,34 +28,112 @@ class DmsfFileRevisionTest < RedmineDmsf::Test::UnitTest
|
|||||||
@revision1 = DmsfFileRevision.find 1
|
@revision1 = DmsfFileRevision.find 1
|
||||||
@revision2 = DmsfFileRevision.find 2
|
@revision2 = DmsfFileRevision.find 2
|
||||||
@revision3 = DmsfFileRevision.find 3
|
@revision3 = DmsfFileRevision.find 3
|
||||||
|
@revision7 = DmsfFileRevision.find 7
|
||||||
@revision8 = DmsfFileRevision.find 8
|
@revision8 = DmsfFileRevision.find 8
|
||||||
@revision13 = DmsfFileRevision.find 13
|
@revision13 = DmsfFileRevision.find 13
|
||||||
@wf1 = DmsfWorkflow.find 1
|
@wf1 = DmsfWorkflow.find 1
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_file_title_length_validation
|
def test_name_presence
|
||||||
file = DmsfFileRevision.new(title: Array.new(256).map { 'a' }.join,
|
@revision1.name = ''
|
||||||
name: 'Test Revision',
|
assert @revision1.invalid?
|
||||||
major_version: 1)
|
assert_includes @revision1.errors.full_messages, 'Name cannot be blank'
|
||||||
assert file.invalid?
|
|
||||||
assert_equal ['Title is too long (maximum is 255 characters)'], file.errors.full_messages
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_file_name_length_validation
|
def test_title_presence
|
||||||
file = DmsfFileRevision.new(name: Array.new(256).map { 'a' }.join,
|
@revision1.title = ''
|
||||||
title: 'Test Revision',
|
assert @revision1.invalid?
|
||||||
major_version: 1)
|
assert_includes @revision1.errors.full_messages, 'Title cannot be blank'
|
||||||
assert file.invalid?
|
|
||||||
assert_equal ['Name is too long (maximum is 255 characters)'], file.errors.full_messages
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_file_disk_filename_length_validation
|
def test_title_length_validation
|
||||||
file = DmsfFileRevision.new(disk_filename: Array.new(256).map { 'a' }.join,
|
@revision1.title = String.new('a' * 256)
|
||||||
title: 'Test Revision',
|
assert @revision1.invalid?
|
||||||
name: 'Test Revision',
|
assert_includes @revision1.errors.full_messages, 'Title is too long (maximum is 255 characters)'
|
||||||
major_version: 1)
|
end
|
||||||
assert file.invalid?
|
|
||||||
assert_equal ['Disk filename is too long (maximum is 255 characters)'], file.errors.full_messages
|
def test_name_length_validation
|
||||||
|
@revision1.name = String.new('a' * 256)
|
||||||
|
assert @revision1.invalid?
|
||||||
|
assert_includes @revision1.errors.full_messages, 'Name is too long (maximum is 255 characters)'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_name_uniqueness_validation
|
||||||
|
User.current = @admin
|
||||||
|
|
||||||
|
# Duplicity among files names
|
||||||
|
@revision7.name = @revision1.name
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among invisible files is all right
|
||||||
|
@revision7.name = @revision3.name
|
||||||
|
assert_not @revision7.invalid?
|
||||||
|
|
||||||
|
# Duplicity among files titles
|
||||||
|
@revision7.name = @revision1.title
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among folders
|
||||||
|
@revision7.name = @folder1.title
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among links
|
||||||
|
@revision7.name = @folder_link1.name
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Name is all right
|
||||||
|
@revision7.name = 'xxx'
|
||||||
|
assert @revision7.valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_uniqueness_validation
|
||||||
|
User.current = @admin
|
||||||
|
|
||||||
|
# Duplicity among files names
|
||||||
|
@revision7.title = @revision1.name
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among invisible files is all right
|
||||||
|
@revision7.title = @revision3.name
|
||||||
|
assert_not @revision7.invalid?
|
||||||
|
|
||||||
|
# Duplicity among files titles
|
||||||
|
@revision7.title = @revision1.title
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among folders
|
||||||
|
@revision7.title = @folder1.title
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among links
|
||||||
|
@revision7.title = @folder_link1.name
|
||||||
|
assert @revision7.invalid?
|
||||||
|
assert_includes @revision7.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Name is all right
|
||||||
|
@revision7.title = 'xxx'
|
||||||
|
assert @revision7.valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_name_invalid_characters_validation
|
||||||
|
@revision1.name << DmsfFolder::INVALID_CHARACTERS[0]
|
||||||
|
assert @revision1.invalid?
|
||||||
|
assert_includes @revision1.errors.full_messages,
|
||||||
|
"Name #{l('activerecord.errors.messages.error_contains_invalid_character')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_invalid_characters_validation
|
||||||
|
@revision1.title << DmsfFolder::INVALID_CHARACTERS[0]
|
||||||
|
assert @revision1.invalid?
|
||||||
|
assert_includes @revision1.errors.full_messages,
|
||||||
|
"Title #{l('activerecord.errors.messages.error_contains_invalid_character')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_delete_restore
|
def test_delete_restore
|
||||||
@ -70,56 +148,6 @@ class DmsfFileRevisionTest < RedmineDmsf::Test::UnitTest
|
|||||||
assert_nil DmsfFileRevision.find_by(id: @revision13.id)
|
assert_nil DmsfFileRevision.find_by(id: @revision13.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_new_storage_filename
|
|
||||||
# Create a file.
|
|
||||||
f = DmsfFile.new
|
|
||||||
f.project_id = 1
|
|
||||||
f.name = 'Testfile.txt'
|
|
||||||
f.dmsf_folder = nil
|
|
||||||
f.notification = RedmineDmsf.dmsf_default_notifications?
|
|
||||||
f.save
|
|
||||||
|
|
||||||
# Create two new revisions, r1 and r2
|
|
||||||
r1 = DmsfFileRevision.new
|
|
||||||
r1.minor_version = 0
|
|
||||||
r1.major_version = 1
|
|
||||||
r1.dmsf_file = f
|
|
||||||
r1.user = User.current
|
|
||||||
r1.name = 'Testfile.txt'
|
|
||||||
r1.title = DmsfFileRevision.filename_to_title(r1.name)
|
|
||||||
r1.description = nil
|
|
||||||
r1.comment = nil
|
|
||||||
r1.size = 4
|
|
||||||
|
|
||||||
r2 = r1.clone
|
|
||||||
r2.minor_version = 1
|
|
||||||
|
|
||||||
assert r1.valid?
|
|
||||||
assert r2.valid?
|
|
||||||
|
|
||||||
# This is a very stupid since the generation and storing of files below must be done during the
|
|
||||||
# same second, so wait until the microsecond part of the DateTime is less than 10 ms, should be
|
|
||||||
# plenty of time to do the rest then.
|
|
||||||
wait_timeout = 2_000
|
|
||||||
while DateTime.current.usec > 10_000
|
|
||||||
wait_timeout -= 10
|
|
||||||
flunk 'Waited too long.' if wait_timeout <= 0
|
|
||||||
sleep 0.01
|
|
||||||
end
|
|
||||||
|
|
||||||
# First, generate the r1 storage filename and save the file
|
|
||||||
r1.disk_filename = r1.new_storage_filename
|
|
||||||
assert r1.save
|
|
||||||
# Just make sure the file exists
|
|
||||||
File.binwrite r1.disk_file, '1234'
|
|
||||||
|
|
||||||
# Directly after the file has been stored generate the r2 storage filename.
|
|
||||||
# Hopefully the seconds part of the DateTime.current has not changed and the generated filename will
|
|
||||||
# be on the same second but it should then be increased by 1.
|
|
||||||
r2.disk_filename = r2.new_storage_filename
|
|
||||||
assert_not_equal r1.disk_filename, r2.disk_filename, 'The disk filename should not be equal for two revisions.'
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_invalid_filename_extension
|
def test_invalid_filename_extension
|
||||||
with_settings(attachment_extensions_allowed: 'txt') do
|
with_settings(attachment_extensions_allowed: 'txt') do
|
||||||
r1 = DmsfFileRevision.new
|
r1 = DmsfFileRevision.new
|
||||||
@ -334,4 +362,12 @@ class DmsfFileRevisionTest < RedmineDmsf::Test::UnitTest
|
|||||||
def test_checksum
|
def test_checksum
|
||||||
assert_equal @revision1.checksum, @revision1.file.blob.checksum
|
assert_equal @revision1.checksum, @revision1.file.blob.checksum
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_content_type
|
||||||
|
assert_equal 'text/plain', @revision1.content_type
|
||||||
|
@revision1.file.blob.content_type = ''
|
||||||
|
assert_equal 'text/plain', @revision1.content_type
|
||||||
|
@revision1.file.blob.filename = 'data'
|
||||||
|
assert_equal 'application/octet-stream', @revision1.content_type
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -28,12 +28,6 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
|
|||||||
@wf2 = DmsfWorkflow.find 2
|
@wf2 = DmsfWorkflow.find 2
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_file_name_length_validation
|
|
||||||
file = DmsfFile.new(name: Array.new(256).map { 'a' }.join)
|
|
||||||
assert file.invalid?
|
|
||||||
assert_equal ['Name is too long (maximum is 255 characters)'], file.errors.full_messages
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_project_file_count_differs_from_project_visibility_count
|
def test_project_file_count_differs_from_project_visibility_count
|
||||||
assert_not_same @project1.dmsf_files.all.size, @project1.dmsf_files.visible.all.size
|
assert_not_same @project1.dmsf_files.all.size, @project1.dmsf_files.visible.all.size
|
||||||
end
|
end
|
||||||
@ -188,15 +182,13 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
|
|||||||
# Text
|
# Text
|
||||||
assert_equal 'attachment', @file1.disposition
|
assert_equal 'attachment', @file1.disposition
|
||||||
# Image
|
# Image
|
||||||
assert_equal 'inline', @file7.disposition
|
assert_equal 'inline', @file6.disposition
|
||||||
# PDF
|
# PDF
|
||||||
assert_equal 'inline', @file8.disposition
|
assert_equal 'inline', @file7.disposition
|
||||||
# Video
|
# Video
|
||||||
@file1.last_revision.disk_filename = 'test.mp4'
|
assert_equal 'inline', @file6.disposition
|
||||||
assert_equal 'inline', @file1.disposition
|
|
||||||
# HTML
|
# HTML
|
||||||
@file1.last_revision.disk_filename = 'test.html'
|
assert_equal 'inline', @file14.disposition
|
||||||
assert_equal 'inline', @file1.disposition
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_image
|
def test_image
|
||||||
@ -209,8 +201,6 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
|
|||||||
assert @file1.text?
|
assert @file1.text?
|
||||||
assert_not @file7.text?
|
assert_not @file7.text?
|
||||||
assert_not @file8.text?
|
assert_not @file8.text?
|
||||||
@file1.last_revision.disk_filename = 'test.c'
|
|
||||||
assert @file1.text?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_pdf
|
def test_pdf
|
||||||
@ -221,25 +211,28 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
|
|||||||
|
|
||||||
def test_video
|
def test_video
|
||||||
assert_not @file1.video?
|
assert_not @file1.video?
|
||||||
@file1.last_revision.disk_filename = 'test.mp4'
|
assert @file6.video?
|
||||||
assert @file1.video?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_html
|
def test_html
|
||||||
assert_not @file1.html?
|
assert_not @file1.html?
|
||||||
@file1.last_revision.disk_filename = 'test.html'
|
assert @file14.html?
|
||||||
assert @file1.html?
|
end
|
||||||
|
|
||||||
|
def test_office_doc
|
||||||
|
assert_not @file1.office_doc?
|
||||||
|
assert @file13.office_doc?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_markdown
|
def test_markdown
|
||||||
assert_not @file1.markdown?
|
assert_not @file1.markdown?
|
||||||
@file1.last_revision.disk_filename = 'test.md'
|
@file1.last_revision.file.blob.content_type = 'text/markdown'
|
||||||
assert @file1.markdown?
|
assert @file1.markdown?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_textile
|
def test_textile
|
||||||
assert_not @file1.textile?
|
assert_not @file1.textile?
|
||||||
@file1.last_revision.disk_filename = 'test.textile'
|
@file1.last_revision.file.blob.content_type = 'text/textile'
|
||||||
assert @file1.textile?
|
assert @file1.textile?
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -293,10 +286,6 @@ class DmsfFileTest < RedmineDmsf::Test::UnitTest
|
|||||||
assert @file1.watched_by?(@jsmith)
|
assert @file1.watched_by?(@jsmith)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_office_doc
|
|
||||||
assert @file13.office_doc?
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_previewable
|
def test_previewable
|
||||||
assert(@file13.previewable?) if RedmineDmsf::Preview.office_available?
|
assert(@file13.previewable?) if RedmineDmsf::Preview.office_available?
|
||||||
end
|
end
|
||||||
|
|||||||
@ -21,9 +21,64 @@ require File.expand_path('../../test_helper', __FILE__)
|
|||||||
|
|
||||||
# Folder tests
|
# Folder tests
|
||||||
class DmsfFolderTest < RedmineDmsf::Test::UnitTest
|
class DmsfFolderTest < RedmineDmsf::Test::UnitTest
|
||||||
|
include Redmine::I18n
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
super
|
super
|
||||||
@link2 = DmsfLink.find 2
|
@link2 = DmsfLink.find 2
|
||||||
|
@revision1 = DmsfFileRevision.find 1
|
||||||
|
@revision3 = DmsfFileRevision.find 3
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_presence
|
||||||
|
@folder1.title = ''
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title cannot be blank'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_length_validation
|
||||||
|
@folder1.title = String.new('a' * 256)
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title is too long (maximum is 255 characters)'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_invalid_characters_validation
|
||||||
|
@folder1.title << DmsfFolder::INVALID_CHARACTERS[0]
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages,
|
||||||
|
"Title #{l('activerecord.errors.messages.error_contains_invalid_character')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_uniqueness_validation
|
||||||
|
User.current = @admin
|
||||||
|
|
||||||
|
# Duplicity among files names
|
||||||
|
@folder1.title = @revision1.name
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among invisible files is all right
|
||||||
|
@folder1.title = @revision3.name
|
||||||
|
assert_not @folder1.invalid?
|
||||||
|
|
||||||
|
# Duplicity among files titles
|
||||||
|
@folder1.title = @revision1.title
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among folders
|
||||||
|
@folder1.title = @folder6.title
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among links
|
||||||
|
@folder1.title = @folder_link1.name
|
||||||
|
assert @folder1.invalid?
|
||||||
|
assert_includes @folder1.errors.full_messages, 'Title has already been taken'
|
||||||
|
|
||||||
|
# Name is all right
|
||||||
|
@folder1.title = 'xxx'
|
||||||
|
assert @folder1.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_visibility
|
def test_visibility
|
||||||
|
|||||||
@ -21,6 +21,14 @@ require File.expand_path('../../test_helper', __FILE__)
|
|||||||
|
|
||||||
# Link tests
|
# Link tests
|
||||||
class DmsfLinksTest < RedmineDmsf::Test::UnitTest
|
class DmsfLinksTest < RedmineDmsf::Test::UnitTest
|
||||||
|
include Redmine::I18n
|
||||||
|
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@revision1 = DmsfFileRevision.find 1
|
||||||
|
@revision3 = DmsfFileRevision.find 3
|
||||||
|
end
|
||||||
|
|
||||||
def test_create_folder_link
|
def test_create_folder_link
|
||||||
folder_link = DmsfLink.new
|
folder_link = DmsfLink.new
|
||||||
folder_link.target_project_id = @project1.id
|
folder_link.target_project_id = @project1.id
|
||||||
@ -57,43 +65,77 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest
|
|||||||
assert external_link.save, external_link.errors.full_messages.to_sentence
|
assert external_link.save, external_link.errors.full_messages.to_sentence
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_name_length
|
def test_name_length_validation
|
||||||
@folder_link1.name = ('a' * 256)
|
@folder_link1.name = String.new('a' * 256)
|
||||||
assert_not @folder_link1.save, "Folder link #{@folder_link1.name} should have not been saved"
|
assert @folder_link1.invalid?
|
||||||
assert_equal 1, @folder_link1.errors.size
|
assert_includes @folder_link1.errors.full_messages, 'Name is too long (maximum is 255 characters)'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_name_presence
|
def test_validate_name_presence
|
||||||
@folder_link1.name = ''
|
@folder_link1.name = ''
|
||||||
assert_not @folder_link1.save, "Folder link #{@folder_link1.name} should have not been saved"
|
assert @folder_link1.invalid?
|
||||||
assert_equal 1, @folder_link1.errors.size
|
assert_includes @folder_link1.errors.full_messages, 'Name cannot be blank'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_title_invalid_characters_validation
|
||||||
|
@folder_link1.name << DmsfFolder::INVALID_CHARACTERS[0]
|
||||||
|
assert @folder_link1.invalid?
|
||||||
|
assert_includes @folder_link1.errors.full_messages,
|
||||||
|
"Name #{l('activerecord.errors.messages.error_contains_invalid_character')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_name_uniqueness_validation
|
||||||
|
User.current = @admin
|
||||||
|
|
||||||
|
# Duplicity among files names
|
||||||
|
@folder_link1.name = @revision1.name
|
||||||
|
assert @folder_link1.invalid?
|
||||||
|
assert_includes @folder_link1.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among invisible files is all right
|
||||||
|
@folder_link1.name = @revision3.name
|
||||||
|
assert_not @folder_link1.invalid?
|
||||||
|
|
||||||
|
# Duplicity among files titles
|
||||||
|
@folder_link1.name = @revision1.title
|
||||||
|
assert @folder_link1.invalid?
|
||||||
|
assert_includes @folder_link1.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Duplicity among folders
|
||||||
|
@folder_link1.name = @folder6.title
|
||||||
|
assert @folder_link1.invalid?
|
||||||
|
assert_includes @folder_link1.errors.full_messages, 'Name has already been taken'
|
||||||
|
|
||||||
|
# Name is all right
|
||||||
|
@folder_link1.name = 'xxx'
|
||||||
|
assert @folder_link1.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_external_url_length
|
def test_validate_external_url_length
|
||||||
@file_link2.target_type = 'DmsfUrl'
|
@file_link2.target_type = 'DmsfUrl'
|
||||||
@file_link2.external_url = "https://localhost/#{'a' * 256}"
|
@file_link2.external_url = "https://localhost/#{'a' * 256}"
|
||||||
assert_not @file_link2.save, "External URL link #{@file_link2.name} should have not been saved"
|
assert @file_link2.invalid?
|
||||||
assert_equal 1, @file_link2.errors.size
|
assert_includes @file_link2.errors.full_messages, 'URL is too long (maximum is 255 characters)'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_external_url_presence
|
def test_validate_external_url_presence
|
||||||
@file_link2.target_type = 'DmsfUrl'
|
@file_link2.target_type = 'DmsfUrl'
|
||||||
@file_link2.external_url = ''
|
@file_link2.external_url = ''
|
||||||
assert_not @file_link2.save, "External URL link #{@file_link2.name} should have not been saved"
|
assert @file_link2.invalid?
|
||||||
assert_equal 1, @file_link2.errors.size
|
assert_includes @file_link2.errors.full_messages, 'URL is invalid'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_external_url_invalid
|
def test_validate_external_url_invalid
|
||||||
@file_link2.target_type = 'DmsfUrl'
|
@file_link2.target_type = 'DmsfUrl'
|
||||||
@file_link2.external_url = 'htt ps://abc.xyz'
|
@file_link2.external_url = 'htt ps://abc.xyz'
|
||||||
assert_not @file_link2.save, "External URL link #{@file_link2.name} should have not been saved"
|
assert @file_link2.invalid?
|
||||||
assert_equal 1, @file_link2.errors.size
|
assert_includes @file_link2.errors.full_messages, 'URL is invalid'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_validate_external_url_valid
|
def test_validate_external_url_valid
|
||||||
@file_link2.target_type = 'DmsfUrl'
|
@file_link2.target_type = 'DmsfUrl'
|
||||||
@file_link2.external_url = 'https://www.google.com/search?q=寿司'
|
@file_link2.external_url = 'https://www.google.com/search?q=寿司'
|
||||||
assert @file_link2.save
|
assert @file_link2.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_belongs_to_project
|
def test_belongs_to_project
|
||||||
@ -186,7 +228,7 @@ class DmsfLinksTest < RedmineDmsf::Test::UnitTest
|
|||||||
def test_copy_to_author
|
def test_copy_to_author
|
||||||
assert_equal @admin.id, @file_link2.user_id
|
assert_equal @admin.id, @file_link2.user_id
|
||||||
User.current = @jsmith
|
User.current = @jsmith
|
||||||
l = @file_link2.copy_to(@project1, @folder1)
|
l = @file_link2.copy_to(@project1, @folder6)
|
||||||
assert l
|
assert l
|
||||||
assert_equal @jsmith.id, l.user_id, 'Author must be updated when copying'
|
assert_equal @jsmith.id, l.user_id, 'Author must be updated when copying'
|
||||||
end
|
end
|
||||||
|
|||||||
@ -37,10 +37,14 @@ class DmsfQueryTest < RedmineDmsf::Test::UnitTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_dmsf_count
|
def test_dmsf_count
|
||||||
n = DmsfFolder.visible.where(project_id: @project1.id).where("title LIKE '%test%'").all.size +
|
n = DmsfFolder.where(project_id: @project1.id).where("title LIKE '%test%'").all.size +
|
||||||
DmsfFile.visible.where(project_id: @project1.id).where("name LIKE '%test%'").all.size +
|
DmsfLink.where(project_id: @project1.id).where("name LIKE '%test%'").all.size
|
||||||
DmsfLink.visible.where(project_id: @project1.id).where("name LIKE '%test%'").all.size
|
|
||||||
assert_equal n - 1, @query401.dmsf_count # One folder is not visible due to the permissions
|
DmsfFile.where(project_id: @project1.id).find_each do |file|
|
||||||
|
n += 1 if file.name.include?('test')
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal n - 2, @query401.dmsf_count # Two file are not visible due to folder's permissions
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dmsf_nodes
|
def test_dmsf_nodes
|
||||||
|
|||||||
@ -350,7 +350,7 @@ class DmsfMacrosTest < RedmineDmsf::Test::HelperTest
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(@file7.last_revision.try(:tooltip)),
|
title: h(@file7.last_revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{@file7.last_revision.detect_content_type}:#{h(@file7.name)}:#{url}")
|
'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}")
|
||||||
assert text.include?(link), text
|
assert text.include?(link), text
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -379,7 +379,7 @@ class DmsfMacrosTest < RedmineDmsf::Test::HelperTest
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(@file7.last_revision.try(:tooltip)),
|
title: h(@file7.last_revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{@file7.last_revision.detect_content_type}:#{h(@file7.name)}:#{url}")
|
'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}")
|
||||||
assert text.include?(link), text
|
assert text.include?(link), text
|
||||||
# TODO: arguments src and with and height are swapped
|
# TODO: arguments src and with and height are swapped
|
||||||
# size = '640x480'
|
# size = '640x480'
|
||||||
@ -390,7 +390,7 @@ class DmsfMacrosTest < RedmineDmsf::Test::HelperTest
|
|||||||
# target: '_blank',
|
# target: '_blank',
|
||||||
# rel: 'noopener',
|
# rel: 'noopener',
|
||||||
# title: h(@file7.last_revision.try(:tooltip)),
|
# title: h(@file7.last_revision.try(:tooltip)),
|
||||||
# 'data-downloadurl' => "#{@file7.last_revision.detect_content_type}:#{h(@file7.name)}:#{url}")
|
# 'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}")
|
||||||
# assert text.include?(link), text
|
# assert text.include?(link), text
|
||||||
height = '480'
|
height = '480'
|
||||||
text = textilizable("{{dmsftn(#{@file7.id}, height=#{height})}}")
|
text = textilizable("{{dmsftn(#{@file7.id}, height=#{height})}}")
|
||||||
@ -410,7 +410,7 @@ class DmsfMacrosTest < RedmineDmsf::Test::HelperTest
|
|||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener',
|
rel: 'noopener',
|
||||||
title: h(@file7.last_revision.try(:tooltip)),
|
title: h(@file7.last_revision.try(:tooltip)),
|
||||||
'data-downloadurl' => "#{@file7.last_revision.detect_content_type}:#{h(@file7.name)}:#{url}")
|
'data-downloadurl' => "#{@file7.last_revision.content_type}:#{h(@file7.name)}:#{url}")
|
||||||
assert text.include?(link), text
|
assert text.include?(link), text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
|
|||||||
def test_dmsf_count
|
def test_dmsf_count
|
||||||
User.current = @jsmith
|
User.current = @jsmith
|
||||||
hash = @project1.dmsf_count
|
hash = @project1.dmsf_count
|
||||||
assert_equal 9, hash[:files]
|
assert_equal 10, hash[:files]
|
||||||
assert_equal 5, hash[:folders]
|
assert_equal 5, hash[:folders]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
|
|||||||
def test_copy_dmsf
|
def test_copy_dmsf
|
||||||
User.current = @jsmith
|
User.current = @jsmith
|
||||||
|
|
||||||
assert_equal 5, @project1.dmsf_files.visible.all.size
|
assert_equal 6, @project1.dmsf_files.visible.all.size
|
||||||
assert_equal 3, @project1.dmsf_folders.visible.all.size
|
assert_equal 3, @project1.dmsf_folders.visible.all.size
|
||||||
assert_equal 2, @project1.file_links.all.size
|
assert_equal 2, @project1.file_links.all.size
|
||||||
assert_equal 1, @project1.folder_links.all.size
|
assert_equal 1, @project1.folder_links.all.size
|
||||||
@ -84,7 +84,7 @@ class ProjectPatchTest < RedmineDmsf::Test::UnitTest
|
|||||||
|
|
||||||
@project5.copy_dmsf @project1
|
@project5.copy_dmsf @project1
|
||||||
|
|
||||||
assert_equal 6, @project5.dmsf_files.all.size
|
assert_equal 7, @project5.dmsf_files.all.size
|
||||||
assert_equal 4, @project5.dmsf_folders.all.size
|
assert_equal 4, @project5.dmsf_folders.all.size
|
||||||
assert_equal 2, @project5.file_links.all.size
|
assert_equal 2, @project5.file_links.all.size
|
||||||
assert_equal 1, @project5.folder_links.all.size
|
assert_equal 1, @project5.folder_links.all.size
|
||||||
|
|||||||
@ -56,10 +56,12 @@ module RedmineDmsf
|
|||||||
@file2 = DmsfFile.find 2
|
@file2 = DmsfFile.find 2
|
||||||
@file4 = DmsfFile.find 4
|
@file4 = DmsfFile.find 4
|
||||||
@file5 = DmsfFile.find 5
|
@file5 = DmsfFile.find 5
|
||||||
|
@file6 = DmsfFile.find 6
|
||||||
@file7 = DmsfFile.find 7
|
@file7 = DmsfFile.find 7
|
||||||
@file8 = DmsfFile.find 8
|
@file8 = DmsfFile.find 8
|
||||||
@file11 = DmsfFile.find 11
|
@file11 = DmsfFile.find 11
|
||||||
@file13 = DmsfFile.find 13
|
@file13 = DmsfFile.find 13
|
||||||
|
@file14 = DmsfFile.find 14
|
||||||
@folder_link1 = DmsfLink.find 1
|
@folder_link1 = DmsfLink.find 1
|
||||||
@file_link2 = DmsfLink.find 2
|
@file_link2 = DmsfLink.find 2
|
||||||
@file_link7 = DmsfLink.find 7
|
@file_link7 = DmsfLink.find 7
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user