Add support for the root directory

This commit is contained in:
galfert 2012-10-01 03:02:47 +02:00
parent d4d02e3e77
commit a21bdab0fa
4 changed files with 129 additions and 28 deletions

View File

@ -68,8 +68,9 @@ module RemoteStorage
else else
object.raw_data = data object.raw_data = data
end end
directory_index = category == "" ? "/" : category
object.indexes.merge!({:user_id_bin => [user], object.indexes.merge!({:user_id_bin => [user],
:directory_bin => [category]}) :directory_bin => [directory_index]})
object.store object.store
create_missing_directory_objects(user, category) create_missing_directory_objects(user, category)
@ -131,6 +132,7 @@ module RemoteStorage
end end
def directory_entries(user, directory) def directory_entries(user, directory)
directory = "/" if directory == ""
map_query = <<-EOH map_query = <<-EOH
function(v){ function(v){
keys = v.key.split(':'); keys = v.key.split(':');
@ -150,6 +152,7 @@ module RemoteStorage
end end
def sub_directories(user, directory) def sub_directories(user, directory)
directory = "/" if directory == ""
map_query = <<-EOH map_query = <<-EOH
function(v){ function(v){
keys = v.key.split(':'); keys = v.key.split(':');
@ -178,11 +181,17 @@ module RemoteStorage
end end
parent_directories.pop parent_directories.pop
end end
unless directory_bucket.exist?("#{user}:")
update_directory_object(user, "")
end
end end
def update_directory_object(user, category) def update_directory_object(user, category)
if category.match /\// if category.match /\//
parent_directory = category[0..category.rindex("/")-1] parent_directory = category[0..category.rindex("/")-1]
elsif category != ""
parent_directory = "/"
end end
directory = directory_bucket.new("#{user}:#{category}") directory = directory_bucket.new("#{user}:#{category}")
directory.raw_data = "" directory.raw_data = ""

View File

@ -31,50 +31,58 @@ class LiquorCabinet < Sinatra::Base
disable :protection disable :protection
end end
["/:user/*/:key", "/:user/*/"].each do |path| ["/:user/*/:key", "/:user/:key", "/:user/*/", "/:user/"].each do |path|
before path do before path do
headers 'Access-Control-Allow-Origin' => '*', headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, PUT, DELETE', 'Access-Control-Allow-Methods' => 'GET, PUT, DELETE',
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, Origin' 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, Origin'
headers['Access-Control-Allow-Origin'] = env["HTTP_ORIGIN"] if env["HTTP_ORIGIN"] headers['Access-Control-Allow-Origin'] = env["HTTP_ORIGIN"] if env["HTTP_ORIGIN"]
@user, @directory, @key = params[:user], params[:splat].first, params[:key] @user, @key = params[:user], params[:key]
@directory = params[:splat] && params[:splat].first || ""
token = env["HTTP_AUTHORIZATION"] ? env["HTTP_AUTHORIZATION"].split(" ")[1] : "" token = env["HTTP_AUTHORIZATION"] ? env["HTTP_AUTHORIZATION"].split(" ")[1] : ""
authorize_request(@user, @directory, token) unless request.options? authorize_request(@user, @directory, token) unless request.options?
end end
end end
get "/:user/*/:key" do ["/:user/*/:key", "/:user/:key"].each do |path|
get_data(@user, @directory, @key) get path do
end get_data(@user, @directory, @key)
get "/:user/*/" do
get_directory_listing(@user, @directory)
end
put "/:user/*/:key" do
data = request.body.read
if env['CONTENT_TYPE'] == "application/x-www-form-urlencoded"
content_type = "text/plain; charset=utf-8"
else
content_type = env['CONTENT_TYPE']
end end
put_data(@user, @directory, @key, data, content_type)
end end
delete "/:user/*/:key" do ["/:user/*/", "/:user/"].each do |path|
delete_data(@user, @directory, @key) get path do
get_directory_listing(@user, @directory)
end
end end
options "/:user/*/:key" do ["/:user/*/:key", "/:user/:key"].each do |path|
halt 200 put path do
data = request.body.read
if env['CONTENT_TYPE'] == "application/x-www-form-urlencoded"
content_type = "text/plain; charset=utf-8"
else
content_type = env['CONTENT_TYPE']
end
put_data(@user, @directory, @key, data, content_type)
end
end end
options "/:user/*/" do ["/:user/*/:key", "/:user/:key"].each do |path|
halt 200 delete path do
delete_data(@user, @directory, @key)
end
end
["/:user/*/:key", "/:user/:key", "/:user/*/", "/:user/"].each do |path|
options path do
halt 200
end
end end
private private

View File

@ -8,7 +8,7 @@ describe "Directories" do
purge_all_buckets purge_all_buckets
auth = auth_bucket.new("jimmy:123") auth = auth_bucket.new("jimmy:123")
auth.data = ["documents:r", "tasks:rw"] auth.data = [":r", "documents:r", "tasks:rw"]
auth.store auth.store
header "Authorization", "Bearer 123" header "Authorization", "Bearer 123"
@ -107,7 +107,7 @@ describe "Directories" do
end end
end end
describe "for an empty or absent directory" do context "for an empty or absent directory" do
it "returns an empty listing" do it "returns an empty listing" do
get "/jimmy/documents/notfound/" get "/jimmy/documents/notfound/"
@ -115,6 +115,30 @@ describe "Directories" do
last_response.body.must_equal "{}" last_response.body.must_equal "{}"
end end
end end
context "for the root directory" do
before do
auth = auth_bucket.new("jimmy:123")
auth.data = [":rw"]
auth.store
put "/jimmy/root-1", "Put my root down"
put "/jimmy/root-2", "Back to the roots"
end
it "lists the containing objects and direct sub-directories" do
get "/jimmy/"
last_response.status.must_equal 200
content = JSON.parse(last_response.body)
content.must_include "root-1"
content.must_include "root-2"
content.must_include "tasks/"
content["tasks/"].to_s.must_match /\d+/
content["tasks/"].to_s.length.must_be :>=, 10
end
end
end end
describe "directory object" do describe "directory object" do
@ -133,6 +157,18 @@ describe "Directories" do
object = directory_bucket.get("jimmy:tasks/home") object = directory_bucket.get("jimmy:tasks/home")
object.indexes["directory_bin"].must_include "tasks" object.indexes["directory_bin"].must_include "tasks"
end end
it "creates directory objects for the parent directories" do
put "/jimmy/tasks/home/trash", "take out the trash"
object = directory_bucket.get("jimmy:tasks")
object.indexes["directory_bin"].must_include "/"
object.last_modified.wont_be_nil
object = directory_bucket.get("jimmy:")
object.indexes["directory_bin"].must_be_empty
object.last_modified.wont_be_nil
end
end end
context "existing directory object" do context "existing directory object" do
@ -177,6 +213,18 @@ describe "Directories" do
last_response.headers["Access-Control-Allow-Headers"].must_equal "Authorization, Content-Type, Origin" last_response.headers["Access-Control-Allow-Headers"].must_equal "Authorization, Content-Type, Origin"
end end
end end
context "root directory" do
it "has CORS headers set" do
options "/jimmy/"
last_response.status.must_equal 200
last_response.headers["Access-Control-Allow-Origin"].must_equal "*"
last_response.headers["Access-Control-Allow-Methods"].must_equal "GET, PUT, DELETE"
last_response.headers["Access-Control-Allow-Headers"].must_equal "Authorization, Content-Type, Origin"
end
end
end end
describe "DELETE file" do describe "DELETE file" do

View File

@ -245,6 +245,42 @@ describe "Permissions" do
data_bucket.get("jimmy:documents/very/interesting:text") data_bucket.get("jimmy:documents/very/interesting:text")
}.must_raise Riak::HTTPFailedRequest }.must_raise Riak::HTTPFailedRequest
end end
context "root directory" do
before do
object = data_bucket.new("jimmy::root")
object.content_type = "text/plain"
object.data = "Back to the roots"
object.store
end
it "allows GET requests" do
get "/jimmy/root"
last_response.status.must_equal 200
last_response.body.must_equal "Back to the roots"
end
it "allows PUT requests" do
put "/jimmy/1", "Gonna kick it root down"
# File.open('response.html', 'w') do |f|
# f.write last_response.body
# end
last_response.status.must_equal 200
data_bucket.get("jimmy::1").data.must_equal "Gonna kick it root down"
end
it "allows DELETE requests" do
delete "/jimmy/root"
last_response.status.must_equal 204
lambda {
data_bucket.get("jimmy::root")
}.must_raise Riak::HTTPFailedRequest
end
end
end end
describe "read all" do describe "read all" do