Skip to content

Commit c4c98cb

Browse files
authored
Merge pull request #26 from evolvedbinary/feature/modify-resource-properties
Add a facility for modifying the properties of Documents and Collections
2 parents 61147e7 + 601027b commit c4c98cb

File tree

8 files changed

+595
-27
lines changed

8 files changed

+595
-27
lines changed

src/main/xar-resources/api.xqm

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import module namespace doc = "http://fusiondb.com/ns/studio/api/document" at "m
3333
import module namespace exp = "http://fusiondb.com/ns/studio/api/explorer" at "modules/explorer.xqm";
3434
import module namespace hsc = "https://tools.ietf.org/html/rfc2616#section-10" at "modules/http-status-codes.xqm";
3535
import module namespace idx = "http://fusiondb.com/ns/studio/api/index" at "modules/index.xqm";
36-
import module namespace jx = "http://joewiz.org/ns/xquery/json-xml" at "modules/json-xml.xqm";
3736
import module namespace mul = "http://fusiondb.com/ns/studio/api/multipart" at "modules/multipart.xqm";
3837
import module namespace perr = "http://fusiondb.com/ns/studio/api/error" at "modules/error.xqm";
3938
import module namespace prxq = "http://fusiondb.com/ns/studio/api/restxq" at "modules/restxq.xqm";
@@ -232,6 +231,52 @@ function api:put-document($uri, $copy-source, $move-source, $media-type, $body)
232231
})
233232
};
234233

234+
declare
235+
%rest:POST("{$body}")
236+
%rest:path("/fusiondb/document")
237+
%rest:query-param("uri", "{$uri}")
238+
%rest:consumes("application/json")
239+
%rest:produces("application/json")
240+
%output:method("json")
241+
function api:update-document-properties($uri, $body) {
242+
api:with-valid-uri-ex($uri, function($uri) {
243+
if (empty($body))
244+
then
245+
[
246+
map {
247+
"code": $hsc:bad-request,
248+
"reason": "Missing request body"
249+
},
250+
()
251+
]
252+
else
253+
(: TODO explicit xs:string cast below is required due to
254+
a Type error in eXist-db that needs investigating...
255+
UntypedValueCheck.java for $body has atomize=false,
256+
but should be atomize=true.
257+
:)
258+
let $json-txt := util:base64-decode($body cast as xs:string)
259+
let $document-properties := fn:parse-json($json-txt)
260+
return
261+
try {
262+
[
263+
map {
264+
"code": if (doc:update-properties($uri, $document-properties)) then $hsc:no-content else $hsc:not-found
265+
},
266+
()
267+
]
268+
} catch perr:PD001 {
269+
[
270+
map {
271+
"code": $hsc:forbidden,
272+
"reason": $err:description
273+
},
274+
()
275+
]
276+
}
277+
})
278+
};
279+
235280
declare
236281
%rest:DELETE
237282
%rest:path("/fusiondb/document")
@@ -322,6 +367,52 @@ function api:put-collection($uri, $copy-source, $move-source) {
322367
})
323368
};
324369

370+
declare
371+
%rest:POST("{$body}")
372+
%rest:path("/fusiondb/collection")
373+
%rest:query-param("uri", "{$uri}")
374+
%rest:consumes("application/json")
375+
%rest:produces("application/json")
376+
%output:method("json")
377+
function api:update-collection-properties($uri, $body) {
378+
api:with-valid-uri-ex($uri, function($uri) {
379+
if (empty($body))
380+
then
381+
[
382+
map {
383+
"code": $hsc:bad-request,
384+
"reason": "Missing request body"
385+
},
386+
()
387+
]
388+
else
389+
(: TODO explicit xs:string cast below is required due to
390+
a Type error in eXist-db that needs investigating...
391+
UntypedValueCheck.java for $body has atomize=false,
392+
but should be atomize=true.
393+
:)
394+
let $json-txt := util:base64-decode($body cast as xs:string)
395+
let $collection-properties := fn:parse-json($json-txt)
396+
return
397+
try {
398+
[
399+
map {
400+
"code": if (col:update-properties($uri, $collection-properties)) then $hsc:no-content else $hsc:not-found
401+
},
402+
()
403+
]
404+
} catch perr:PD001 {
405+
[
406+
map {
407+
"code": $hsc:forbidden,
408+
"reason": $err:description
409+
},
410+
()
411+
]
412+
}
413+
})
414+
};
415+
325416
declare
326417
%rest:DELETE
327418
%rest:path("/fusiondb/collection")

