Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
lucas.parsy
jio
Commits
f0045483
Commit
f0045483
authored
Aug 21, 2013
by
Tristan Cavelier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Some files removed temporarily
parent
3356688e
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
0 additions
and
3179 deletions
+0
-3179
src/jio.storage/conflictmanagerstorage.js
src/jio.storage/conflictmanagerstorage.js
+0
-1085
src/jio.storage/davstorage.js
src/jio.storage/davstorage.js
+0
-943
src/jio.storage/ramstorage.js
src/jio.storage/ramstorage.js
+0
-446
test/jio.storage/davstorage.tests.js
test/jio.storage/davstorage.tests.js
+0
-705
No files found.
src/jio.storage/conflictmanagerstorage.js
deleted
100644 → 0
View file @
3356688e
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, hex_sha256: true, setTimeout: true */
jIO
.
addStorageType
(
'
conflictmanager
'
,
function
(
spec
,
my
)
{
var
that
,
priv
,
storage_exists
,
local_namespace
,
empty_fun
,
super_serialized
;
spec
=
spec
||
{};
that
=
my
.
basicStorage
(
spec
,
my
);
priv
=
{};
storage_exists
=
(
spec
.
storage
?
true
:
false
);
priv
.
sub_storage_spec
=
spec
.
storage
||
{
type
:
'
base
'
};
priv
.
sub_storage_string
=
JSON
.
stringify
(
priv
.
sub_storage_spec
);
local_namespace
=
'
jio/conflictmanager/
'
+
priv
.
sub_storage_string
+
'
/
'
;
empty_fun
=
function
()
{};
super_serialized
=
that
.
serialized
;
that
.
serialized
=
function
()
{
var
o
=
super_serialized
();
o
.
storage
=
priv
.
sub_storage_spec
;
return
o
;
};
that
.
validateState
=
function
()
{
if
(
storage_exists
)
{
return
''
;
}
return
'
Need at least one parameter: "storage".
'
;
};
priv
.
getDistantMetadata
=
function
(
command
,
path
,
success
,
error
)
{
var
cloned_option
=
command
.
cloneOption
();
cloned_option
.
metadata_only
=
false
;
that
.
addJob
(
'
get
'
,
priv
.
sub_storage_spec
,
path
,
cloned_option
,
success
,
error
);
};
priv
.
saveMetadataToDistant
=
function
(
command
,
path
,
content
,
success
,
error
)
{
that
.
addJob
(
'
put
'
,
priv
.
sub_storage_spec
,
{
_id
:
path
,
content
:
JSON
.
stringify
(
content
)
},
command
.
cloneOption
(),
success
,
error
);
};
priv
.
saveNewRevision
=
function
(
command
,
path
,
content
,
success
,
error
)
{
that
.
addJob
(
'
post
'
,
priv
.
sub_storage_spec
,
{
_id
:
path
,
content
:
content
},
command
.
cloneOption
(),
success
,
error
);
};
priv
.
loadRevision
=
function
(
command
,
path
,
success
,
error
)
{
that
.
addJob
(
'
get
'
,
priv
.
sub_storage_spec
,
path
,
command
.
cloneOption
(),
success
,
error
);
};
priv
.
deleteAFile
=
function
(
command
,
path
,
success
,
error
)
{
that
.
addJob
(
'
remove
'
,
priv
.
sub_storage_spec
,
{
_id
:
path
},
command
.
cloneOption
(),
success
,
error
);
};
priv
.
chooseARevision
=
function
(
metadata
)
{
var
tmp_last_modified
=
0
,
ret_rev
=
''
,
rev
;
for
(
rev
in
metadata
)
{
if
(
metadata
.
hasOwnProperty
(
rev
))
{
if
(
tmp_last_modified
<
metadata
[
rev
].
_last_modified
)
{
tmp_last_modified
=
metadata
[
rev
].
_last_modified
;
ret_rev
=
rev
;
}
}
}
return
ret_rev
;
};
priv
.
_revs
=
function
(
metadata
,
revision
)
{
if
(
!
(
metadata
&&
revision
))
{
return
null
;
}
if
(
metadata
[
revision
])
{
return
{
start
:
metadata
[
revision
].
_revisions
.
length
,
ids
:
metadata
[
revision
].
_revisions
};
}
return
null
;
};
priv
.
_revs_info
=
function
(
metadata
)
{
if
(
!
metadata
)
{
return
null
;
}
var
k
,
l
=
[];
for
(
k
in
metadata
)
{
if
(
metadata
.
hasOwnProperty
(
k
))
{
l
.
push
({
rev
:
k
,
status
:
(
metadata
[
k
]
?
(
metadata
[
k
].
_deleted
?
'
deleted
'
:
'
available
'
)
:
'
missing
'
)
});
}
}
return
l
;
};
priv
.
solveConflict
=
function
(
doc
,
option
,
param
)
{
var
o
=
{},
am
=
priv
.
newAsyncModule
(),
command
=
param
.
command
,
metadata_file_path
=
param
.
docid
+
'
.metadata
'
,
current_revision
=
''
,
current_revision_file_path
=
''
,
metadata_file_content
=
null
,
on_conflict
=
false
,
conflict_object
=
{
total_rows
:
0
,
rows
:
[]
},
on_remove
=
param
.
_deleted
,
previous_revision
=
param
.
previous_revision
,
previous_revision_content_object
=
null
,
now
=
new
Date
(),
failerror
;
o
.
getDistantMetadata
=
function
()
{
priv
.
getDistantMetadata
(
command
,
metadata_file_path
,
function
(
result
)
{
var
previous_revision_number
=
parseInt
(
previous_revision
.
split
(
'
-
'
)[
0
],
10
);
metadata_file_content
=
JSON
.
parse
(
result
.
content
);
// set current revision
// jslint: removed '' in hex_sha256(''...
current_revision
=
(
previous_revision_number
+
1
)
+
'
-
'
+
hex_sha256
(
doc
.
content
+
previous_revision
+
JSON
.
stringify
(
metadata_file_content
));
current_revision_file_path
=
param
.
docid
+
'
.
'
+
current_revision
;
previous_revision_content_object
=
metadata_file_content
[
previous_revision
]
||
{};
if
(
!
on_remove
)
{
am
.
wait
(
o
,
'
saveMetadataOnDistant
'
,
1
);
am
.
call
(
o
,
'
saveNewRevision
'
);
}
am
.
call
(
o
,
'
previousUpdateMetadata
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
saveNewRevision
=
function
()
{
priv
.
saveNewRevision
(
command
,
current_revision_file_path
,
doc
.
content
,
function
()
{
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
previousUpdateMetadata
=
function
()
{
var
i
;
for
(
i
=
0
;
i
<
param
.
key
.
length
;
i
+=
1
)
{
delete
metadata_file_content
[
param
.
key
[
i
]];
}
am
.
call
(
o
,
'
checkForConflicts
'
);
};
o
.
checkForConflicts
=
function
()
{
var
rev
;
for
(
rev
in
metadata_file_content
)
{
if
(
metadata_file_content
.
hasOwnProperty
(
rev
))
{
on_conflict
=
true
;
failerror
=
{
status
:
409
,
error
:
'
conflict
'
,
statusText
:
'
Conflict
'
,
reason
:
'
document update conflict
'
,
message
:
'
There is one or more conflicts
'
};
break
;
}
}
am
.
call
(
o
,
'
updateMetadata
'
);
};
o
.
updateMetadata
=
function
()
{
var
revision_history
,
id
=
''
;
id
=
current_revision
.
split
(
'
-
'
);
id
.
shift
();
id
=
id
.
join
(
'
-
'
);
revision_history
=
previous_revision_content_object
.
_revisions
;
revision_history
.
unshift
(
id
);
metadata_file_content
[
current_revision
]
=
{
_creation_date
:
previous_revision_content_object
.
_creation_date
||
now
.
getTime
(),
_last_modified
:
now
.
getTime
(),
_revisions
:
revision_history
,
_conflict
:
on_conflict
,
_deleted
:
on_remove
};
if
(
on_conflict
)
{
conflict_object
=
priv
.
createConflictObject
(
command
,
metadata_file_content
,
current_revision
);
}
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
};
o
.
saveMetadataOnDistant
=
function
()
{
priv
.
saveMetadataToDistant
(
command
,
metadata_file_path
,
metadata_file_content
,
function
()
{
am
.
call
(
o
,
'
deleteAllConflictingRevision
'
);
if
(
on_conflict
)
{
am
.
call
(
o
,
'
error
'
);
}
else
{
am
.
call
(
o
,
'
success
'
);
}
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
deleteAllConflictingRevision
=
function
()
{
var
i
;
for
(
i
=
0
;
i
<
param
.
key
.
length
;
i
+=
1
)
{
priv
.
deleteAFile
(
command
,
param
.
docid
+
'
.
'
+
param
.
key
[
i
],
empty_fun
,
empty_fun
);
}
};
o
.
success
=
function
()
{
var
a
=
{
ok
:
true
,
id
:
param
.
docid
,
rev
:
current_revision
};
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
if
(
option
.
revs
)
{
a
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
option
.
revs_info
)
{
a
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
option
.
conflicts
)
{
a
.
conflicts
=
conflict_object
;
}
param
.
success
(
a
);
};
o
.
error
=
function
(
error
)
{
var
err
=
error
||
failerror
||
{
status
:
0
,
statusText
:
'
Unknown
'
,
error
:
'
unknown_error
'
,
message
:
'
Unknown error.
'
,
reason
:
'
unknown error
'
};
if
(
current_revision
)
{
err
.
rev
=
current_revision
;
}
if
(
option
.
revs
)
{
err
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
option
.
revs_info
)
{
err
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
option
.
conflicts
)
{
err
.
conflicts
=
conflict_object
;
}
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
param
.
error
(
err
);
};
am
.
call
(
o
,
'
getDistantMetadata
'
);
};
priv
.
createConflictObject
=
function
(
command
,
metadata
,
revision
)
{
return
{
total_rows
:
1
,
rows
:
[
priv
.
createConflictRow
(
command
,
command
.
getDocId
(),
metadata
,
revision
)]
};
};
priv
.
getParam
=
function
(
list
)
{
var
param
=
{},
i
=
0
;
if
(
typeof
list
[
i
]
===
'
string
'
)
{
param
.
content
=
list
[
i
];
i
+=
1
;
}
if
(
typeof
list
[
i
]
===
'
object
'
)
{
param
.
options
=
list
[
i
];
i
+=
1
;
}
else
{
param
.
options
=
{};
}
param
.
callback
=
function
()
{};
param
.
success
=
function
(
val
)
{
param
.
callback
(
undefined
,
val
);
};
param
.
error
=
function
(
err
)
{
param
.
callback
(
err
,
undefined
);
};
if
(
typeof
list
[
i
]
===
'
function
'
)
{
if
(
typeof
list
[
i
+
1
]
===
'
function
'
)
{
param
.
success
=
list
[
i
];
param
.
error
=
list
[
i
+
1
];
}
else
{
param
.
callback
=
list
[
i
];
}
}
return
param
;
};
priv
.
createConflictRow
=
function
(
command
,
docid
,
metadata
,
revision
)
{
var
row
=
{
id
:
docid
,
key
:
[],
value
:
{
// jslint: removed params /* content, option, success, error */
_solveConflict
:
function
()
{
var
param
=
{},
got
=
priv
.
getParam
(
arguments
);
if
(
got
.
content
===
undefined
)
{
param
.
_deleted
=
true
;
}
else
{
param
.
_deleted
=
false
;
}
param
.
success
=
got
.
success
;
param
.
error
=
got
.
error
;
param
.
previous_revision
=
revision
;
param
.
docid
=
docid
;
param
.
key
=
row
.
key
;
param
.
command
=
command
.
clone
();
return
priv
.
solveConflict
({
_id
:
docid
,
content
:
got
.
content
,
_rev
:
revision
},
got
.
options
,
param
);
}
}
},
k
;
for
(
k
in
metadata
)
{
if
(
metadata
.
hasOwnProperty
(
k
))
{
row
.
key
.
push
(
k
);
}
}
return
row
;
};
priv
.
newAsyncModule
=
function
()
{
var
async
=
{};
async
.
call
=
function
(
obj
,
function_name
,
arglist
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
if
(
obj
.
_wait
[
function_name
])
{
obj
.
_wait
[
function_name
]
-=
1
;
return
empty_fun
;
}
// ok if undef or 0
arglist
=
arglist
||
[];
setTimeout
(
function
()
{
obj
[
function_name
].
apply
(
obj
[
function_name
],
arglist
);
});
};
async
.
neverCall
=
function
(
obj
,
function_name
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
obj
.
_wait
[
function_name
]
=
-
1
;
};
async
.
wait
=
function
(
obj
,
function_name
,
times
)
{
obj
.
_wait
=
obj
.
_wait
||
{};
obj
.
_wait
[
function_name
]
=
times
;
};
async
.
end
=
function
()
{
async
.
call
=
empty_fun
;
};
return
async
;
};
that
.
post
=
function
(
command
)
{
that
.
put
(
command
);
};
/**
* Save a document and can manage conflicts.
* @method put
*/
that
.
put
=
function
(
command
)
{
var
o
=
{},
am
=
priv
.
newAsyncModule
(),
metadata_file_path
=
command
.
getDocId
()
+
'
.metadata
'
,
current_revision
=
''
,
current_revision_file_path
=
''
,
metadata_file_content
=
null
,
on_conflict
=
false
,
conflict_object
=
{
total_rows
:
0
,
rows
:
[]
},
previous_revision
=
command
.
getDocInfo
(
'
_rev
'
)
||
'
0
'
,
previous_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
previous_revision
,
now
=
new
Date
(),
failerror
;
o
.
getDistantMetadata
=
function
()
{
priv
.
getDistantMetadata
(
command
,
metadata_file_path
,
function
(
result
)
{
var
previous_revision_number
=
parseInt
(
previous_revision
.
split
(
'
-
'
)[
0
],
10
);
metadata_file_content
=
JSON
.
parse
(
result
.
content
);
// set current revision
current_revision
=
(
previous_revision_number
+
1
)
+
'
-
'
+
// jslint: removed hex_sha256(''+...
hex_sha256
(
command
.
getDocContent
()
+
previous_revision
+
JSON
.
stringify
(
metadata_file_content
));
current_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
current_revision
;
am
.
wait
(
o
,
'
saveMetadataOnDistant
'
,
1
);
am
.
call
(
o
,
'
saveNewRevision
'
);
am
.
call
(
o
,
'
checkForConflicts
'
);
},
function
(
error
)
{
if
(
error
.
status
===
404
)
{
current_revision
=
'
1-
'
+
hex_sha256
(
command
.
getDocContent
());
current_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
current_revision
;
am
.
wait
(
o
,
'
saveMetadataOnDistant
'
,
1
);
am
.
call
(
o
,
'
saveNewRevision
'
);
am
.
call
(
o
,
'
createMetadata
'
);
}
else
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
}
);
};
o
.
saveNewRevision
=
function
()
{
priv
.
saveNewRevision
(
command
,
current_revision_file_path
,
command
.
getDocContent
(),
function
()
{
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
checkForConflicts
=
function
()
{
var
rev
;
for
(
rev
in
metadata_file_content
)
{
if
(
metadata_file_content
.
hasOwnProperty
(
rev
)
&&
rev
!==
previous_revision
)
{
on_conflict
=
true
;
failerror
=
{
status
:
409
,
error
:
'
conflict
'
,
statusText
:
'
Conflict
'
,
reason
:
'
document update conflict
'
,
message
:
'
Document update conflict.
'
};
break
;
}
}
am
.
call
(
o
,
'
updateMetadata
'
);
};
o
.
createMetadata
=
function
()
{
var
id
=
current_revision
;
id
=
id
.
split
(
'
-
'
);
id
.
shift
();
id
=
id
.
join
(
'
-
'
);
metadata_file_content
=
{};
metadata_file_content
[
current_revision
]
=
{
_creation_date
:
now
.
getTime
(),
_last_modified
:
now
.
getTime
(),
_revisions
:
[
id
],
_conflict
:
false
,
_deleted
:
false
};
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
};
o
.
updateMetadata
=
function
()
{
var
previous_creation_date
,
revision_history
=
[],
id
=
''
;
if
(
metadata_file_content
[
previous_revision
])
{
previous_creation_date
=
metadata_file_content
[
previous_revision
].
_creation_date
;
revision_history
=
metadata_file_content
[
previous_revision
].
_revisions
;
delete
metadata_file_content
[
previous_revision
];
}
id
=
current_revision
.
split
(
'
-
'
);
id
.
shift
();
id
=
id
.
join
(
'
-
'
);
revision_history
.
unshift
(
id
);
metadata_file_content
[
current_revision
]
=
{
_creation_date
:
previous_creation_date
||
now
.
getTime
(),
_last_modified
:
now
.
getTime
(),
_revisions
:
revision_history
,
_conflict
:
on_conflict
,
_deleted
:
false
};
if
(
on_conflict
)
{
conflict_object
=
priv
.
createConflictObject
(
command
,
metadata_file_content
,
current_revision
);
}
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
};
o
.
saveMetadataOnDistant
=
function
()
{
priv
.
saveMetadataToDistant
(
command
,
metadata_file_path
,
metadata_file_content
,
function
()
{
am
.
call
(
o
,
'
deletePreviousRevision
'
);
if
(
on_conflict
)
{
am
.
call
(
o
,
'
error
'
);
}
else
{
am
.
call
(
o
,
'
success
'
);
}
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
deletePreviousRevision
=
function
()
{
// jslint: removed /*&& !on_conflict*/
if
(
previous_revision
!==
'
0
'
)
{
priv
.
deleteAFile
(
command
,
previous_revision_file_path
,
empty_fun
,
empty_fun
);
}
};
o
.
success
=
function
()
{
var
a
=
{
ok
:
true
,
id
:
command
.
getDocId
(),
rev
:
current_revision
};
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
if
(
command
.
getOption
(
'
revs
'
))
{
a
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
a
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
a
.
conflicts
=
conflict_object
;
}
that
.
success
(
a
);
};
o
.
error
=
function
(
error
)
{
var
err
=
error
||
failerror
||
{
status
:
0
,
statusText
:
'
Unknown
'
,
error
:
'
unknown_error
'
,
message
:
'
Unknown error.
'
,
reason
:
'
unknown error
'
};
if
(
current_revision
)
{
err
.
rev
=
current_revision
;
}
if
(
command
.
getOption
(
'
revs
'
))
{
err
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
err
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
err
.
conflicts
=
conflict_object
;
}
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
that
.
error
(
err
);
};
am
.
call
(
o
,
'
getDistantMetadata
'
);
};
// end put
/**
* Load a document from several storages, and send the first retreived
* document.
* @method get
*/
that
.
get
=
function
(
command
)
{
var
o
=
{},
am
=
priv
.
newAsyncModule
(),
metadata_file_path
=
command
.
getDocId
()
+
'
.metadata
'
,
current_revision
=
command
.
getOption
(
'
rev
'
)
||
''
,
metadata_file_content
=
null
,
metadata_only
=
command
.
getOption
(
'
metadata_only
'
),
on_conflict
=
false
,
conflict_object
=
{
total_rows
:
0
,
rows
:
[]
},
doc
=
{
_id
:
command
.
getDocId
()
},
call404
=
function
(
message
)
{
am
.
call
(
o
,
'
error
'
,
[{
status
:
404
,
statusText
:
'
Not Found
'
,
error
:
'
not_found
'
,
message
:
message
,
reason
:
message
}]);
};
o
.
getDistantMetadata
=
function
()
{
priv
.
getDistantMetadata
(
command
,
metadata_file_path
,
function
(
result
)
{
metadata_file_content
=
JSON
.
parse
(
result
.
content
);
if
(
!
metadata_only
)
{
am
.
wait
(
o
,
'
success
'
,
1
);
}
am
.
call
(
o
,
'
affectMetadata
'
);
am
.
call
(
o
,
'
checkForConflicts
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
affectMetadata
=
function
()
{
if
(
current_revision
)
{
if
(
!
metadata_file_content
[
current_revision
])
{
return
call404
(
'
Document revision does not exists.
'
);
}
}
else
{
current_revision
=
priv
.
chooseARevision
(
metadata_file_content
);
}
doc
.
_last_modified
=
metadata_file_content
[
current_revision
].
_last_modified
;
doc
.
_creation_date
=
metadata_file_content
[
current_revision
].
_creation_date
;
doc
.
_rev
=
current_revision
;
if
(
metadata_only
)
{
am
.
call
(
o
,
'
success
'
);
}
else
{
am
.
call
(
o
,
'
loadRevision
'
);
}
};
o
.
loadRevision
=
function
()
{
if
(
!
current_revision
||
metadata_file_content
[
current_revision
].
_deleted
)
{
return
call404
(
'
Document has been removed.
'
);
}
priv
.
loadRevision
(
command
,
doc
.
_id
+
'
.
'
+
current_revision
,
function
(
result
)
{
doc
.
content
=
result
.
content
;
am
.
call
(
o
,
'
success
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
checkForConflicts
=
function
()
{
if
(
metadata_file_content
[
current_revision
].
_conflict
)
{
on_conflict
=
true
;
conflict_object
=
priv
.
createConflictObject
(
command
,
metadata_file_content
,
current_revision
);
}
am
.
call
(
o
,
'
success
'
);
};
o
.
success
=
function
()
{
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
if
(
command
.
getOption
(
'
revs
'
))
{
doc
.
_revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
doc
.
_revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
doc
.
_conflicts
=
conflict_object
;
}
that
.
success
(
doc
);
};
o
.
error
=
function
(
error
)
{
var
err
=
error
||
{
status
:
0
,
statusText
:
'
Unknown
'
,
message
:
'
Unknown error.
'
};
if
(
command
.
getOption
(
'
revs
'
))
{
err
.
_revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
err
.
_revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
err
.
_conflicts
=
conflict_object
;
}
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
that
.
error
(
err
);
};
am
.
call
(
o
,
'
getDistantMetadata
'
);
};
/**
* Get a document list from several storages, and returns the first
* retreived document list.
* @method allDocs
*/
that
.
allDocs
=
function
(
command
)
{
var
o
=
{},
am
=
priv
.
newAsyncModule
(),
metadata_only
=
command
.
getOption
(
'
metadata_only
'
),
result_list
=
[],
conflict_object
=
{
total_rows
:
0
,
rows
:
[]
},
success_count
=
0
,
success_max
=
0
;
o
.
retreiveList
=
function
()
{
var
cloned_option
=
command
.
cloneOption
(),
success
=
function
(
result
)
{
am
.
call
(
o
,
'
filterTheList
'
,
[
result
]);
},
error
=
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
};
cloned_option
.
metadata_only
=
true
;
that
.
addJob
(
'
allDocs
'
,
priv
.
sub_storage_spec
,
null
,
cloned_option
,
success
,
error
);
};
o
.
filterTheList
=
function
(
result
)
{
var
i
,
splitname
;
success_max
+=
1
;
for
(
i
=
0
;
i
<
result
.
total_rows
;
i
+=
1
)
{
splitname
=
result
.
rows
[
i
].
id
.
split
(
'
.
'
)
||
[];
if
(
splitname
.
length
>
0
&&
splitname
[
splitname
.
length
-
1
]
===
'
metadata
'
)
{
success_max
+=
1
;
splitname
.
length
-=
1
;
am
.
call
(
o
,
'
loadMetadataFile
'
,
[
splitname
.
join
(
'
.
'
)]);
}
}
am
.
call
(
o
,
'
success
'
);
};
o
.
loadMetadataFile
=
function
(
path
)
{
priv
.
getDistantMetadata
(
command
,
path
+
'
.metadata
'
,
function
(
data
)
{
data
=
JSON
.
parse
(
data
.
content
);
var
revision
=
priv
.
chooseARevision
(
data
);
if
(
!
data
[
revision
].
_deleted
)
{
am
.
call
(
o
,
'
loadFile
'
,
[
path
,
revision
,
data
]);
}
else
{
am
.
call
(
o
,
'
success
'
);
}
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
loadFile
=
function
(
path
,
revision
,
data
)
{
var
doc
=
{
id
:
path
,
key
:
path
,
value
:
{
_last_modified
:
data
[
revision
].
_last_modified
,
_creation_date
:
data
[
revision
].
_creation_date
,
_rev
:
revision
}
};
if
(
command
.
getOption
(
'
revs
'
))
{
doc
.
value
.
_revisions
=
priv
.
_revs
(
data
,
revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
doc
.
value
.
_revs_info
=
priv
.
_revs_info
(
data
,
revision
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
if
(
data
[
revision
].
_conflict
)
{
conflict_object
.
total_rows
+=
1
;
conflict_object
.
rows
.
push
(
priv
.
createConflictRow
(
command
,
path
,
data
,
revision
)
);
}
}
if
(
!
metadata_only
)
{
priv
.
loadRevision
(
command
,
path
+
'
.
'
+
revision
,
function
(
data
)
{
doc
.
content
=
data
.
content
;
result_list
.
push
(
doc
);
am
.
call
(
o
,
'
success
'
);
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
}
else
{
result_list
.
push
(
doc
);
am
.
call
(
o
,
'
success
'
);
}
};
o
.
success
=
function
()
{
var
obj
;
success_count
+=
1
;
if
(
success_count
>=
success_max
)
{
am
.
end
();
obj
=
{
total_rows
:
result_list
.
length
,
rows
:
result_list
};
if
(
command
.
getOption
(
'
conflicts
'
))
{
obj
.
conflicts
=
conflict_object
;
}
that
.
success
(
obj
);
}
};
o
.
error
=
function
(
error
)
{
am
.
end
();
that
.
error
(
error
);
};
am
.
call
(
o
,
'
retreiveList
'
);
};
// end allDocs
/**
* Remove a document from several storages.
* @method remove
*/
that
.
remove
=
function
(
command
)
{
var
o
=
{},
am
=
priv
.
newAsyncModule
(),
metadata_file_path
=
command
.
getDocId
()
+
'
.metadata
'
,
current_revision
=
''
,
current_revision_file_path
=
''
,
metadata_file_content
=
null
,
on_conflict
=
false
,
conflict_object
=
{
total_rows
:
0
,
rows
:
[]
},
previous_revision
=
command
.
getOption
(
'
rev
'
)
||
'
0
'
,
previous_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
previous_revision
,
now
=
new
Date
(),
failerror
;
o
.
getDistantMetadata
=
function
()
{
priv
.
getDistantMetadata
(
command
,
metadata_file_path
,
function
(
result
)
{
metadata_file_content
=
JSON
.
parse
(
result
.
content
);
if
(
previous_revision
===
'
last
'
)
{
previous_revision
=
priv
.
chooseARevision
(
metadata_file_content
);
previous_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
previous_revision
;
}
var
previous_revision_number
=
parseInt
(
previous_revision
.
split
(
'
-
'
)[
0
],
10
)
||
0
;
// set current revision
current_revision
=
(
previous_revision_number
+
1
)
+
'
-
'
+
//jslint: removed hex_sha256(''...
hex_sha256
(
previous_revision
+
JSON
.
stringify
(
metadata_file_content
)
);
current_revision_file_path
=
command
.
getDocId
()
+
'
.
'
+
current_revision
;
am
.
call
(
o
,
'
checkForConflicts
'
);
},
function
(
error
)
{
if
(
error
.
status
===
404
)
{
am
.
call
(
o
,
'
error
'
,
[{
status
:
404
,
statusText
:
'
Not Found
'
,
error
:
'
not_found
'
,
reason
:
'
missing
'
,
message
:
'
Document not found.
'
}]);
}
else
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
}
);
};
o
.
checkForConflicts
=
function
()
{
var
rev
;
for
(
rev
in
metadata_file_content
)
{
if
(
metadata_file_content
.
hasOwnProperty
(
rev
)
&&
rev
!==
previous_revision
)
{
on_conflict
=
true
;
failerror
=
{
status
:
409
,
error
:
'
conflict
'
,
statusText
:
'
Conflict
'
,
reason
:
'
document update conflict
'
,
message
:
'
There is one or more conflicts
'
};
break
;
}
}
am
.
call
(
o
,
'
updateMetadata
'
);
};
o
.
updateMetadata
=
function
()
{
var
previous_creation_date
,
revision_history
=
[],
id
=
''
;
if
(
metadata_file_content
[
previous_revision
])
{
previous_creation_date
=
metadata_file_content
[
previous_revision
].
_creation_date
;
revision_history
=
metadata_file_content
[
previous_revision
].
_revisions
;
delete
metadata_file_content
[
previous_revision
];
}
id
=
current_revision
;
id
=
id
.
split
(
'
-
'
);
id
.
shift
();
id
=
id
.
join
(
'
-
'
);
revision_history
.
unshift
(
id
);
metadata_file_content
[
current_revision
]
=
{
_creation_date
:
previous_creation_date
||
now
.
getTime
(),
_last_modified
:
now
.
getTime
(),
_revisions
:
revision_history
,
_conflict
:
on_conflict
,
_deleted
:
true
};
if
(
on_conflict
)
{
conflict_object
=
priv
.
createConflictObject
(
command
,
metadata_file_content
,
current_revision
);
}
am
.
call
(
o
,
'
saveMetadataOnDistant
'
);
};
o
.
saveMetadataOnDistant
=
function
()
{
priv
.
saveMetadataToDistant
(
command
,
metadata_file_path
,
metadata_file_content
,
function
()
{
am
.
call
(
o
,
'
deletePreviousRevision
'
);
if
(
on_conflict
)
{
am
.
call
(
o
,
'
error
'
);
}
else
{
am
.
call
(
o
,
'
success
'
);
}
},
function
(
error
)
{
am
.
call
(
o
,
'
error
'
,
[
error
]);
}
);
};
o
.
deletePreviousRevision
=
function
()
{
// jslint: removed /*&& !on_conflict*/
if
(
previous_revision
!==
'
0
'
)
{
priv
.
deleteAFile
(
command
,
previous_revision_file_path
,
empty_fun
,
empty_fun
);
}
};
o
.
success
=
function
(
revision
)
{
var
a
=
{
ok
:
true
,
id
:
command
.
getDocId
(),
rev
:
revision
||
current_revision
};
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
if
(
command
.
getOption
(
'
revs
'
))
{
a
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
a
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
a
.
conflicts
=
conflict_object
;
}
that
.
success
(
a
);
};
o
.
error
=
function
(
error
)
{
var
err
=
error
||
failerror
||
{
status
:
0
,
statusText
:
'
Unknown
'
,
error
:
'
unknown_error
'
,
message
:
'
Unknown error.
'
,
reason
:
'
unknown error
'
};
if
(
current_revision
)
{
err
.
rev
=
current_revision
;
}
if
(
command
.
getOption
(
'
revs
'
))
{
err
.
revisions
=
priv
.
_revs
(
metadata_file_content
,
current_revision
);
}
if
(
command
.
getOption
(
'
revs_info
'
))
{
err
.
revs_info
=
priv
.
_revs_info
(
metadata_file_content
);
}
if
(
command
.
getOption
(
'
conflicts
'
))
{
err
.
conflicts
=
conflict_object
;
}
am
.
neverCall
(
o
,
'
error
'
);
am
.
neverCall
(
o
,
'
success
'
);
that
.
error
(
err
);
};
am
.
call
(
o
,
'
getDistantMetadata
'
);
};
// end remove
return
that
;
});
src/jio.storage/davstorage.js
deleted
100644 → 0
View file @
3356688e
/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jQuery, btoa */
// JIO Dav Storage Description :
// {
// type: "dav",
// url: {string}
// }
// {
// type: "dav",
// url: {string},
// auth_type: {string}, (optional)
// - "auto" (default) (not implemented)
// - "basic"
// - "digest" (not implemented)
// realm: {string}, (optional)
// - undefined (default) (not implemented)
// - "<string>" realm name (not implemented)
// username: {string},
// password: {string} (optional)
// }
// {
// type: "dav",
// url: {string},
// encoded_login: {string}
// }
// {
// type: "dav",
// url: {string},
// secured_login: {string} (not implemented)
// }
// NOTE: to get the authentication type ->
// curl --verbose -X OPTION http://domain/
// In the headers: "WWW-Authenticate: Basic realm="DAV-upload"
// URL Characters convertion:
// If I want to retrieve the file which id is -> http://100%.json
// http://domain/collection/http://100%.json cannot be applied
// - '/' is col separator,
// - '?' is url/parameter separator
// - '%' is special char
// - '.' document and attachment separator
// http://100%.json will become
// - http:%2F%2F100%25.json to avoid bad request ('/', '%' -> '%2F', '%25')
// - http:%2F%2F100%25_.json to avoid ids conflicts ('.' -> '_.')
// - http:%252F%252F100%2525_.json to avoid request bad interpretation
// ('%', '%25')
// The file will be saved as http:%2F%2F100%25_.json
// define([module_name], [dependencies], module);
(
function
(
dependencies
,
module
)
{
"
use strict
"
;
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
return
define
(
dependencies
,
module
);
}
module
(
jIO
,
jQuery
);
}([
'
jio
'
,
'
jquery
'
],
function
(
jIO
,
$
)
{
"
use strict
"
;
jIO
.
addStorageType
(
"
dav
"
,
function
(
spec
,
my
)
{
var
priv
=
{},
that
=
my
.
basicStorage
(
spec
,
my
),
dav
=
{};
// ATTRIBUTES //
priv
.
url
=
null
;
priv
.
username
=
null
;
priv
.
password
=
null
;
priv
.
encoded_login
=
null
;
// CONSTRUCTOR //
/**
* Init the dav storage connector thanks to the description
* @method __init__
* @param {object} description The description object
*/
priv
.
__init__
=
function
(
description
)
{
priv
.
url
=
description
.
url
||
""
;
priv
.
url
=
priv
.
removeSlashIfLast
(
priv
.
url
);
// if (description.secured_login) {
// not implemented
// } else
if
(
description
.
encoded_login
)
{
priv
.
encoded_login
=
description
.
encoded_login
;
}
else
if
(
description
.
auth_type
)
{
if
(
description
.
auth_type
===
"
basic
"
)
{
priv
.
encoded_login
=
"
Basic
"
+
btoa
((
description
.
username
||
""
)
+
"
:
"
+
(
description
.
password
||
""
));
}
}
else
{
priv
.
encoded_login
=
""
;
}
};
// OVERRIDES //
that
.
specToStore
=
function
()
{
// TODO: secured password
// The encoded_login can be seen by anyone,
// we must find a way to secure it!
// secured_login = encrypt(encoded_login)
// encoded_login = decrypt(secured_login)
return
{
"
url
"
:
priv
.
url
,
"
encoded_login
"
:
priv
.
encoded_login
};
};
that
.
validateState
=
function
()
{
if
(
typeof
priv
.
url
!==
"
string
"
||
priv
.
url
===
""
)
{
return
"
The webDav server URL is not provided
"
;
}
if
(
priv
.
encoded_login
===
null
)
{
return
"
Impossible to create the authorization
"
;
}
return
""
;
};
// TOOLS //
/**
* Generate a new uuid
* @method generateUuid
* @return {string} The new uuid
*/
priv
.
generateUuid
=
function
()
{
var
S4
=
function
()
{
/* 65536 */
var
i
,
string
=
Math
.
floor
(
Math
.
random
()
*
0x10000
).
toString
(
16
);
for
(
i
=
string
.
length
;
i
<
4
;
i
+=
1
)
{
string
=
"
0
"
+
string
;
}
return
string
;
};
return
S4
()
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
S4
()
+
S4
();
};
// /**
// * Clones an object in deep
// * @method clone
// * @param {object} object The object to clone
// * @return {object} The cloned object
// */
// priv.clone = function (object) {
// var tmp = JSON.stringify(object);
// if (tmp === undefined) {
// return undefined;
// }
// return JSON.parse(tmp);
// };
/**
* Replace substrings to another strings
* @method recursiveReplace
* @param {string} string The string to do replacement
* @param {array} list_of_replacement An array of couple
* ["substring to select", "selected substring replaced by this string"].
* @return {string} The replaced string
*/
priv
.
recursiveReplace
=
function
(
string
,
list_of_replacement
)
{
var
i
,
split_string
=
string
.
split
(
list_of_replacement
[
0
][
0
]);
if
(
list_of_replacement
[
1
])
{
for
(
i
=
0
;
i
<
split_string
.
length
;
i
+=
1
)
{
split_string
[
i
]
=
priv
.
recursiveReplace
(
split_string
[
i
],
list_of_replacement
.
slice
(
1
)
);
}
}
return
split_string
.
join
(
list_of_replacement
[
0
][
1
]);
};
/**
* Changes spaces to %20, / to %2f, % to %25 and ? to %3f
* @method secureName
* @param {string} name The name to secure
* @return {string} The secured name
*/
priv
.
secureName
=
function
(
name
)
{
return
priv
.
recursiveReplace
(
name
,
[
[
"
"
,
"
%20
"
],
[
"
/
"
,
"
%2F
"
],
[
"
%
"
,
"
%25
"
],
[
"
?
"
,
"
%3F
"
]
]);
};
/**
* Restores the original name from a secured name
* @method restoreName
* @param {string} secured_name The secured name to restore
* @return {string} The original name
*/
priv
.
restoreName
=
function
(
secured_name
)
{
return
priv
.
recursiveReplace
(
secured_name
,
[
[
"
%20
"
,
"
"
],
[
"
%2F
"
,
"
/
"
],
[
"
%25
"
,
"
%
"
],
[
"
%3F
"
,
"
?
"
]
]);
};
/**
* Convert document id and attachment id to a file name
* @method idsToFileName
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id (optional)
* @return {string} The file name
*/
priv
.
idsToFileName
=
function
(
doc_id
,
attachment_id
)
{
doc_id
=
priv
.
secureName
(
doc_id
).
split
(
"
.
"
).
join
(
"
_.
"
);
if
(
typeof
attachment_id
===
"
string
"
)
{
attachment_id
=
priv
.
secureName
(
attachment_id
).
split
(
"
.
"
).
join
(
"
_.
"
);
return
doc_id
+
"
.
"
+
attachment_id
;
}
return
doc_id
;
};
/**
* Convert a file name to a document id (and attachment id if there)
* @method fileNameToIds
* @param {string} file_name The file name to convert
* @return {array} ["document id", "attachment id"] or ["document id"]
*/
priv
.
fileNameToIds
=
function
(
file_name
)
{
var
separator_index
=
-
1
,
split
=
file_name
.
split
(
"
.
"
);
split
.
slice
(
0
,
-
1
).
forEach
(
function
(
file_name_part
,
index
)
{
if
(
file_name_part
.
slice
(
-
1
)
!==
"
_
"
)
{
if
(
separator_index
!==
-
1
)
{
separator_index
=
new
TypeError
(
"
Corrupted file name
"
);
separator_index
.
status
=
24
;
throw
separator_index
;
}
separator_index
=
index
;
}
});
if
(
separator_index
===
-
1
)
{
return
[
priv
.
restoreName
(
priv
.
restoreName
(
file_name
).
split
(
"
_.
"
).
join
(
"
.
"
))];
}
return
[
priv
.
restoreName
(
priv
.
restoreName
(
split
.
slice
(
0
,
separator_index
+
1
).
join
(
"
.
"
)
).
split
(
"
_.
"
).
join
(
"
.
"
)),
priv
.
restoreName
(
priv
.
restoreName
(
split
.
slice
(
separator_index
+
1
).
join
(
"
.
"
)
).
split
(
"
_.
"
).
join
(
"
.
"
))
];
};
/**
* Removes the last character if it is a "/". "/a/b/c/" become "/a/b/c"
* @method removeSlashIfLast
* @param {string} string The string to modify
* @return {string} The modified string
*/
priv
.
removeSlashIfLast
=
function
(
string
)
{
if
(
string
[
string
.
length
-
1
]
===
"
/
"
)
{
return
string
.
slice
(
0
,
-
1
);
}
return
string
;
};
/**
* Modify an ajax object to add default values
* @method makeAjaxObject
* @param {string} file_name The file name to add to the url
* @param {object} ajax_object The ajax object to override
* @return {object} A new ajax object with default values
*/
priv
.
makeAjaxObject
=
function
(
file_name
,
method
,
ajax_object
)
{
ajax_object
.
type
=
method
||
ajax_object
.
type
||
"
GET
"
;
ajax_object
.
url
=
priv
.
url
+
"
/
"
+
priv
.
secureName
(
file_name
)
+
"
?_=
"
+
Date
.
now
();
ajax_object
.
async
=
ajax_object
.
async
===
false
?
false
:
true
;
ajax_object
.
crossdomain
=
ajax_object
.
crossdomain
===
false
?
false
:
true
;
ajax_object
.
headers
=
ajax_object
.
headers
||
{};
ajax_object
.
headers
.
Authorization
=
ajax_object
.
headers
.
Authorization
||
priv
.
encoded_login
;
return
ajax_object
;
};
/**
* Runs all ajax requests for davStorage
* @method ajax
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id, can be undefined
* @param {string} method The request method
* @param {object} ajax_object The request parameters (optional)
*/
priv
.
ajax
=
function
(
doc_id
,
attachment_id
,
method
,
ajax_object
)
{
var
new_ajax_object
=
JSON
.
parse
(
JSON
.
stringify
(
ajax_object
)
||
"
{}
"
);
return
$
.
ajax
(
priv
.
makeAjaxObject
(
priv
.
idsToFileName
(
doc_id
||
''
,
attachment_id
),
method
,
new_ajax_object
));
//.always(then || function () {});
};
/**
* Creates error objects for this storage
* @method createError
* @param {string} url url to clean up
* @return {object} error The error object
*/
priv
.
createError
=
function
(
status
,
message
,
reason
)
{
var
error
=
{
"
status
"
:
status
,
"
message
"
:
message
,
"
reason
"
:
reason
};
switch
(
status
)
{
case
404
:
error
.
statusText
=
"
Not found
"
;
break
;
case
405
:
error
.
statusText
=
"
Method Not Allowed
"
;
break
;
case
409
:
error
.
statusText
=
"
Conflicts
"
;
break
;
case
24
:
error
.
statusText
=
"
Corrupted Document
"
;
break
;
}
error
.
error
=
error
.
statusText
.
toLowerCase
().
split
(
"
"
).
join
(
"
_
"
);
return
error
;
};
/**
* Converts ajax error object to a JIO error object
* @method ajaxErrorToJioError
* @param {object} ajax_error_object The ajax error object
* @param {string} message The error message
* @param {string} reason The error reason
* @return {object} The JIO error object
*/
priv
.
ajaxErrorToJioError
=
function
(
ajax_error_object
,
message
,
reason
)
{
var
jio_error_object
=
{};
jio_error_object
.
status
=
ajax_error_object
.
status
;
jio_error_object
.
statusText
=
ajax_error_object
.
statusText
;
jio_error_object
.
error
=
ajax_error_object
.
statusText
.
toLowerCase
().
split
(
"
"
).
join
(
"
_
"
);
jio_error_object
.
message
=
message
;
jio_error_object
.
reason
=
reason
;
return
jio_error_object
;
};
/**
* Function that create an object containing jQuery like callbacks
* @method makeJQLikeCallback
* @return {object} jQuery like callback methods
*/
priv
.
makeJQLikeCallback
=
function
()
{
var
result
=
null
,
emptyFun
=
function
()
{},
jql
=
{
"
respond
"
:
function
()
{
result
=
arguments
;
},
"
to_return
"
:
{
"
always
"
:
function
(
func
)
{
if
(
result
)
{
func
.
apply
(
func
,
result
);
jql
.
to_return
.
always
=
emptyFun
;
}
else
{
jql
.
respond
=
func
;
}
return
jql
.
to_return
;
},
"
then
"
:
function
(
func
)
{
if
(
result
)
{
func
(
result
[
1
]);
jql
.
to_return
.
then
=
emptyFun
;
}
else
{
jql
.
respond
=
function
(
err
,
response
)
{
func
(
response
);
};
}
return
jql
.
to_return
;
}
}
};
return
jql
;
};
// DAV REQUESTS //
/**
* Retrieve a document file
* @method dav.getDocument
* @param {string} doc_id The document id
*/
dav
.
getDocument
=
function
(
doc_id
)
{
var
doc
,
jql
=
priv
.
makeJQLikeCallback
(),
error
=
null
;
priv
.
ajax
(
doc_id
,
undefined
,
"
GET
"
).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
error
=
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot retrieve document
"
,
"
Unknown
"
);
if
(
one
.
status
===
404
)
{
error
.
reason
=
"
Not Found
"
;
}
return
jql
.
respond
(
error
,
undefined
);
}
try
{
doc
=
JSON
.
parse
(
one
);
}
catch
(
e
)
{
return
jql
.
respond
(
priv
.
createError
(
24
,
"
Cannot parse document
"
,
"
Document is corrupted
"
),
undefined
);
}
// document health is good
return
jql
.
respond
(
undefined
,
doc
);
});
return
jql
.
to_return
;
};
/**
* Retrieve an attachment file
* @method dav.getAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
*/
dav
.
getAttachment
=
function
(
doc_id
,
attachment_id
)
{
var
jql
=
priv
.
makeJQLikeCallback
(),
error
=
null
;
priv
.
ajax
(
doc_id
,
attachment_id
,
"
GET
"
).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
error
=
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot retrieve attachment
"
,
"
Unknown
"
);
if
(
one
.
status
===
404
)
{
error
.
reason
=
"
Not Found
"
;
}
return
jql
.
respond
(
error
,
undefined
);
}
return
jql
.
respond
(
undefined
,
one
);
});
return
jql
.
to_return
;
};
/**
* Uploads a document file
* @method dav.putDocument
* @param {object} doc The document object
*/
dav
.
putDocument
=
function
(
doc
)
{
var
jql
=
priv
.
makeJQLikeCallback
();
priv
.
ajax
(
doc
.
_id
,
undefined
,
"
PUT
"
,
{
"
dataType
"
:
"
text
"
,
"
data
"
:
JSON
.
stringify
(
doc
)
}).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
return
jql
.
respond
(
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot upload document
"
,
"
Unknown
"
),
undefined
);
}
jql
.
respond
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc
.
_id
});
});
return
jql
.
to_return
;
};
/**
* Uploads an attachment file
* @method dav.putAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
* @param {string} data The attachment data
*/
dav
.
putAttachment
=
function
(
doc_id
,
attachment_id
,
data
)
{
var
jql
=
priv
.
makeJQLikeCallback
();
priv
.
ajax
(
doc_id
,
attachment_id
,
"
PUT
"
,
{
"
dataType
"
:
"
text
"
,
"
data
"
:
data
}).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
return
jql
.
respond
(
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot upload attachment
"
,
"
Unknown
"
),
undefined
);
}
return
jql
.
respond
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc_id
,
"
attachment
"
:
attachment_id
});
});
return
jql
.
to_return
;
};
/**
* Deletes a document file
* @method dav.removeDocument
* @param {string} doc_id The document id
*/
dav
.
removeDocument
=
function
(
doc_id
)
{
var
jql
=
priv
.
makeJQLikeCallback
(),
error
=
null
;
priv
.
ajax
(
doc_id
,
undefined
,
"
DELETE
"
).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
error
=
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot delete document
"
,
"
Unknown
"
);
if
(
one
.
status
===
404
)
{
error
.
reason
=
"
Not Found
"
;
}
return
jql
.
respond
(
error
,
undefined
);
}
jql
.
respond
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc_id
});
});
return
jql
.
to_return
;
};
/**
* Deletes an attachment file
* @method dav.removeAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
*/
dav
.
removeAttachment
=
function
(
doc_id
,
attachment_id
)
{
var
jql
=
priv
.
makeJQLikeCallback
(),
error
=
null
;
priv
.
ajax
(
doc_id
,
attachment_id
,
"
DELETE
"
).
always
(
function
(
one
,
state
,
three
)
{
if
(
state
!==
"
success
"
)
{
error
=
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot delete attachment
"
,
"
Unknown
"
);
if
(
one
.
status
===
404
)
{
error
.
reason
=
"
Not Found
"
;
}
return
jql
.
respond
(
error
,
undefined
);
}
jql
.
respond
(
undefined
,
{
"
ok
"
:
true
,
"
id
"
:
doc_id
});
});
return
jql
.
to_return
;
};
/**
* Get a list of document file
* @method dav.allDocs
*/
dav
.
allDocs
=
function
()
{
var
jql
=
priv
.
makeJQLikeCallback
(),
rows
=
[];
priv
.
ajax
(
undefined
,
undefined
,
"
PROPFIND
"
,
{
"
dataType
"
:
"
xml
"
,
"
headers
"
:
{
"
Depth
"
:
1
}
}).
always
(
function
(
one
,
state
,
three
)
{
var
response
,
len
;
if
(
state
!==
"
success
"
)
{
return
jql
.
respond
(
priv
.
ajaxErrorToJioError
(
one
,
"
Cannot get the document list
"
,
"
Unknown
"
),
undefined
);
}
response
=
$
(
one
).
find
(
"
D
\\
:response, response
"
);
len
=
response
.
length
;
if
(
len
===
1
)
{
return
jql
.
respond
({
"
total_rows
"
:
0
,
"
rows
"
:
[]});
}
response
.
each
(
function
(
i
,
data
)
{
var
row
;
if
(
i
>
0
)
{
// exclude parent folder
row
=
{
"
id
"
:
""
,
"
key
"
:
""
,
"
value
"
:
{}
};
$
(
data
).
find
(
"
D
\\
:href, href
"
).
each
(
function
()
{
row
.
id
=
$
(
this
).
text
().
split
(
'
/
'
).
slice
(
-
1
)[
0
];
try
{
row
.
id
=
priv
.
fileNameToIds
(
row
.
id
);
}
catch
(
e
)
{
if
(
e
.
name
===
"
TypeError
"
&&
e
.
status
===
24
)
{
return
;
}
throw
e
;
}
if
(
row
.
id
.
length
!==
1
)
{
row
=
undefined
;
}
else
{
row
.
id
=
row
.
id
[
0
];
row
.
key
=
row
.
id
;
}
});
if
(
row
!==
undefined
)
{
rows
.
push
(
row
);
}
}
});
jql
.
respond
(
undefined
,
{
"
total_rows
"
:
rows
.
length
,
"
rows
"
:
rows
});
});
return
jql
.
to_return
;
};
// JIO COMMANDS //
// wedDav methods rfc4918 (short summary)
// COPY Reproduces single resources (files) and collections (directory
// trees). Will overwrite files (if specified by request) but will
// respond 209 (Conflict) if it would overwrite a tree
// DELETE deletes files and directory trees
// GET just the vanilla HTTP/1.1 behaviour
// HEAD ditto
// LOCK locks a resources
// MKCOL creates a directory
// MOVE Moves (rename or copy) a file or a directory tree. Will
// 'overwrite' files (if specified by the request) but will respond
// 209 (Conflict) if it would overwrite a tree.
// OPTIONS If WebDAV is enabled and available for the path this reports the
// WebDAV extension methods
// PROPFIND Retrieves the requested file characteristics, DAV lock status
// and 'dead' properties for individual files, a directory and its
// child files, or a directory tree
// PROPPATCHset and remove 'dead' meta-data properties
// PUT Update or create resource or collections
// UNLOCK unlocks a resource
// Notes: all Ajax requests should be CORS (cross-domain)
// adding custom headers triggers preflight OPTIONS request!
// http://remysharp.com/2011/04/21/getting-cors-working/
/**
* Creates a new document
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
var
doc_id
=
command
.
getDocId
()
||
priv
.
generateUuid
();
dav
.
getDocument
(
doc_id
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
if
(
err
.
status
===
404
)
{
// the document does not already exist
// updating document
var
doc
=
command
.
cloneDoc
();
doc
.
_id
=
doc_id
;
return
dav
.
putDocument
(
doc
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
retry
(
err
);
}
return
that
.
success
(
response
);
});
}
if
(
err
.
status
===
24
)
{
return
that
.
error
(
err
);
}
// an error occured
return
that
.
retry
(
err
);
}
// the document already exists
return
that
.
error
(
priv
.
createError
(
405
,
"
Cannot create document
"
,
"
Document already exists
"
));
});
};
/**
* Creates or updates a document
* @method put
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
)
{
dav
.
putDocument
(
command
.
cloneDoc
()).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
// an error occured
return
that
.
retry
(
err
);
}
// document updated
return
that
.
success
(
response
);
});
};
/**
* Add an attachment to a document
* @method putAttachment
* @param {object} command The JIO command
*/
that
.
putAttachment
=
function
(
command
)
{
var
doc
=
null
,
doc_id
=
command
.
getDocId
(),
attachment_id
,
tmp
;
attachment_id
=
command
.
getAttachmentId
();
dav
.
getDocument
(
doc_id
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
// document not found or error
tmp
=
that
.
retry
;
if
(
err
.
status
===
404
||
err
.
status
===
24
)
{
tmp
=
that
.
error
;
}
return
tmp
(
err
);
}
doc
=
response
;
doc
.
_attachments
=
doc
.
_attachments
||
{};
doc
.
_attachments
[
attachment_id
]
=
{
"
length
"
:
command
.
getAttachmentLength
(),
"
digest
"
:
"
md5-
"
+
command
.
md5SumAttachmentData
(),
"
content_type
"
:
command
.
getAttachmentMimeType
()
};
// put the attachment
dav
.
putAttachment
(
doc_id
,
attachment_id
,
command
.
getAttachmentData
()
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
// an error occured
return
that
.
retry
(
err
);
}
// update the document
dav
.
putDocument
(
doc
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
retry
(
err
);
}
response
.
attachment
=
attachment_id
;
return
that
.
success
(
response
);
});
});
});
};
/**
* Get a document
* @method get
* @param {object} command The JIO command
*/
that
.
get
=
function
(
command
)
{
dav
.
getDocument
(
command
.
getDocId
()).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
if
(
err
.
status
===
404
||
err
.
status
===
24
)
{
return
that
.
error
(
err
);
}
return
that
.
retry
(
err
);
}
return
that
.
success
(
response
);
});
};
/**
* Get an attachment
* @method getAttachment
* @param {object} command The JIO command
*/
that
.
getAttachment
=
function
(
command
)
{
dav
.
getAttachment
(
command
.
getDocId
(),
command
.
getAttachmentId
()
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
if
(
err
.
status
===
404
)
{
return
that
.
error
(
err
);
}
return
that
.
retry
(
err
);
}
return
that
.
success
(
response
);
});
};
/**
* Remove a document
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
var
doc_id
=
command
.
getDocId
(),
count
=
0
,
end
;
end
=
function
()
{
count
-=
1
;
if
(
count
===
0
)
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
doc_id
});
}
};
dav
.
getDocument
(
doc_id
).
always
(
function
(
err
,
response
)
{
var
attachment_id
=
null
;
if
(
err
)
{
if
(
err
.
status
===
404
)
{
return
that
.
error
(
err
);
}
if
(
err
.
status
!==
24
)
{
// 24 -> corrupted document
return
that
.
retry
(
err
);
}
response
=
{};
}
count
+=
2
;
dav
.
removeDocument
(
doc_id
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
if
(
err
.
status
===
404
)
{
return
that
.
error
(
err
);
}
return
that
.
retry
(
err
);
}
return
end
();
});
for
(
attachment_id
in
response
.
_attachments
)
{
if
(
response
.
_attachments
.
hasOwnProperty
(
attachment_id
))
{
count
+=
1
;
dav
.
removeAttachment
(
doc_id
,
attachment_id
).
always
(
end
);
}
}
end
();
});
};
/**
* Remove an attachment
* @method removeAttachment
* @param {object} command The JIO command
*/
that
.
removeAttachment
=
function
(
command
)
{
var
doc_id
=
command
.
getDocId
(),
doc
,
attachment_id
;
attachment_id
=
command
.
getAttachmentId
();
dav
.
getDocument
(
doc_id
).
always
(
function
(
err
,
response
)
{
var
still_has_attachments
;
if
(
err
)
{
if
(
err
.
status
===
404
||
err
.
status
===
24
)
{
return
that
.
error
(
err
);
}
return
that
.
retry
(
err
);
}
doc
=
response
;
if
(
typeof
(
doc
.
_attachments
||
{})[
attachment_id
]
!==
"
object
"
)
{
return
that
.
error
(
priv
.
createError
(
404
,
"
Cannot remove attachment
"
,
"
Not Found
"
));
}
delete
doc
.
_attachments
[
attachment_id
];
// check if there is still attachments
for
(
still_has_attachments
in
doc
.
_attachments
)
{
if
(
doc
.
_attachments
.
hasOwnProperty
(
still_has_attachments
))
{
break
;
}
}
if
(
still_has_attachments
===
undefined
)
{
delete
doc
.
_attachments
;
}
doc
.
_id
=
doc_id
;
dav
.
putDocument
(
doc
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
retry
(
err
);
}
dav
.
removeAttachment
(
doc_id
,
attachment_id
).
always
(
function
(
err
,
response
)
{
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
doc_id
,
"
attachment
"
:
attachment_id
});
});
});
});
};
/**
* Gets a document list from a distant dav storage
* Options:
* - {boolean} include_docs Also retrieve the actual document content.
* @method allDocs
* @param {object} command The JIO command
*/
that
.
allDocs
=
function
(
command
)
{
var
count
=
0
,
end
,
rows
;
end
=
function
()
{
count
-=
1
;
if
(
count
===
0
)
{
that
.
success
(
rows
);
}
};
dav
.
allDocs
().
always
(
function
(
err
,
response
)
{
if
(
err
)
{
return
that
.
retry
(
err
);
}
if
(
command
.
getOption
(
"
include_docs
"
)
===
true
)
{
count
+=
1
;
rows
=
response
;
rows
.
rows
.
forEach
(
function
(
row
)
{
count
+=
1
;
dav
.
getDocument
(
row
.
id
).
always
(
function
(
err
,
response
)
{
if
(
err
)
{
if
(
err
.
status
===
404
||
err
.
status
===
24
)
{
return
that
.
error
(
err
);
}
return
that
.
retry
(
err
);
}
row
.
doc
=
response
;
end
();
});
});
end
();
}
else
{
that
.
success
(
response
);
}
});
};
priv
.
__init__
(
spec
);
return
that
;
});
}));
src/jio.storage/ramstorage.js
deleted
100644 → 0
View file @
3356688e
/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global define, jIO, setTimeout, complex_queries */
// define([module_name], [dependencies], module);
(
function
(
dependencies
,
module
)
{
"
use strict
"
;
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
return
define
(
dependencies
,
module
);
}
module
(
jIO
);
}([
'
jio
'
],
function
(
jIO
)
{
var
storage
=
{};
/**
* Returns 4 hexadecimal random characters.
*
* @return {String} The characters
*/
function
S4
()
{
return
(
'
0000
'
+
Math
.
floor
(
Math
.
random
()
*
0x10000
/* 65536 */
).
toString
(
16
)).
slice
(
-
4
);
}
/**
* An Universal Unique ID generator
*
* @return {String} The new UUID.
*/
function
generateUuid
()
{
return
S4
()
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
S4
()
+
S4
();
}
/**
* Checks if an object has no enumerable keys
*
* @param {Object} obj The object
* @return {Boolean} true if empty, else false
*/
function
objectIsEmpty
(
obj
)
{
var
k
;
for
(
k
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
k
))
{
return
false
;
}
}
return
true
;
}
/**
* JIO Ram Storage. Type = 'ram'.
* Memory "database" storage.
*
* Storage Description:
*
* {
* "type": "ram",
* "namespace": <string>, // default 'default'
* }
*
* Document are stored in path
* 'namespace/document_id' like this:
*
* {
* "_id": "document_id",
* "_attachments": {
* "attachment_name": {
* "length": data_length,
* "digest": "md5-XXX",
* "content_type": "mime/type"
* },
* "attachment_name2": {..}, ...
* },
* "metadata_name": "metadata_value"
* "metadata_name2": ...
* ...
* }
*
* Only "_id" and "_attachments" are specific metadata keys, other one can be
* added without loss.
*
* @class RamStorage
*/
function
ramStorage
(
spec
,
my
)
{
var
that
,
priv
=
{},
ramstorage
;
that
=
my
.
basicStorage
(
spec
,
my
);
/*
* Wrapper for the localStorage used to simplify instion of any kind of
* values
*/
ramstorage
=
{
getItem
:
function
(
item
)
{
var
value
=
storage
[
item
];
return
value
===
undefined
?
null
:
JSON
.
parse
(
value
);
},
setItem
:
function
(
item
,
value
)
{
storage
[
item
]
=
JSON
.
stringify
(
value
);
},
removeItem
:
function
(
item
)
{
delete
storage
[
item
];
}
};
// attributes
if
(
typeof
spec
.
namespace
!==
'
string
'
)
{
priv
.
namespace
=
'
default
'
;
}
else
{
priv
.
namespace
=
spec
.
namespace
;
}
// ===================== overrides ======================
that
.
specToStore
=
function
()
{
return
{
"
namespace
"
:
priv
.
namespace
};
};
that
.
validateState
=
function
()
{
return
''
;
};
// ==================== commands ====================
/**
* Create a document in local storage.
* @method post
* @param {object} command The JIO command
*/
that
.
post
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
,
doc_id
=
command
.
getDocId
();
if
(
!
doc_id
)
{
doc_id
=
generateUuid
();
}
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
doc_id
);
if
(
doc
===
null
)
{
// the document does not exist
doc
=
command
.
cloneDoc
();
doc
.
_id
=
doc_id
;
delete
doc
.
_attachments
;
ramstorage
.
setItem
(
priv
.
namespace
+
"
/
"
+
doc_id
,
doc
);
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
doc_id
});
}
else
{
// the document already exists
that
.
error
({
"
status
"
:
409
,
"
statusText
"
:
"
Conflicts
"
,
"
error
"
:
"
conflicts
"
,
"
message
"
:
"
Cannot create a new document
"
,
"
reason
"
:
"
Document already exists
"
});
}
});
};
/**
* Create or update a document in local storage.
* @method put
* @param {object} command The JIO command
*/
that
.
put
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
,
tmp
;
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
if
(
doc
===
null
)
{
// the document does not exist
doc
=
command
.
cloneDoc
();
delete
doc
.
_attachments
;
}
else
{
// the document already exists
tmp
=
command
.
cloneDoc
();
tmp
.
_attachments
=
doc
.
_attachments
;
doc
=
tmp
;
}
// write
ramstorage
.
setItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
(),
doc
);
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
});
});
};
/**
* Add an attachment to a document
* @method putAttachment
* @param {object} command The JIO command
*/
that
.
putAttachment
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
;
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
if
(
doc
===
null
)
{
// the document does not exist
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Impossible to add attachment
"
,
"
reason
"
:
"
Document not found
"
});
return
;
}
// the document already exists
doc
.
_attachments
=
doc
.
_attachments
||
{};
doc
.
_attachments
[
command
.
getAttachmentId
()]
=
{
"
content_type
"
:
command
.
getAttachmentMimeType
(),
"
digest
"
:
"
md5-
"
+
command
.
md5SumAttachmentData
(),
"
length
"
:
command
.
getAttachmentLength
()
};
// upload data
ramstorage
.
setItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
(),
command
.
getAttachmentData
());
// write document
ramstorage
.
setItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
(),
doc
);
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
(),
"
attachment
"
:
command
.
getAttachmentId
()
});
});
};
/**
* Get a document
* @method get
* @param {object} command The JIO command
*/
that
.
get
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
if
(
doc
!==
null
)
{
that
.
success
(
doc
);
}
else
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the document
"
,
"
reason
"
:
"
Document does not exist
"
});
}
});
};
/**
* Get a attachment
* @method getAttachment
* @param {object} command The JIO command
*/
that
.
getAttachment
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
());
if
(
doc
!==
null
)
{
that
.
success
(
doc
);
}
else
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Cannot find the attachment
"
,
"
reason
"
:
"
Attachment does not exist
"
});
}
});
};
/**
* Remove a document
* @method remove
* @param {object} command The JIO command
*/
that
.
remove
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
,
i
,
attachment_list
;
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
attachment_list
=
[];
if
(
doc
!==
null
&&
typeof
doc
===
"
object
"
)
{
if
(
typeof
doc
.
_attachments
===
"
object
"
)
{
// prepare list of attachments
for
(
i
in
doc
.
_attachments
)
{
if
(
doc
.
_attachments
.
hasOwnProperty
(
i
))
{
attachment_list
.
push
(
i
);
}
}
}
}
else
{
return
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
"
Document not found
"
,
"
reason
"
:
"
missing
"
});
}
ramstorage
.
removeItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
// delete all attachments
for
(
i
=
0
;
i
<
attachment_list
.
length
;
i
+=
1
)
{
ramstorage
.
removeItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
()
+
"
/
"
+
attachment_list
[
i
]);
}
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
()
});
});
};
/**
* Remove an attachment
* @method removeAttachment
* @param {object} command The JIO command
*/
that
.
removeAttachment
=
function
(
command
)
{
setTimeout
(
function
()
{
var
doc
,
error
,
i
,
attachment_list
;
error
=
function
(
word
)
{
that
.
error
({
"
status
"
:
404
,
"
statusText
"
:
"
Not Found
"
,
"
error
"
:
"
not_found
"
,
"
message
"
:
word
+
"
not found
"
,
"
reason
"
:
"
missing
"
});
};
doc
=
ramstorage
.
getItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
());
// remove attachment from document
if
(
doc
!==
null
&&
typeof
doc
===
"
object
"
&&
typeof
doc
.
_attachments
===
"
object
"
)
{
if
(
typeof
doc
.
_attachments
[
command
.
getAttachmentId
()]
===
"
object
"
)
{
delete
doc
.
_attachments
[
command
.
getAttachmentId
()];
if
(
priv
.
objectIsEmpty
(
doc
.
_attachments
))
{
delete
doc
.
_attachments
;
}
ramstorage
.
setItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
(),
doc
);
ramstorage
.
removeItem
(
priv
.
namespace
+
"
/
"
+
command
.
getDocId
()
+
"
/
"
+
command
.
getAttachmentId
());
that
.
success
({
"
ok
"
:
true
,
"
id
"
:
command
.
getDocId
(),
"
attachment
"
:
command
.
getAttachmentId
()
});
}
else
{
error
(
"
Attachment
"
);
}
}
else
{
error
(
"
Document
"
);
}
});
};
/**
* Get all filenames belonging to a user from the document index
* @method allDocs
* @param {object} command The JIO command
*/
that
.
allDocs
=
function
(
command
)
{
var
i
,
row
,
path_re
,
rows
=
[],
document_list
,
option
,
document_object
;
document_list
=
[];
path_re
=
new
RegExp
(
"
^
"
+
complex_queries
.
stringEscapeRegexpCharacters
(
priv
.
namespace
)
+
"
/[^/]+$
"
);
option
=
command
.
cloneOption
();
if
(
typeof
complex_queries
!==
"
object
"
||
(
option
.
query
===
undefined
&&
option
.
sort_on
===
undefined
&&
option
.
select_list
===
undefined
&&
option
.
include_docs
===
undefined
))
{
rows
=
[];
for
(
i
in
storage
)
{
if
(
storage
.
hasOwnProperty
(
i
))
{
// filter non-documents
if
(
path_re
.
test
(
i
))
{
row
=
{
"
value
"
:
{}};
row
.
id
=
i
.
split
(
'
/
'
).
slice
(
-
1
)[
0
];
row
.
key
=
row
.
id
;
if
(
command
.
getOption
(
'
include_docs
'
))
{
row
.
doc
=
ramstorage
.
getItem
(
i
);
}
rows
.
push
(
row
);
}
}
}
that
.
success
({
"
rows
"
:
rows
,
"
total_rows
"
:
rows
.
length
});
}
else
{
// create complex query object from returned results
for
(
i
in
storage
)
{
if
(
storage
.
hasOwnProperty
(
i
))
{
if
(
path_re
.
test
(
i
))
{
document_list
.
push
(
ramstorage
.
getItem
(
i
));
}
}
}
option
.
select_list
=
option
.
select_list
||
[];
option
.
select_list
.
push
(
"
_id
"
);
if
(
option
.
include_docs
===
true
)
{
document_object
=
{};
document_list
.
forEach
(
function
(
meta
)
{
document_object
[
meta
.
_id
]
=
meta
;
});
}
complex_queries
.
QueryFactory
.
create
(
option
.
query
||
""
).
exec
(
document_list
,
option
);
document_list
=
document_list
.
map
(
function
(
value
)
{
var
o
=
{
"
id
"
:
value
.
_id
,
"
key
"
:
value
.
_id
};
if
(
option
.
include_docs
===
true
)
{
o
.
doc
=
document_object
[
value
.
_id
];
delete
document_object
[
value
.
_id
];
}
delete
value
.
_id
;
o
.
value
=
value
;
return
o
;
});
that
.
success
({
"
total_rows
"
:
document_list
.
length
,
"
rows
"
:
document_list
});
}
};
return
that
;
}
jIO
.
addStorageType
(
'
ram
'
,
ramStorage
);
}));
test/jio.storage/davstorage.tests.js
deleted
100644 → 0
View file @
3356688e
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, window, test, ok, deepEqual, sinon, expect */
// define([module_name], [dependencies], module);
(
function
(
dependencies
,
module
)
{
"
use strict
"
;
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
return
define
(
dependencies
,
module
);
}
module
(
jIO
,
jio_tests
);
}([
'
jio
'
,
'
jio_tests
'
,
'
davstorage
'
],
function
(
jIO
,
util
)
{
"
use strict
"
;
function
generateTools
()
{
return
{
clock
:
sinon
.
useFakeTimers
(),
spy
:
util
.
ospy
,
tick
:
util
.
otick
};
}
module
(
"
DAVStorage
"
);
test
(
"
Post
"
,
function
()
{
var
o
=
generateTools
(
this
);
o
.
jio
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
url
"
:
"
https://ca-davstorage:8080
"
,
"
auth_type
"
:
"
basic
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
"
pwd
"
});
// post without id
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/[0-9a-fA-F]{4}
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Document not found</h1>
"
]
);
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/[0-9a-fA-F]{4}
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Document updated!</h1>
"
]
);
o
.
spy
(
o
,
"
jobstatus
"
,
"
done
"
,
"
Post without id
"
);
o
.
jio
.
post
({},
{
"
max_retry
"
:
1
},
function
(
err
,
response
)
{
o
.
f
.
apply
(
arguments
);
if
(
response
)
{
ok
(
util
.
isUuid
(
response
.
id
),
"
Uuid should look like
"
+
"
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx :
"
+
response
.
id
);
}
});
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// post document with id
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Document not found</h1>
"
]
);
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Document updated!</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
id
"
:
"
http://100%.json
"
,
"
ok
"
:
true
},
"
Create document with an id
"
);
o
.
jio
.
post
({
"
_id
"
:
"
http://100%.json
"
,
"
title
"
:
"
Hello There
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// post already existant file
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
'
{"_id":"doc1","title":"Hello There"}
'
]
);
o
.
spy
(
o
,
"
status
"
,
405
,
"
Update document previous -> 405
"
);
o
.
jio
.
post
({
"
_id
"
:
"
http://100%.json
"
,
"
title
"
:
"
Hello There Again
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
util
.
closeAndcleanUpJio
(
o
.
jio
);
});
test
(
"
Put
"
,
function
()
{
var
o
=
generateTools
(
this
);
o
.
jio
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
url
"
:
"
https://ca-davstorage:8080
"
,
"
auth_type
"
:
"
basic
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
"
pwd
"
});
// put without id => 20 Id Required
o
.
spy
(
o
,
"
status
"
,
20
,
"
Put without id -> 20
"
);
o
.
jio
.
put
({},
o
.
f
);
o
.
tick
(
o
);
// put non empty document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK1</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
},
"
Create document
"
);
o
.
jio
.
put
({
"
_id
"
:
"
http://100%.json
"
,
"
title
"
:
"
Hi There
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// update document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK!</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
},
"
Update document
"
);
o
.
jio
.
put
({
"
_id
"
:
"
http://100%.json
"
,
"
title
"
:
"
Hi There Again
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// putAttachment without document id => 20 Id Required
o
.
spy
(
o
,
"
status
"
,
20
,
"
PutAttachment without doc id -> 20
"
);
o
.
jio
.
putAttachment
({
"
_attachment
"
:
"
body.html
"
},
o
.
f
);
o
.
tick
(
o
);
// putAttachment without attachment id => 22 Attachment Id Required
o
.
spy
(
o
,
"
status
"
,
22
,
"
PutAttachment without attachment id -> 22
"
);
o
.
jio
.
putAttachment
({
"
_id
"
:
"
http://100%.json
"
},
o
.
f
);
o
.
tick
(
o
);
// putAttachment without underlying document => 404 Not Found
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Not Found</h1>
"
]
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
PutAttachment without document -> 404
"
);
o
.
jio
.
putAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
putattmt2
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// upload attachment
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
'
{"_id":"http://100%.json","title":"Hi There!"}
'
]
);
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json.body_
\\
.html
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK!</h1>
"
]
);
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK!</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
,
"
attachment
"
:
"
body.html
"
},
"
Upload attachment
"
);
o
.
jio
.
putAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
body.html
"
,
"
_mimetype
"
:
"
text/html
"
,
"
_data
"
:
"
<h1>Hi There!!</h1><p>How are you?</p>
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
util
.
closeAndcleanUpJio
(
o
.
jio
);
});
test
(
"
Get
"
,
function
()
{
var
o
=
generateTools
(
this
);
o
.
jio
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
url
"
:
"
https://ca-davstorage:8080
"
,
"
auth_type
"
:
"
basic
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
"
pwd
"
});
// get inexistent document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Not Found</h1>
"
]
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get non existing document -> 404
"
);
o
.
jio
.
get
({
"
_id
"
:
"
http://100%.json
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// get document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
'
{"_id":"http://100%.json","title":"Hi There!"}
'
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
_id
"
:
"
http://100%.json
"
,
"
title
"
:
"
Hi There!
"
},
"
Get document
"
);
o
.
jio
.
get
({
"
_id
"
:
"
http://100%.json
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// get inexistent attachment
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json
\\
.body_
\\
.html
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Not Found</h1>
"
]
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Get inexistent attachment -> 404
"
);
o
.
jio
.
getAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
body.html
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// get attachment
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json
\\
.body_
\\
.html
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
My Attachment Content
"
]
);
o
.
spy
(
o
,
"
value
"
,
"
My Attachment Content
"
,
"
Get attachment
"
);
o
.
jio
.
getAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
body.html
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
util
.
closeAndcleanUpJio
(
o
.
jio
);
});
test
(
"
Remove
"
,
function
()
{
var
o
=
generateTools
(
this
);
o
.
jio
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
url
"
:
"
https://ca-davstorage:8080
"
,
"
auth_type
"
:
"
basic
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
"
pwd
"
});
// remove inexistent document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
404
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>Not Found</h1>
"
]
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove inexistent document -> 404
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
http://100%.json
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// remove document
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
{My corrupted document}
"
]
);
o
.
server
.
respondWith
(
"
DELETE
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
<h1>Deleted</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
},
"
Remove document
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
http://100%.json
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// remove inexistent attachment
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
{}
"
]
);
o
.
spy
(
o
,
"
status
"
,
404
,
"
Remove inexistent attachment -> 404
"
);
o
.
jio
.
removeAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
body.html
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
// o.server.respond();
// o.server.respond();
o
.
server
.
restore
();
// remove attachment
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
JSON
.
stringify
({
"
_attachments
"
:
{
"
body.html
"
:
{
"
length
"
:
32
,
"
digest
"
:
"
md5-dontcare
"
,
"
content_type
"
:
"
text/html
"
}
}
})
]
);
o
.
server
.
respondWith
(
"
PUT
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK</h1>
"
]
);
o
.
server
.
respondWith
(
"
DELETE
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json.body_
\\
.html
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
"
<h1>OK</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
,
"
attachment
"
:
"
body.html
"
},
"
Remove attachment
"
);
o
.
jio
.
removeAttachment
({
"
_id
"
:
"
http://100%.json
"
,
"
_attachment
"
:
"
body.html
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// remove document with multiple attachments
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/html
"
},
JSON
.
stringify
({
"
_attachments
"
:
{
"
body.html
"
:
{
"
length
"
:
32
,
"
digest
"
:
"
md5-dontcare
"
,
"
content_type
"
:
"
text/html
"
},
"
other
"
:
{
"
length
"
:
3
,
"
digest
"
:
"
md5-dontcare-again
"
,
"
content_type
"
:
"
text/plain
"
}
}
})
]
);
o
.
server
.
respondWith
(
"
DELETE
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
<h1>Deleted</h1>
"
]
);
o
.
server
.
respondWith
(
"
DELETE
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json
\\
.body_
\\
.html
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
<h1>Deleted</h1>
"
]
);
o
.
server
.
respondWith
(
"
DELETE
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
+
"
http:%252F%252F100%2525_
\\
.json
\\
.other
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
"
<h1>Deleted</h1>
"
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
ok
"
:
true
,
"
id
"
:
"
http://100%.json
"
},
"
Remove document containing multiple attachments
"
);
o
.
jio
.
remove
({
"
_id
"
:
"
http://100%.json
"
},
{
"
max_retry
"
:
1
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
util
.
closeAndcleanUpJio
(
o
.
jio
);
});
test
(
"
AllDocs
"
,
function
()
{
// need to make server requests before activating fakeServer
var
davlist
,
o
=
generateTools
();
davlist
=
"
<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?> <D:multist
"
+
"
atus xmlns:D=
\"
DAV:
\"
> <D:response xmlns:lp1=
\"
DAV:
\"
xmlns:lp2
"
+
"
=
\"
http://apache.org/dav/props/
\"
> <D:href>/some/path/</D:href>
"
+
"
<D:propstat> <D:prop> <lp1:resourcetype><D:collection/></lp1:r
"
+
"
esourcetype> <lp1:creationdate>2012-05-02T12:48:33Z</lp1:creati
"
+
"
ondate> <lp1:getlastmodified>Wed, 02 May 2012 12:48:33 GMT</lp1
"
+
"
:getlastmodified> <lp1:getetag>
\"
1000-4bf0d1aeb9e43
\"
</lp1:gete
"
+
"
tag> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/
"
+
"
></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockent
"
+
"
ry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:loc
"
+
"
ktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock>
"
+
"
<D:lockdiscovery/> <D:getcontenttype>httpd/unix-directory</D:g
"
+
"
etcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> <
"
+
"
/D:propstat> </D:response> <D:response xmlns:lp1=
\"
DAV:
\"
xmlns
"
+
"
:lp2=
\"
http://apache.org/dav/props/
\"
> <D:href>/some/path/http:
"
+
"
%252F%252F100%2525_.json</D:href> <D:propstat> <D:prop> <lp1:re
"
+
"
sourcetype/> <lp1:creationdate>2012-05-02T12:48:31Z</lp1:creati
"
+
"
ondate> <lp1:getcontentlength>201</lp1:getcontentlength> <lp1:g
"
+
"
etlastmodified>Wed, 02 May 2012 12:48:27 GMT</lp1:getlastmodifi
"
+
"
ed> <lp1:getetag>
\"
c9-4bf0d1a845df9
\"
</lp1:getetag> <lp2:execut
"
+
"
able>F</lp2:executable> <D:supportedlock> <D:lockentry> <D:lock
"
+
"
scope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:lo
"
+
"
cktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></
"
+
"
D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry>
"
+
"
</D:supportedlock> <D:lockdiscovery/> </D:prop> <D:status>HTTP
"
+
"
/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response
"
+
"
xmlns:lp1=
\"
DAV:
\"
xmlns:lp2=
\"
http://apache.org/dav/props/
\"
>
"
+
"
<D:href>/some/path/ISBN:1038729410372</D:href> <D:propstat> <D:
"
+
"
prop> <lp1:resourcetype/> <lp1:creationdate>2012-05-01T17:41:13
"
+
"
Z</lp1:creationdate> <lp1:getcontentlength>223</lp1:getcontentl
"
+
"
ength> <lp1:getlastmodified>Wed, 02 May 2012 10:48:33 GMT</lp1:
"
+
"
getlastmodified> <lp1:getetag>
\"
c9-4bf0d1aeb9e43
\"
</lp1:getetag
"
+
"
> <lp2:executable>F</lp2:executable> <D:supportedlock> <D:locke
"
+
"
ntry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:
"
+
"
write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope>
"
+
"
<D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> <
"
+
"
/D:lockentry> </D:supportedlock> <D:lockdiscovery/> </D:prop> <
"
+
"
D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response>
"
+
"
<D:response xmlns:lp1=
\"
DAV:
\"
xmlns:lp2=
\"
http://apache.org/d
"
+
"
av/props/
\"
> <D:href>/some/path/http:%252F%252F100%2525_.json.b
"
+
"
ody_.html</D:href> <D:propstat> <D:prop> <lp1:resourcetype/> <l
"
+
"
p1:creationdate>2012-05-01T17:41:13Z</lp1:creationdate> <lp1:ge
"
+
"
tcontentlength>223</lp1:getcontentlength> <lp1:getlastmodified>
"
+
"
Wed, 02 May 2012 10:48:33 GMT</lp1:getlastmodified> <lp1:geteta
"
+
"
g>
\"
c9-4bf0d1aeb9e43
\"
</lp1:getetag> <lp2:executable>F</lp2:exe
"
+
"
cutable> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclus
"
+
"
ive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:loc
"
+
"
kentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D
"
+
"
:locktype><D:write/></D:locktype> </D:lockentry> </D:supportedl
"
+
"
ock> <D:lockdiscovery/> </D:prop> <D:status>HTTP/1.1 200 OK</D:
"
+
"
status> </D:propstat> </D:response> </D:multistatus>
"
;
o
.
jio
=
jIO
.
newJio
({
"
type
"
:
"
dav
"
,
"
url
"
:
"
https://ca-davstorage:8080
"
,
"
auth_type
"
:
"
basic
"
,
"
username
"
:
"
admin
"
,
"
password
"
:
"
pwd
"
});
// get all documents
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
PROPFIND
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
),
[
200
,
{
"
Content-Type
"
:
"
text/xml
"
},
davlist
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
rows
"
:
[
{
"
id
"
:
"
http://100%.json
"
,
"
key
"
:
"
http://100%.json
"
,
"
value
"
:
{}},
{
"
id
"
:
"
ISBN:1038729410372
"
,
"
key
"
:
"
ISBN:1038729410372
"
,
"
value
"
:
{}}
],
"
total_rows
"
:
2
},
"
allDocs
"
);
o
.
jio
.
allDocs
(
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
// allDocs with option include_docs
o
.
server
=
sinon
.
fakeServer
.
create
();
o
.
server
.
respondWith
(
"
PROPFIND
"
,
new
RegExp
(
"
https://ca-davstorage:8080/
"
),
[
200
,
{
"
Content-Type
"
:
"
text/xml
"
},
davlist
]
);
o
.
doc1
=
{
"
_id
"
:
"
http://100%.json
"
,
"
_attachments
"
:
{
"
body.html
"
:
{
"
length
"
:
32
,
"
digest
"
:
"
md5-doncare
"
,
"
content_type
"
:
"
text/html
"
}
}};
o
.
doc2
=
{
"
_id
"
:
"
ISBN:1038729410372
"
,
"
title
"
:
"
Book Title
"
};
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/http:%252F%252F100%2525_
\\
.json
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
JSON
.
stringify
(
o
.
doc1
)
]
);
o
.
server
.
respondWith
(
"
GET
"
,
new
RegExp
(
"
https://ca-davstorage:8080/ISBN:1038729410372
"
),
[
200
,
{
"
Content-Type
"
:
"
text/plain
"
},
JSON
.
stringify
(
o
.
doc2
)
]
);
o
.
spy
(
o
,
"
value
"
,
{
"
rows
"
:
[{
"
id
"
:
"
http://100%.json
"
,
"
key
"
:
"
http://100%.json
"
,
"
value
"
:
{},
"
doc
"
:
o
.
doc1
},
{
"
id
"
:
"
ISBN:1038729410372
"
,
"
key
"
:
"
ISBN:1038729410372
"
,
"
value
"
:
{},
"
doc
"
:
o
.
doc2
}],
"
total_rows
"
:
2
},
"
allDocs (include_docs)
"
);
o
.
jio
.
allDocs
({
"
include_docs
"
:
true
},
o
.
f
);
o
.
clock
.
tick
(
1000
);
o
.
server
.
respond
();
o
.
tick
(
o
);
o
.
server
.
restore
();
util
.
closeAndcleanUpJio
(
o
.
jio
);
});
}));
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment