dav4rack 0.2.11 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,341 @@
1
+ # coding: utf-8
2
+ require 'mime/types'
3
+
4
+ module DAV4Rack
5
+
6
+ class MongoResource < DAV4Rack::Resource
7
+
8
+ # @@logger = Rails.logger
9
+
10
+ def initialize(public_path, path, request, response, options)
11
+ # 'ASCII-8BIT'で渡される場合があるので'UTF-8'を指定しておく
12
+ _force_encoding!(public_path)
13
+ _force_encoding!(path)
14
+ super(public_path, path, request, response, options)
15
+ @filesystem = Mongo::GridFileSystem.new(Mongoid.database)
16
+ @collection = Mongoid.database.collection('fs.files')
17
+ if options[:bson]
18
+ @bson = options[:bson]
19
+ elsif path.length <= 1
20
+ # ルートの場合 (''の場合と'/'の場合がある)
21
+ @bson = {'filename' => root + '/'}
22
+ else
23
+ # ファイルかディレクトリが、パラメータだけでは判断できない。ので \/? が必要。
24
+ # だから、ディレクトリと同名のファイルは、作成できない。
25
+ @bson = @collection.find_one({:filename => /^#{Regexp.escape(file_path)}\/?$/}) rescue nil
26
+ end
27
+ end
28
+
29
+ def child(bson)
30
+ path = remove(bson['filename'], root)
31
+ public_path = @options[:root_uri_path] + path
32
+ @options[:bson] = bson
33
+ self.class.new(public_path, path, @request, @response, @options)
34
+ end
35
+
36
+ # If this is a collection, return the child resources.
37
+ def children
38
+ # Dir[file_path + '/*'].map do |path|
39
+ # child File.basename(path)
40
+ # end
41
+ @collection.find({:filename => /^#{Regexp.escape(@bson['filename'])}[^\/]+\/?$/}).map do |bson|
42
+ child bson
43
+ end
44
+ end
45
+
46
+ # Is this resource a collection?
47
+ def collection?
48
+ # File.directory?(file_path)
49
+ @bson && _collection?(@bson['filename'])
50
+ end
51
+
52
+ # Does this recource exist?
53
+ def exist?
54
+ # File.exist?(file_path)
55
+ @bson
56
+ end
57
+
58
+ # Return the creation time.
59
+ def creation_date
60
+ # stat.ctime
61
+ @bson['uploadDate'] || Date.new
62
+ end
63
+
64
+ # Return the time of last modification.
65
+ def last_modified
66
+ # stat.mtime
67
+ @bson['uploadDate'] || Date.new
68
+ end
69
+
70
+ # Set the time of last modification.
71
+ def last_modified=(time)
72
+ # File.utime(Time.now, time, file_path)
73
+ end
74
+
75
+ # Return an Etag, an unique hash value for this resource.
76
+ def etag
77
+ # sprintf('%x-%x-%x', stat.ino, stat.size, stat.mtime.to_i)
78
+ @bson['_id'].to_s
79
+ end
80
+
81
+ # Return the mime type of this resource.
82
+ def content_type
83
+ # if stat.directory?
84
+ # "text/html"
85
+ # else
86
+ # mime_type(file_path, DefaultMimeTypes)
87
+ # end
88
+ @bson['contentType'] || "text/html"
89
+ end
90
+
91
+ # Return the size in bytes for this resource.
92
+ def content_length
93
+ # stat.size
94
+ @bson['length'] || 0
95
+ end
96
+
97
+ # HTTP GET request.
98
+ #
99
+ # Write the content of the resource to the response.body.
100
+ def get(request, response)
101
+ raise NotFound unless exist?
102
+ # if stat.directory?
103
+ # response.body = ""
104
+ # Rack::Directory.new(root).call(request.env)[2].each do |line|
105
+ # response.body << line
106
+ # end
107
+ # response['Content-Length'] = response.body.size.to_s
108
+ # else
109
+ # file = Rack::File.new(root)
110
+ # response.body = file
111
+ # end
112
+ if collection?
113
+ response.body = "<html>"
114
+ response.body << "<h2>" + file_path.html_safe + "</h2>"
115
+ children.each do |child|
116
+ name = child.file_path.html_safe
117
+ path = child.public_path
118
+ response.body << "<a href='" + path + "'>" + name + "</a>"
119
+ response.body << "</br>"
120
+ end
121
+ response.body << "</html>"
122
+ response['Content-Length'] = response.body.size.to_s
123
+ response['Content-Type'] = 'text/html'
124
+ else
125
+ @filesystem.open(file_path, 'r') do |f|
126
+ response.body = f
127
+ response['Content-Type'] = @bson['contentType']
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ # HTTP PUT request.
134
+ #
135
+ # Save the content of the request.body.
136
+ def put(request, response)
137
+ write(request.body)
138
+ Created
139
+ end
140
+
141
+ # HTTP POST request.
142
+ #
143
+ # Usually forbidden.
144
+ def post(request, response)
145
+ raise HTTPStatus::Forbidden
146
+ end
147
+
148
+ # HTTP DELETE request.
149
+ #
150
+ # Delete this resource.
151
+ def delete
152
+ # if stat.directory?
153
+ # FileUtils.rm_rf(file_path)
154
+ # else
155
+ # File.unlink(file_path)
156
+ # end
157
+ if collection?
158
+ @collection.find({:filename => /^#{Regexp.escape(@bson['filename'])}/}).each do |bson|
159
+ @collection.remove(bson)
160
+ end
161
+ else
162
+ @collection.remove(@bson)
163
+ end
164
+ NoContent
165
+ end
166
+
167
+ # HTTP COPY request.
168
+ #
169
+ # Copy this resource to given destination resource.
170
+ def copy(dest, overwrite = false)
171
+ # if(dest.path == path)
172
+ # Conflict
173
+ # elsif(stat.directory?)
174
+ # dest.make_collection
175
+ # FileUtils.cp_r("#{file_path}/.", "#{dest.send(:file_path)}/")
176
+ # OK
177
+ # else
178
+ # exists = File.exists?(file_path)
179
+ # if(exists && !overwrite)
180
+ # PreconditionFailed
181
+ # else
182
+ # open(file_path, "rb") do |file|
183
+ # dest.write(file)
184
+ # end
185
+ # exists ? NoContent : Created
186
+ # end
187
+ # end
188
+
189
+ # ディレクトリなら末尾に「/」をつける。
190
+ # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
191
+ # CarotDAV : 「/」が付いていない
192
+ # TeamFile : 「/」が付いている
193
+ dest.collection! if collection?
194
+
195
+ src = @bson['filename']
196
+ dst = dest.file_path
197
+ exists = nil
198
+
199
+ @collection.find({:filename => /^#{Regexp.escape(src)}/}).each do |bson|
200
+ src_name = bson['filename']
201
+ dst_name = dst + src_name.slice(src.length, src_name.length)
202
+
203
+ exists = @collection.find_one({:filename => dst_name}) rescue nil
204
+
205
+ return PreconditionFailed if (exists && !overwrite && !collection?)
206
+
207
+ @filesystem.open(src_name, "r") do |src|
208
+ @filesystem.open(dst_name, "w") do |dst|
209
+ dst.write(src) if src.file_length > 0
210
+ end
211
+ end
212
+
213
+ @collection.remove(exists) if exists
214
+ end
215
+
216
+ collection? ? Created : (exists ? NoContent : Created)
217
+ end
218
+
219
+ # HTTP MOVE request.
220
+ #
221
+ # Move this resource to given destination resource.
222
+ def move(dest, overwrite = false)
223
+
224
+ # ディレクトリなら末尾に「/」をつける。
225
+ # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
226
+ # CarotDAV : 「/」が付いていない
227
+ # TeamFile : 「/」が付いている
228
+ dest.collection! if collection?
229
+
230
+ src = @bson['filename']
231
+ dst = dest.file_path
232
+ exists = nil
233
+
234
+ @collection.find({:filename => /^#{Regexp.escape(src)}/}).each do |bson|
235
+ src_name = bson['filename']
236
+ dst_name = dst + src_name.slice(src.length, src_name.length)
237
+
238
+ exists = @collection.find_one({:filename => dst_name}) rescue nil
239
+
240
+ # http://mongoid.org/docs/persistence/atomic.html
241
+ # http://rubydoc.info/github/mongoid/mongoid/master/Mongoid/Collection#update-instance_method
242
+ @collection.update({'_id' => bson['_id']}, {'$set' => {'filename' => dst_name}}, :safe => true)
243
+
244
+ @collection.remove(exists) if exists
245
+ end
246
+
247
+ collection? ? Created : (exists ? NoContent : Created)
248
+ end
249
+
250
+ # HTTP MKCOL request.
251
+ #
252
+ # Create this resource as collection.
253
+ def make_collection
254
+ # Dir.mkdir(file_path)
255
+ # Created
256
+
257
+ # ディレクトリなら末尾に「/」をつける。
258
+ # (dstにもともと「/」が付いているかどうか、クライアントに依存している)
259
+ # CarotDAV : 「/」が付いていない
260
+ # TeamFile : 「/」が付いている
261
+ collection!
262
+
263
+ bson = @collection.find_one({:filename => file_path}) rescue nil
264
+
265
+ # 0バイトのファイルを作成しディレクトリの代わりとする
266
+ @filesystem.open(file_path, "w") { |f| } if !bson
267
+
268
+ # @@logger.error('make_collection : ' + file_path)
269
+
270
+ Created
271
+ end
272
+
273
+ # Write to this resource from given IO.
274
+ def write(io)
275
+ # tempfile = "#{file_path}.#{Process.pid}.#{object_id}"
276
+ # open(tempfile, "wb") do |file|
277
+ # while part = io.read(8192)
278
+ # file << part
279
+ # end
280
+ # end
281
+ # File.rename(tempfile, file_path)
282
+ # ensure
283
+ # File.unlink(tempfile) rescue nil
284
+
285
+ # 同名のファイルができないように
286
+ bson = @collection.find_one({:filename => file_path}) rescue nil
287
+
288
+ @filesystem.open(file_path, "w", :content_type => _content_type(file_path)) { |f| f.write(io) }
289
+
290
+ # 同名のファイルができないように
291
+ @collection.remove(bson) if bson
292
+
293
+ end
294
+
295
+ protected
296
+
297
+ def file_path
298
+ root + path
299
+ end
300
+
301
+ # ファイル名の末尾に「/」を付加してディレクトリ(コレクション)とする
302
+ def collection!
303
+ path << '/' if !_collection?(path)
304
+ end
305
+
306
+ private
307
+
308
+ def _content_type(filename)
309
+ MIME::Types.type_for(filename).first.to_s || 'text/html'
310
+ end
311
+
312
+ def authenticate(user, pass)
313
+ if(options[:username])
314
+ options[:username] == user && options[:password] == pass
315
+ else
316
+ true
317
+ end
318
+ end
319
+
320
+ # path1の先頭からpath2を取り除く
321
+ def remove(path1, path2)
322
+ path1.slice(path2.length, path1.length)
323
+ end
324
+
325
+ def root
326
+ @options[:root]
327
+ end
328
+
329
+ # ファイル名の末尾が「/」のファイルをディレクトリ(コレクション)とする
330
+ def _collection?(path)
331
+ path && path[-1].chr == '/'
332
+ end
333
+
334
+ # 'ASCII-8BIT'で渡される場合があるので'UTF-8'を指定しておく
335
+ def _force_encoding!(str)
336
+ str.force_encoding('UTF-8')
337
+ end
338
+
339
+ end
340
+
341
+ end
@@ -0,0 +1,40 @@
1
+ require 'ostruct'
2
+
3
+ module DAV4Rack
4
+
5
+ # Simple wrapper for formatted elements
6
+ class DAVElement < OpenStruct
7
+ def [](key)
8
+ self.send(key)
9
+ end
10
+ end
11
+
12
+ module Utils
13
+ def to_element_hash(element)
14
+ ns = element.namespace
15
+ DAVElement.new(
16
+ :namespace => ns,
17
+ :name => element.name,
18
+ :ns_href => (ns.href if ns),
19
+ :children => element.children.collect{|e|
20
+ to_element_hash(e) if e.element?
21
+ }.compact,
22
+ :attributes => attributes_hash(element)
23
+ )
24
+ end
25
+
26
+ def to_element_key(element)
27
+ ns = element.namespace
28
+ "#{ns.href if ns}!!#{element.name}"
29
+ end
30
+
31
+ private
32
+ def attributes_hash(node)
33
+ node.attributes.inject({}) do |ret, (key,attr)|
34
+ ret[attr.name] = attr.value
35
+ ret
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -13,5 +13,5 @@ module DAV4Rack
13
13
  end
14
14
  end
15
15
 
16
- VERSION = Version.new('0.2.11')
16
+ VERSION = Version.new('0.3.0')
17
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dav4rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-06 00:00:00.000000000 Z
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &15276900 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 1.4.2
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *15276900
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.2
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: uuidtools
27
- requirement: &15293080 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: 2.1.1
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *15293080
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.1.1
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rack
38
- requirement: &15292420 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ! '>='
@@ -43,7 +53,12 @@ dependencies:
43
53
  version: 1.1.0
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *15292420
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.0
47
62
  description: WebDAV handler for Rack
48
63
  email: chrisroberts.code@gmail.com
49
64
  executables:
@@ -52,26 +67,28 @@ extensions: []
52
67
  extra_rdoc_files:
53
68
  - README.rdoc
54
69
  files:
55
- - .gitignore
56
- - LICENSE
57
70
  - dav4rack.gemspec
71
+ - README.rdoc
72
+ - CHANGELOG.rdoc
73
+ - LICENSE
74
+ - bin/dav4rack
58
75
  - lib/dav4rack.rb
59
- - lib/dav4rack/file_resource.rb
60
- - lib/dav4rack/handler.rb
61
- - lib/dav4rack/controller.rb
76
+ - lib/dav4rack/lock_store.rb
77
+ - lib/dav4rack/logger.rb
62
78
  - lib/dav4rack/http_status.rb
79
+ - lib/dav4rack/version.rb
80
+ - lib/dav4rack/remote_file.rb
81
+ - lib/dav4rack/controller.rb
63
82
  - lib/dav4rack/resource.rb
64
- - lib/dav4rack/interceptor.rb
83
+ - lib/dav4rack/lock.rb
65
84
  - lib/dav4rack/interceptor_resource.rb
66
- - lib/dav4rack/remote_file.rb
85
+ - lib/dav4rack/interceptor.rb
67
86
  - lib/dav4rack/file.rb
68
- - lib/dav4rack/lock.rb
69
- - lib/dav4rack/lock_store.rb
70
- - lib/dav4rack/logger.rb
71
- - lib/dav4rack/version.rb
72
- - bin/dav4rack
73
- - spec/handler_spec.rb
74
- - README.rdoc
87
+ - lib/dav4rack/file_resource_lock.rb
88
+ - lib/dav4rack/utils.rb
89
+ - lib/dav4rack/resources/mongo_resource.rb
90
+ - lib/dav4rack/resources/file_resource.rb
91
+ - lib/dav4rack/handler.rb
75
92
  homepage: http://github.com/chrisroberts/dav4rack
76
93
  licenses: []
77
94
  post_install_message:
@@ -92,9 +109,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
109
  version: '0'
93
110
  requirements: []
94
111
  rubyforge_project:
95
- rubygems_version: 1.8.17
112
+ rubygems_version: 1.8.24
96
113
  signing_key:
97
114
  specification_version: 3
98
115
  summary: WebDAV handler for Rack
99
116
  test_files: []
100
- has_rdoc: true