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
Xiaowu Zhang
jio
Commits
0c33f817
Commit
0c33f817
authored
Oct 30, 2013
by
Tristan Cavelier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
check and repair added to davstorage.js
parent
c49462b8
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
468 additions
and
4 deletions
+468
-4
src/jio.storage/davstorage.js
src/jio.storage/davstorage.js
+330
-0
test/jio.storage/davstorage.tests.js
test/jio.storage/davstorage.tests.js
+138
-4
No files found.
src/jio.storage/davstorage.js
View file @
0c33f817
...
...
@@ -112,6 +112,46 @@
}
exports
.
createDescription
=
createDescription
;
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called
* with no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
function
sequence
(
thens
)
{
var
promises
=
[];
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
,
notify
)
{
var
i
;
promises
[
0
]
=
new
RSVP
.
Promise
(
function
(
resolve
)
{
resolve
();
});
for
(
i
=
0
;
i
<
thens
.
length
;
i
+=
1
)
{
if
(
Array
.
isArray
(
thens
[
i
]))
{
promises
[
i
+
1
]
=
promises
[
i
].
then
(
thens
[
i
][
0
],
thens
[
i
][
1
],
thens
[
i
][
2
]);
}
else
{
promises
[
i
+
1
]
=
promises
[
i
].
then
(
thens
[
i
]);
}
}
promises
[
i
].
then
(
resolve
,
reject
,
notify
);
},
function
()
{
var
i
;
for
(
i
=
0
;
i
<
promises
.
length
;
i
+=
1
)
{
promises
[
i
].
cancel
();
}
});
}
/**
* Changes spaces to %20, / to %2f, % to %25 and ? to %3f
*
...
...
@@ -886,6 +926,296 @@
then
(
o
.
success
,
o
.
reject
,
o
.
notifyProgress
);
};
/**
* Check the storage or a specific document
*
* @method check
* @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} options The command options
*/
DavStorage
.
prototype
.
check
=
function
(
command
,
param
)
{
this
.
genericRepair
(
command
,
param
,
false
);
};
/**
* Repair the storage or a specific document
*
* @method repair
* @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} options The command options
*/
DavStorage
.
prototype
.
repair
=
function
(
command
,
param
)
{
this
.
genericRepair
(
command
,
param
,
true
);
};
/**
* A generic method that manage check or repair command
*
* @method genericRepair
* @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Boolean} repair If true then repair else just check
*/
DavStorage
.
prototype
.
genericRepair
=
function
(
command
,
param
,
repair
)
{
var
that
=
this
,
repair_promise
,
command_promise
;
// returns a jio object
function
getAllFile
()
{
return
sequence
([
function
()
{
return
ajax
[
that
.
_auth_type
](
"
PROPFIND
"
,
"
text
"
,
that
.
_url
+
'
/
'
,
null
,
that
.
_login
);
},
[
function
(
e
)
{
// on success
var
i
,
length
,
rows
=
new
DOMParser
().
parseFromString
(
e
.
target
.
responseText
,
"
text/xml
"
).
querySelectorAll
(
"
D
\\
:response, response
"
);
if
(
rows
.
length
===
1
)
{
return
{
"
status
"
:
200
,
"
data
"
:
[]};
}
// exclude parent folder and browse
rows
=
[].
slice
.
call
(
rows
);
rows
.
shift
();
length
=
rows
.
length
;
for
(
i
=
0
;
i
<
length
;
i
+=
1
)
{
rows
[
i
]
=
rows
[
i
].
querySelector
(
"
D
\\
:href, href
"
).
textContent
.
split
(
'
/
'
).
slice
(
-
1
)[
0
];
}
return
{
"
data
"
:
rows
,
"
status
"
:
200
};
// rows -> [
// 'file_path_1',
// ...
// ]
},
function
(
e
)
{
// on error
// convert into jio error object
// then propagate
throw
{
"
status
"
:
e
.
target
.
status
,
"
reason
"
:
e
.
target
.
statusText
};
}]]);
}
// returns jio object
function
repairOne
(
shared
,
repair
)
{
var
modified
=
false
,
document_id
=
shared
.
_id
;
return
sequence
([
function
()
{
return
that
.
_get
({
"
_id
"
:
document_id
});
},
[
function
(
event
)
{
var
attachment_id
,
metadata
=
event
.
target
.
response
;
// metadata should be an object
if
(
typeof
metadata
!==
'
object
'
||
metadata
===
null
||
Array
.
isArray
(
metadata
))
{
if
(
!
repair
)
{
throw
{
"
status
"
:
"
conflict
"
,
"
reason
"
:
"
corrupted
"
,
"
message
"
:
"
Bad metadata found in document
\"
"
+
document_id
+
"
\"
"
};
}
return
{};
}
// check metadata content
if
(
!
repair
)
{
if
(
!
(
new
jIO
.
Metadata
(
metadata
).
check
()))
{
return
{
"
status
"
:
"
conflict
"
,
"
reason
"
:
"
corrupted
"
,
"
message
"
:
"
Some metadata might be lost
"
};
}
}
else
{
modified
=
(
jIO
.
util
.
uniqueJSONStringify
(
metadata
)
!==
jIO
.
util
.
uniqueJSONStringify
(
new
jIO
.
Metadata
(
metadata
).
format
().
_dict
)
);
}
// check metadata id
if
(
metadata
.
_id
!==
document_id
)
{
// metadata id is different than file
// this is not a critical thing
modified
=
true
;
metadata
.
_id
=
document_id
;
}
// check attachment metadata container
if
(
metadata
.
_attachments
&&
(
typeof
metadata
.
_attachments
!==
'
object
'
||
Array
.
isArray
(
metadata
.
_attachments
)))
{
// is not undefined nor object
if
(
!
repair
)
{
throw
{
"
status
"
:
"
conflict
"
,
"
reason
"
:
"
corrupted
"
,
"
message
"
:
"
Bad attachment metadata found in document
\"
"
+
document_id
+
"
\"
"
};
}
delete
metadata
.
_attachments
;
modified
=
true
;
}
// check every attachment metadata
if
(
metadata
.
_attachments
)
{
for
(
attachment_id
in
metadata
.
_attachments
)
{
if
(
metadata
.
_attachments
.
hasOwnProperty
(
attachment_id
))
{
// check attachment metadata type
if
(
typeof
metadata
.
_attachments
[
attachment_id
]
!==
'
object
'
||
metadata
.
_attachments
[
attachment_id
]
===
null
||
Array
.
isArray
(
metadata
.
_attachments
[
attachment_id
]))
{
// is not object
if
(
!
repair
)
{
throw
{
"
status
"
:
"
conflict
"
,
"
reason
"
:
"
corrupted
"
,
"
message
"
:
"
Bad attachment metadata found in document
\"
"
+
document_id
+
"
\"
, attachment
\"
"
+
attachment_id
+
"
\"
"
};
}
metadata
.
_attachments
[
attachment_id
]
=
{};
modified
=
true
;
}
// check attachment existency if all attachment are listed
if
(
shared
.
referenced_dict
)
{
if
(
shared
.
unreferenced_dict
[
metadata
.
_id
]
&&
shared
.
unreferenced_dict
[
metadata
.
_id
][
attachment_id
])
{
// attachment seams to exist but is not referenced
shared
.
referenced_dict
[
metadata
.
_id
]
=
shared
.
referenced_dict
[
metadata
.
_id
]
||
{};
shared
.
referenced_dict
[
metadata
.
_id
][
attachment_id
]
=
true
;
delete
shared
.
unreferenced_dict
[
metadata
.
_id
][
attachment_id
];
}
else
if
(
!
(
shared
.
referenced_dict
[
metadata
.
_id
]
&&
shared
.
referenced_dict
[
metadata
.
_id
][
attachment_id
])
)
{
// attachment doesn't exist, remove attachment id
if
(
!
repair
)
{
throw
{
"
status
"
:
"
conflict
"
,
"
reason
"
:
"
attachment missing
"
,
"
message
"
:
"
Attachment
\"
"
+
attachment_id
+
"
\"
from document
\"
"
+
document_id
+
"
\"
is missing
"
};
}
delete
metadata
.
_attachments
[
attachment_id
];
modified
=
true
;
}
}
}
}
}
return
{
"
modified
"
:
modified
,
"
metadata
"
:
metadata
};
},
function
(
event
)
{
// on error
// convert into jio error object
// then propagate
throw
{
"
status
"
:
event
.
target
.
status
,
"
reason
"
:
event
.
target
.
statustext
};
}],
function
(
dict
)
{
if
(
dict
.
modified
)
{
return
this
.
_put
(
dict
.
metadata
);
}
return
null
;
},
function
()
{
return
"
no_content
"
;
}]);
}
// returns jio object
function
repairAll
(
shared
,
repair
)
{
return
sequence
([
function
()
{
return
getAllFile
();
},
function
(
answer
)
{
var
index
,
data
=
answer
.
data
,
length
=
data
.
length
,
id_list
,
document_list
=
[];
for
(
index
=
0
;
index
<
length
;
index
+=
1
)
{
// parsing all files
id_list
=
fileNameToIds
(
data
[
index
]);
if
(
id_list
.
length
===
1
)
{
// this is a document
document_list
[
document_list
.
length
]
=
id_list
[
0
];
}
else
if
(
id_list
.
length
===
2
)
{
// this is an attachment
// reference it
shared
.
unreferenced_dict
[
id_list
[
0
]]
=
shared
.
unreferenced_dict
[
id_list
[
0
]]
||
{};
shared
.
unreferenced_dict
[
id_list
[
0
]][
id_list
[
1
]]
=
true
;
}
else
{
shared
.
unknown_file_list
.
push
(
data
[
index
]);
}
}
length
=
document_list
.
length
;
for
(
index
=
0
;
index
<
length
;
index
+=
1
)
{
shared
.
_id
=
document_list
[
index
];
document_list
[
index
]
=
repairOne
(
shared
,
repair
);
}
function
fileRemover
(
name
)
{
return
function
()
{
return
ajax
[
that
.
_auth_type
](
"
DELETE
"
,
null
,
that
.
_url
+
'
/
'
+
name
+
"
?_=
"
+
Date
.
now
(),
null
,
that
.
_login
);
};
}
function
errorEventConverter
(
event
)
{
throw
{
"
status
"
:
event
.
target
.
status
,
"
reason
"
:
event
.
target
.
statusText
};
}
length
=
shared
.
unknown_file_list
.
length
;
for
(
index
=
0
;
index
<
length
;
index
+=
1
)
{
document_list
.
push
(
sequence
([
fileRemover
(
shared
.
unknown_file_list
[
index
]),
[
null
,
errorEventConverter
]
]));
}
return
RSVP
.
all
(
document_list
);
},
function
()
{
return
"
no_content
"
;
}]);
}
if
(
typeof
param
.
_id
===
'
string
'
)
{
repair_promise
=
repairOne
(
param
,
repair
);
}
else
{
param
.
referenced_attachment_path_dict
=
{};
param
.
unreferenced_attachment_path_dict
=
{};
param
.
unknown_file_list
=
[];
repair_promise
=
repairAll
(
param
,
repair
);
}
command_promise
=
sequence
([
function
()
{
return
repair_promise
;
},
[
command
.
success
,
command
.
error
]]);
command
.
oncancel
=
function
()
{
command_promise
.
cancel
();
};
};
jIO
.
addStorage
(
'
dav
'
,
DavStorage
);
}));
test/jio.storage/davstorage.tests.js
View file @
0c33f817
...
...
@@ -62,7 +62,7 @@
* X-Requested-With, X-HTTP-Method-Override, Accept, Authorization,
* Depth"
*/
test
(
"
Scenario
"
,
3
0
,
function
()
{
test
(
"
Scenario
"
,
3
2
,
function
()
{
var
server
,
responses
=
[],
shared
=
{},
jio
=
jIO
.
createJIO
(
spec
,
{
"
workspace
"
:
{},
...
...
@@ -218,6 +218,138 @@
},
"
Post specific document
"
);
}
function
checkDocument
()
{
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
b
"
,
"
title
"
:
"
Bee
"
})]);
// GET
return
jio
.
check
({
"
_id
"
:
"
b
"
});
}
function
checkDocumentTest
(
answer
)
{
deepEqual
(
answer
,
{
"
id
"
:
"
b
"
,
"
method
"
:
"
check
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Check specific document
"
);
}
function
checkStorage
()
{
responses
.
push
([
207
,
{
"
Content-Type
"
:
"
text/xml
"
},
'
<?xml version="1.0" encoding="utf-8"?>
'
+
'
<D:multistatus xmlns:D="DAV:">
'
+
'
<D:response xmlns:lp1="DAV:"
'
+
'
xmlns:lp2="http://apache.org/dav/props/">
'
+
'
<D:href>/uploads/</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype><D:collection/></lp1:resourcetype>
'
+
'
<lp1:creationdate>2013-10-30T17:19:46Z</lp1:creationdate>
'
+
'
<lp1:getlastmodified>Wed, 30 Oct 2013 17:19:46 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"240be-1000-4e9f88a305c4e"</lp1:getetag>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<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:getcontenttype>httpd/unix-directory</D:getcontenttype>
'
+
'
</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>/uploads/
'
+
shared
.
created_document_id
+
'
</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype/>
'
+
'
<lp1:creationdate>2013-10-30T17:19:46Z</lp1:creationdate>
'
+
'
<lp1:getcontentlength>66</lp1:getcontentlength>
'
+
'
<lp1:getlastmodified>Wed, 30 Oct 2013 17:19:46 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"20568-42-4e9f88a2ea198"</lp1:getetag>
'
+
'
<lp2:executable>F</lp2:executable>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<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/dav/props/">
'
+
'
<D:href>/uploads/b</D:href>
'
+
'
<D:propstat>
'
+
'
<D:prop>
'
+
'
<lp1:resourcetype/>
'
+
'
<lp1:creationdate>2013-10-30T17:19:46Z</lp1:creationdate>
'
+
'
<lp1:getcontentlength>25</lp1:getcontentlength>
'
+
'
<lp1:getlastmodified>Wed, 30 Oct 2013 17:19:46 GMT
'
+
'
</lp1:getlastmodified>
'
+
'
<lp1:getetag>"21226-19-4e9f88a305c4e"</lp1:getetag>
'
+
'
<lp2:executable>F</lp2:executable>
'
+
'
<D:supportedlock>
'
+
'
<D:lockentry>
'
+
'
<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:multistatus>
'
]);
// PROPFIND
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
shared
.
created_document_id
,
"
title
"
:
"
Unique ID
"
})]);
// GET
responses
.
push
([
200
,
{
"
Content-Type
"
:
"
application/octet-stream
"
},
JSON
.
stringify
({
"
_id
"
:
"
b
"
,
"
title
"
:
"
Bee
"
})]);
// GET
return
jio
.
check
({});
}
function
checkStorageTest
(
answer
)
{
deepEqual
(
answer
,
{
"
method
"
:
"
check
"
,
"
result
"
:
"
success
"
,
"
status
"
:
204
,
"
statusText
"
:
"
No Content
"
},
"
Check storage state
"
);
}
function
listDocuments
()
{
responses
.
push
([
207
,
...
...
@@ -1023,6 +1155,10 @@
then
(
getCreatedDocument
).
then
(
getCreatedDocumentTest
).
// post b 201
then
(
postSpecificDocument
).
then
(
postSpecificDocumentTest
).
// check b 204
then
(
checkDocument
).
then
(
checkDocumentTest
).
// check storage 204
then
(
checkStorage
).
then
(
checkStorageTest
).
// allD 200 2 documents
then
(
listDocuments
).
then
(
list2DocumentsTest
).
// remove a 204
...
...
@@ -1069,9 +1205,7 @@
then
(
getInexistentDocument
).
then
(
getInexistentDocumentTest
).
// remove 404
then
(
removeInexistentDocument
).
then
(
removeInexistentDocumentTest
).
// check 204
//then(checkDocument).done(checkDocumentTest).
//then(checkStorage).done(checkStorageTest).
// end
fail
(
unexpectedError
).
always
(
start
).
always
(
function
()
{
...
...
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