Pass 1 of webdav (VERY ROUGH) - Functional on Get/Head (Web based listing) and also webdav listing and downloading of resources.
User based authentication and tracking of downloads, however security model not implemented yet.
This commit is contained in:
parent
fa4207dfce
commit
2e431568d6
@ -25,8 +25,8 @@ class DmsfFileRevision < ActiveRecord::Base
|
|||||||
belongs_to :deleted_by_user, :class_name => "User", :foreign_key => "deleted_by_user_id"
|
belongs_to :deleted_by_user, :class_name => "User", :foreign_key => "deleted_by_user_id"
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
|
|
||||||
acts_as_customizable
|
acts_as_customizable
|
||||||
|
|
||||||
acts_as_event :title => Proc.new {|o| "#{l(:label_dmsf_updated)}: #{o.file.dmsf_path_str}"},
|
acts_as_event :title => Proc.new {|o| "#{l(:label_dmsf_updated)}: #{o.file.dmsf_path_str}"},
|
||||||
:url => Proc.new {|o| {:controller => 'dmsf_files', :action => 'show', :id => o.file}},
|
:url => Proc.new {|o| {:controller => 'dmsf_files', :action => 'show', :id => o.file}},
|
||||||
:datetime => Proc.new {|o| o.updated_at },
|
:datetime => Proc.new {|o| o.updated_at },
|
||||||
@ -79,9 +79,9 @@ class DmsfFileRevision < ActiveRecord::Base
|
|||||||
["disk_filename = :filename", {:filename => self.disk_filename}])
|
["disk_filename = :filename", {:filename => self.disk_filename}])
|
||||||
File.delete(self.disk_file) if dependent.length <= 1 && File.exist?(self.disk_file)
|
File.delete(self.disk_file) if dependent.length <= 1 && File.exist?(self.disk_file)
|
||||||
DmsfFileRevisionAccess.find(:all, :conditions => ["dmsf_file_revision_id = ?", self.id]).each {|a| a.destroy}
|
DmsfFileRevisionAccess.find(:all, :conditions => ["dmsf_file_revision_id = ?", self.id]).each {|a| a.destroy}
|
||||||
CustomValue.find(:all, :conditions => "customized_id = " + self.id.to_s).each do |v|
|
CustomValue.find(:all, :conditions => "customized_id = " + self.id.to_s).each do |v|
|
||||||
v.destroy
|
v.destroy
|
||||||
end
|
end
|
||||||
self.destroy
|
self.destroy
|
||||||
else
|
else
|
||||||
self.deleted = true
|
self.deleted = true
|
||||||
@ -134,8 +134,8 @@ class DmsfFileRevision < ActiveRecord::Base
|
|||||||
new_revision.name = self.name
|
new_revision.name = self.name
|
||||||
new_revision.folder = self.folder
|
new_revision.folder = self.folder
|
||||||
|
|
||||||
new_revision.custom_values = self.custom_values.map(&:clone)
|
new_revision.custom_values = self.custom_values.map(&:clone)
|
||||||
|
|
||||||
return new_revision
|
return new_revision
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -209,20 +209,20 @@ class DmsfFileRevision < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
|
|
||||||
def available_custom_fields
|
|
||||||
search_project = nil
|
|
||||||
if self.project.present?
|
|
||||||
search_project = self.project
|
|
||||||
elsif self.project_id.present?
|
|
||||||
search_project = Project.find(self.project_id)
|
|
||||||
end
|
|
||||||
if search_project
|
|
||||||
search_project.all_dmsf_custom_fields
|
|
||||||
else
|
|
||||||
DmsfFileRevisionCustomField.all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
# Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
|
||||||
|
def available_custom_fields
|
||||||
|
search_project = nil
|
||||||
|
if self.project.present?
|
||||||
|
search_project = self.project
|
||||||
|
elsif self.project_id.present?
|
||||||
|
search_project = Project.find(self.project_id)
|
||||||
|
end
|
||||||
|
if search_project
|
||||||
|
search_project.all_dmsf_custom_fields
|
||||||
|
else
|
||||||
|
DmsfFileRevisionCustomField.all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
module RedmineDmsf
|
module RedmineDmsf
|
||||||
module Webdav
|
module Webdav
|
||||||
class BaseResource < DAV4Rack::Resource
|
class BaseResource < DAV4Rack::Resource
|
||||||
|
include Redmine::I18n
|
||||||
|
include ActionView::Helpers::NumberHelper
|
||||||
|
|
||||||
|
|
||||||
DIR_FILE = "<tr><td class=\"name\"><a href=\"%s\">%s</a></td><td class=\"size\">%s</td><td class=\"type\">%s</td><td class=\"mtime\">%s</td></tr>"
|
DIR_FILE = "<tr><td class=\"name\"><a href=\"%s\">%s</a></td><td class=\"size\">%s</td><td class=\"type\">%s</td><td class=\"mtime\">%s</td></tr>"
|
||||||
|
|
||||||
@ -24,7 +27,15 @@ module RedmineDmsf
|
|||||||
|
|
||||||
@response.body = ""
|
@response.body = ""
|
||||||
Confict unless collection?
|
Confict unless collection?
|
||||||
entities = children.map{|child| DIR_FILE % [child.public_path.html_safe, child.long_name || child.name, "-", child.special_type || child.content_type, child.last_modified]} * "\n"
|
entities = children.map{|child|
|
||||||
|
DIR_FILE % [
|
||||||
|
child.public_path,
|
||||||
|
child.long_name || child.name,
|
||||||
|
child.collection? ? '-' : number_to_human_size(child.content_length),
|
||||||
|
child.special_type || child.content_type,
|
||||||
|
child.last_modified
|
||||||
|
]
|
||||||
|
} * "\n"
|
||||||
@response.body << index_page % [ path.empty? ? "/" : path, path.empty? ? "/" : path , entities ]
|
@response.body << index_page % [ path.empty? ? "/" : path, path.empty? ? "/" : path , entities ]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -62,6 +73,12 @@ table { width:100%%; }
|
|||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
def basename
|
||||||
|
File.basename(path)
|
||||||
|
end
|
||||||
|
def dirname
|
||||||
|
File.dirname(path)
|
||||||
|
end
|
||||||
def Project
|
def Project
|
||||||
return @Project unless @Project.nil?
|
return @Project unless @Project.nil?
|
||||||
pinfo = @path.split('/').drop(1)
|
pinfo = @path.split('/').drop(1)
|
||||||
@ -72,6 +89,9 @@ table { width:100%%; }
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
def projectless_path
|
||||||
|
'/'+path.split('/').drop(2).join('/')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
132
lib/redmine_dmsf/webdav/dmsf_resource.rb
Normal file
132
lib/redmine_dmsf/webdav/dmsf_resource.rb
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
module RedmineDmsf
|
||||||
|
module Webdav
|
||||||
|
class DmsfResource < BaseResource
|
||||||
|
|
||||||
|
def children
|
||||||
|
NotFound unless exist? && folder?
|
||||||
|
return @children unless @children.nil?
|
||||||
|
@children = []
|
||||||
|
@_folderdata.subfolders.map do |p|
|
||||||
|
@children.push child(p.title, p)
|
||||||
|
end
|
||||||
|
@_folderdata.files.map do |p|
|
||||||
|
@children.push child(p.name, p)
|
||||||
|
end
|
||||||
|
@children
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def exist?
|
||||||
|
folder? || file?
|
||||||
|
end
|
||||||
|
|
||||||
|
def collection?
|
||||||
|
exist? && folder?
|
||||||
|
end
|
||||||
|
|
||||||
|
def folder?
|
||||||
|
return @_folder unless @_folder.nil?
|
||||||
|
@_folder = false
|
||||||
|
folders = DmsfFolder.find(:all, :conditions => ["project_id = :project_id", {:project_id => self.Project.id}], :order => "title ASC")
|
||||||
|
folders.delete_if {|x| x.title != basename}
|
||||||
|
return false unless folders.length > 0
|
||||||
|
if (folders.length > 1) then
|
||||||
|
folders.delete_if {|x| x.dmsf_path_str != projectless_path}
|
||||||
|
return false unless folders.length > 0
|
||||||
|
@_folder=true
|
||||||
|
@_folderdata = folders[0]
|
||||||
|
else
|
||||||
|
if ('/'+folders[0].dmsf_path_str == projectless_path) then
|
||||||
|
@_folder=true
|
||||||
|
@_folderdata = folders[0]
|
||||||
|
else
|
||||||
|
@_folder= false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@_folder
|
||||||
|
end
|
||||||
|
|
||||||
|
def file?
|
||||||
|
return @_file unless @_file.nil?
|
||||||
|
@_file = false
|
||||||
|
files = DmsfFile.find(:all, :conditions => ["project_id = :project_id AND name = :file_name AND deleted = :deleted", {:project_id => self.Project.id, :file_name => basename, :deleted => false}], :order => "name ASC")
|
||||||
|
files.delete_if {|x| File.dirname('/'+x.dmsf_path_str) != File.dirname(projectless_path)}
|
||||||
|
if files.length > 0
|
||||||
|
@_filedata = files[0]
|
||||||
|
@_file = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_type
|
||||||
|
if folder? then
|
||||||
|
"inode/directory"
|
||||||
|
elsif file?
|
||||||
|
@_filedata.last_revision.detect_content_type
|
||||||
|
else
|
||||||
|
NotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def creation_date
|
||||||
|
if folder?
|
||||||
|
@_folderdata.created_at
|
||||||
|
elsif file?
|
||||||
|
@_filedata.created_at
|
||||||
|
else
|
||||||
|
NotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def last_modified
|
||||||
|
if folder?
|
||||||
|
@_folderdata.updated_at
|
||||||
|
elsif file?
|
||||||
|
@_filedata.updated_at
|
||||||
|
else
|
||||||
|
NotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def etag
|
||||||
|
filesize = file? ? @_filedata.size : 4096;
|
||||||
|
fileino = file? ? File.stat(@_filedata.last_revision.disk_file).ino : 2;
|
||||||
|
sprintf('%x-%x-%x', fileino, filesize, last_modified.to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_length
|
||||||
|
file? ? @_filedata.size : 4096;
|
||||||
|
end
|
||||||
|
|
||||||
|
def special_type
|
||||||
|
l(:field_folder) if folder?
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(request, response)
|
||||||
|
raise NotFound unless exist?
|
||||||
|
if collection?
|
||||||
|
html_display
|
||||||
|
response['Content-Length'] = response.body.bytesize.to_s
|
||||||
|
else
|
||||||
|
response.body = download
|
||||||
|
end
|
||||||
|
OK
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
def download
|
||||||
|
raise NotFound unless file?
|
||||||
|
#log_activity("downloaded")
|
||||||
|
if @request.env['HTTP_RANGE'].nil?
|
||||||
|
access = DmsfFileRevisionAccess.new(:user_id => User.current.id, :dmsf_file_revision_id => @_filedata.last_revision.id,
|
||||||
|
:action => DmsfFileRevisionAccess::DownloadAction)
|
||||||
|
access.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
Download.new(@_filedata.last_revision.disk_file)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
32
lib/redmine_dmsf/webdav/download.rb
Normal file
32
lib/redmine_dmsf/webdav/download.rb
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
require 'time'
|
||||||
|
require 'rack/utils'
|
||||||
|
require 'rack/mime'
|
||||||
|
|
||||||
|
module RedmineDmsf
|
||||||
|
module Webdav
|
||||||
|
class Download < Rack::File
|
||||||
|
def initialize(root, cache_control = nil)
|
||||||
|
@path = root
|
||||||
|
@cache_control = cache_control
|
||||||
|
end
|
||||||
|
|
||||||
|
def _call(env)
|
||||||
|
unless ALLOWED_VERBS.include? env["REQUEST_METHOD"]
|
||||||
|
return fail(405, "Method Not Allowed")
|
||||||
|
end
|
||||||
|
|
||||||
|
available = begin
|
||||||
|
F.file?(@path) && F.readable?(@path)
|
||||||
|
rescue SystemCallError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
if available
|
||||||
|
serving(env)
|
||||||
|
else
|
||||||
|
raise NotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -9,21 +9,18 @@ module RedmineDmsf
|
|||||||
def children
|
def children
|
||||||
#caching for repeat usage
|
#caching for repeat usage
|
||||||
return @children unless @children.nil?
|
return @children unless @children.nil?
|
||||||
|
@children = []
|
||||||
DmsfFolder.project_root_folders(self.Project).map do |p|
|
DmsfFolder.project_root_folders(self.Project).map do |p|
|
||||||
child p.title, p
|
@children.push child(p.title, p)
|
||||||
end
|
end
|
||||||
DmsfFile.project_root_files(self.Project).map do |p|
|
DmsfFile.project_root_files(self.Project).map do |p|
|
||||||
child p.display_name, p
|
@children.push child(p.name, p)
|
||||||
end
|
end
|
||||||
end
|
@children
|
||||||
|
|
||||||
|
|
||||||
def name
|
|
||||||
self.Project.name unless self.Project.nil?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def exist?
|
def exist?
|
||||||
!self.Project.nil?
|
!(self.Project.nil? || User.current.anonymous?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def collection?
|
def collection?
|
||||||
@ -55,7 +52,7 @@ module RedmineDmsf
|
|||||||
end
|
end
|
||||||
|
|
||||||
def special_type
|
def special_type
|
||||||
"Project"
|
l(:field_project)
|
||||||
end
|
end
|
||||||
|
|
||||||
def content_length
|
def content_length
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user