src/main/xar-resources/modules/collection.xqm

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,55 @@ declare function col:put($uri as xs:string) as xs:string {
3737
perr:error($perr:PD001, $uri)
3838
};
3939

40+
41+
declare function col:update-properties($uri as xs:string, $collection-properties as map(xs:string, item())) as xs:boolean {
42+
if (xmldb:collection-available($uri)) then
43+
if (sm:has-access(xs:anyURI($uri), "r--")
44+
and ut:is-current-user(sm:get-permissions(xs:anyURI($uri))/sm:permission/@owner))
45+
then
46+
(: update collection properties :)
47+
(
48+
let $_ :=
49+
if ($collection-properties?mode)
50+
then
51+
sm:chmod(xs:anyURI($uri), $collection-properties?mode)
52+
else()
53+
let $_ :=
54+
if ($collection-properties?acl)
55+
then
56+
let $_ := sm:clear-acl(xs:anyURI($uri))
57+
let $_ := array:for-each($collection-properties?acl, function($ace) {
58+
let $f := if ($ace?target eq "USER")
59+
then
60+
sm:add-user-ace#4
61+
else
62+
sm:add-group-ace#4
63+
return
64+
$f(xs:anyURI($uri), $ace?who, $ace?accessType eq "ALLOWED", $ace?mode)
65+
66+
})
67+
return
68+
()
69+
else()
70+
let $_ :=
71+
if ($collection-properties?group)
72+
then
73+
sm:chgrp(xs:anyURI($uri), $collection-properties?group)
74+
else()
75+
let $_ :=
76+
if ($collection-properties?owner)
77+
then
78+
sm:chown(xs:anyURI($uri), $collection-properties?owner)
79+
else()
80+
return
81+
true()
82+
)
83+
else
84+
perr:error($perr:PD001, $uri)
85+
else
86+
false()
87+
};
88+
4089
declare function col:delete($uri as xs:string) as xs:boolean {
4190
if (xmldb:collection-available($uri))
4291
then

src/main/xar-resources/modules/document.xqm

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ declare
7777
%private
7878
function doc:store($collection-uri as xs:string, $doc-name as xs:string, $content) {
7979
if (sm:has-access(xs:anyURI($collection-uri), "w")) then
80-
let $_ := util:log("INFO", ("ABOUT TO STORE=" || $collection-uri || "/" || $doc-name)) return
81-
80+
8281
(: NOTE we don't explicitly specify the media-type from the
8382
request here, instead we let eXist-db figure it out :)
8483

@@ -104,6 +103,63 @@ function doc:store($collection-uri as xs:string, $doc-name as xs:string, $conten
104103
perr:error($perr:PD001, $collection-uri || "/" || $doc-name)
105104
};
106105

106+
declare function doc:update-properties($uri as xs:string, $document-properties as map(xs:string, item())) as xs:boolean {
107+
if (ut:doc-available($uri)) then
108+
let $collection-uri := ut:parent-path($uri)
109+
let $doc-name := ut:last-path-component($uri)
110+
return
111+
if (sm:has-access(xs:anyURI($uri), "r--")
112+
and sm:has-access(xs:anyURI($collection-uri), "r-x")
113+
and ut:is-current-user(sm:get-permissions(xs:anyURI($uri))/sm:permission/@owner))
114+
then
115+
(: update document properties :)
116+
(
117+
let $_ :=
118+
if ($document-properties?mediaType)
119+
then
120+
xmldb:set-mime-type(xs:anyURI($uri), $document-properties?mediaType)
121+
else()
122+
let $_ :=
123+
if ($document-properties?mode)
124+
then
125+
sm:chmod(xs:anyURI($uri), $document-properties?mode)
126+
else()
127+
let $_ :=
128+
if ($document-properties?acl)
129+
then
130+
let $_ := sm:clear-acl(xs:anyURI($uri))
131+
let $_ := array:for-each($document-properties?acl, function($ace) {
132+
let $f := if ($ace?target eq "USER")
133+
then
134+
sm:add-user-ace#4
135+
else
136+
sm:add-group-ace#4
137+
return
138+
$f(xs:anyURI($uri), $ace?who, $ace?accessType eq "ALLOWED", $ace?mode)
139+
140+
})
141+
return
142+
()
143+
else()
144+
let $_ :=
145+
if ($document-properties?group)
146+
then
147+
sm:chgrp(xs:anyURI($uri), $document-properties?group)
148+
else()
149+
let $_ :=
150+
if ($document-properties?owner)
151+
then
152+
sm:chown(xs:anyURI($uri), $document-properties?owner)
153+
else()
154+
return
155+
true()
156+
)
157+
else
158+
perr:error($perr:PD001, $uri)
159+
else
160+
false()
161+
};
162+
107163
declare function doc:delete($uri as xs:string) as xs:boolean {
108164
if (ut:doc-available($uri)) then
109165
let $collection-uri := ut:parent-path($uri)

src/main/xar-resources/modules/explorer.xqm

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,36 +64,63 @@ function exp:describe-collection($uri) as map(xs:string, xs:string) {
6464

6565
declare
6666
%private
67-
function exp:collection-properties($uri) as map(xs:string, xs:string) {
68-
map:merge((
69-
exp:common-resource-properties($uri),
70-
map {
71-
"created": xmldb:created($uri)
72-
}
73-
))
74-
};
75-
76-
declare
77-
%private
78-
function exp:describe-document($uri) as map(xs:string, item()) {
79-
let $collection-uri := ut:parent-path($uri)
80-
let $doc-name := ut:last-path-component($uri)
67+
function exp:collection-properties($uri) as map(xs:string, xs:string)? {
68+
(:
69+
TODO the need for the sm:has-access check below is likely
70+
a bug. I think reading the properties of the collection should
71+
not require read access to the collection as the collection
72+
properties are stored in the Collection entry... check what
73+
Unix does!
8174
82-
let $last-modified := xmldb:last-modified($collection-uri, $doc-name)
83-
let $media-type := xmldb:get-mime-type($uri)
84-
let $is-binary-doc := util:is-binary-doc($uri)
85-
let $size := xmldb:size($collection-uri, $doc-name)
86-
return
75+
It seems especially strange... as xmldb:get-child-collections
76+
is able to read the collection entries without needing
77+
read access on each collection!
78+
:)
79+
if (sm:has-access(xs:anyURI($uri), "r--"))
80+
then
8781
map:merge((
8882
exp:common-resource-properties($uri),
8983
map {
90-
"created": xmldb:created($collection-uri, $doc-name),
91-
"lastModified": $last-modified,
92-
"mediaType": $media-type,
93-
"binaryDoc": $is-binary-doc,
94-
"size": $size
84+
"created": xmldb:created($uri)
9585
}
9686
))
87+
else()
88+
};
89+
90+
declare
91+
%private
92+
function exp:describe-document($uri) as map(xs:string, item())? {
93+
(:
94+
TODO the need for the sm:has-access check below is likely
95+
a bug. I think reading the properties of the document should
96+
not require read access to the document as the document
97+
properties are stored in the Collection entry... check what
98+
Unix does!
99+
100+
It seems especially strange... as xmldb:get-child-resources
101+
is able to read the collection entries without needing
102+
read access on each document!
103+
:)
104+
if (sm:has-access(xs:anyURI($uri), "r--"))
105+
then
106+
let $collection-uri := ut:parent-path($uri)
107+
let $doc-name := ut:last-path-component($uri)
108+
let $last-modified := xmldb:last-modified($collection-uri, $doc-name)
109+
let $media-type := xmldb:get-mime-type($uri)
110+
let $is-binary-doc := util:is-binary-doc($uri)
111+
let $size := xmldb:size($collection-uri, $doc-name)
112+
return
113+
map:merge((
114+
exp:common-resource-properties($uri),
115+
map {
116+
"created": xmldb:created($collection-uri, $doc-name),
117+
"lastModified": $last-modified,
118+
"mediaType": $media-type,
119+
"binaryDoc": $is-binary-doc,
120+
"size": $size
121+
}
122+
))
123+
else()
97124
};
98125

99126
declare

src/test/java/com/fusiondb/studio/api/API.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,13 @@ static boolean testServerHasBadJsonSerialization() {
166166
|| dockerTestImage.endsWith("existdb:5.0.0")
167167
|| dockerTestImage.endsWith("existdb:5.2.0");
168168
}
169+
170+
static boolean testServerHasBadXmldbSetMimeType() {
171+
final String dockerTestImage = envVarOrDefault(ENV_VAR_DOCKER_TEST_IMAGE, null, envVarValue -> envVarValue);
172+
if (dockerTestImage == null || dockerTestImage.isEmpty()) {
173+
return false;
174+
}
175+
176+
return dockerTestImage.endsWith("fusiondb-server:1.0.0-ALPHA2");
177+
}
169178
}

0 commit comments

Comments
 (0)