diff --git a/examples/data/props.json b/examples/data/props.json
new file mode 100644
index 0000000..02dd711
--- /dev/null
+++ b/examples/data/props.json
@@ -0,0 +1,4 @@
+{
+ "document-transform-all":false,
+ "document-transform-out":"simpleExtension"
+}
\ No newline at end of file
diff --git a/examples/data/simpleExtension.sjs b/examples/data/simpleExtension.sjs
new file mode 100644
index 0000000..6518f6b
--- /dev/null
+++ b/examples/data/simpleExtension.sjs
@@ -0,0 +1,13 @@
+function metadataFilter(context, params, content) {
+ var mutableDoc = content.toObject();
+ xdmp.log("context");
+ xdmp.log(context);
+ xdmp.log("params");
+ xdmp.log(params);
+ xdmp.log("content");
+ xdmp.log(content);
+ content = xdmp.unquote('hello', null, ["repair-none", "default-language=en"]);
+ return content;
+};
+
+exports.transform = metadataFilter;
\ No newline at end of file
diff --git a/examples/deployFile.py b/examples/deployFile.py
new file mode 100644
index 0000000..2dcd672
--- /dev/null
+++ b/examples/deployFile.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python3
+#
+# Copyright 2016 MarkLogic Corporation
+#
+# This script provides examples of deploying files to a MarkLogic database without using MLCP
+# This is useful when the Application Servers within MarkLogic have SSL enabled.
+#
+# For example:
+#
+# python3 deployFile
+
+__author__ = 'pmb'
+
+import argparse
+import os
+import requests
+from requests.auth import HTTPDigestAuth
+from marklogic.connection import Connection
+from restloader import RESTLoader
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--host", action='store', default="192.168.200.162",
+ help="Management API host")
+parser.add_argument("--restPort", action='store', default="8000",
+ help="REST port for modules DB")
+parser.add_argument("--protocol", action='store', default="http",
+ help="http or https")
+parser.add_argument("--username", action='store', default="admin",
+ help="User name")
+parser.add_argument("--password", action='store', default="admin",
+ help="Password")
+parser.add_argument("--source", action='store', default="data",
+ help="file or root directory to deploy")
+parser.add_argument("--targetUri", action='store', default="/app",
+ help="root path for the files in MarkLogic")
+parser.add_argument("--certificate", action='store', default=None,
+ help="root path for the files in MarkLogic")
+parser.add_argument("--database", action='store', default=None,
+ help="root path for the files in MarkLogic")
+parser.add_argument("--permissions", action='store', default=True,
+ help="Permissions for the files in MarkLogic")
+args = parser.parse_args()
+
+source = args.source
+targetUri = args.targetUri
+
+conn = Connection(args.host, HTTPDigestAuth(args.username, args.password), args.protocol, verify=args.certificate)
+requests.packages.urllib3.disable_warnings()
+
+restLoader = RESTLoader(conn, args.restPort, args.database, args.permissions)
+
+if (source is not None):
+ if (os.path.isfile(source)):
+ response = restLoader.load_file(source, targetUri)
+ if (response.status_code == 201):
+ print("CREATED: " + targetUri)
+ elif (response.status_code == 204):
+ print("UPDATED: " + targetUri)
+ else:
+ print("Unexpected Response:"+response)
+ elif (os.path.isdir(source)):
+ restLoader.load_directory(source, targetUri)
+ else:
+ print("The specified source is either not found or not a file/directory")
+else:
+ print("You must specify the source file/directory")
+print("Complete")
\ No newline at end of file
diff --git a/examples/put-file.py b/examples/put-file.py
new file mode 100644
index 0000000..8a54615
--- /dev/null
+++ b/examples/put-file.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python3
+#
+# Copyright 2015 MarkLogic Corporation
+#
+# This script takes a JSON object that enumerates a set of artifacts and
+# applies those changes to the server, creating artifacts if necessary.
+#
+# See put-json-file.py
+#
+# For example:
+#
+# python3 put-json-file
+#
+# TODO
+#
+# * Upload a file using a PUT CURL command
+
+__author__ = 'pmb'
+
+from requests.auth import HTTPDigestAuth
+from marklogic.connection import Connection
+
+conn = Connection("192.168.200.162", HTTPDigestAuth("admin","admin"))
+
+uri = "http://192.168.200.162:8004/LATEST/config/properties"
+data = open("./data/props.json", 'rb').read()
+response = conn.putFile(uri=uri, data=data)
+print(response)
+
+uri = "http://192.168.200.162:8004/LATEST/config/transforms/simpleExtension"
+data = open("./data/simpleExtension.sjs", 'rb').read()
+response = conn.putFile(uri=uri, data=data, content_type="application/vnd.marklogic-javascript")
+print(response)
diff --git a/examples/restloader.py b/examples/restloader.py
new file mode 100644
index 0000000..582db86
--- /dev/null
+++ b/examples/restloader.py
@@ -0,0 +1,53 @@
+import logging
+import os
+from os import listdir
+from os.path import isfile, join
+from test.test_threadedtempfile import FILES_PER_THREAD
+
+class RESTLoader():
+ """
+ This class will upload files using the REST API.
+ """
+ def __init__(self, conn, restPort, database, permissions):
+ self.logger = logging.getLogger("marklogic.examples")
+ self.conn = conn
+ self.restPort = restPort
+ self.database = database
+ self.permissions = permissions
+ pass
+
+ def build_uri(self, targetUri):
+ baseUri = self.conn.protocol + "://"+self.conn.host+":" + str(self.restPort) + "/LATEST/documents"
+ uri = baseUri + "?uri=" + targetUri
+ if (self.database is not None):
+ uri += "&database=" + self.database
+ if (self.permissions is not None):
+ for perm in self.permissions.split(","):
+ uri += "&perm:" + perm
+ return uri
+
+ def load_file(self, sourceFile, targetUri):
+ self.logger.info("Loading {0} to {1}".format(sourceFile, targetUri))
+ uri = self.build_uri(targetUri)
+ print(uri)
+ data = open(sourceFile, 'rb').read()
+ response = self.conn.putFile(uri=uri, data=data, content_type="test/text")
+ if (response.status_code == 201):
+ print("CREATED: " + targetUri)
+ elif (response.status_code == 204):
+ print("UPDATED: " + targetUri)
+ else:
+ print("Unexpected Response:"+str(response.status_code))
+ return response
+
+ def load_directory(self, sourceDirectory, targetUri):
+ self.logger.info("Loading {0} to {1}".format(sourceDirectory, targetUri))
+ files = [f for f in listdir(sourceDirectory) if isfile(join(sourceDirectory, f))]
+ for file in files:
+ print(file)
+ response = self.load_file(sourceDirectory+os.path.sep+file, targetUri+"/"+file)
+ directories = [d for d in listdir(sourceDirectory) if os.path.isdir(sourceDirectory+os.path.sep+d)]
+ for directory in directories:
+ print(directory)
+ response = self.load_directory(sourceDirectory+os.path.sep+directory, targetUri+"/"+directory)
+
\ No newline at end of file
diff --git a/marklogic/connection.py b/marklogic/connection.py
index 9ca6ce0..ef56f6f 100644
--- a/marklogic/connection.py
+++ b/marklogic/connection.py
@@ -38,7 +38,7 @@ class Connection:
"""
def __init__(self, host, auth,
protocol="http", port=8000, management_port=8002,
- root="manage", version="v2", client_version="v1"):
+ root="manage", version="v2", client_version="v1", verify=False):
self.host = host
self.auth = auth
self.protocol = protocol
@@ -47,6 +47,7 @@ def __init__(self, host, auth,
self.root = root
self.version = version
self.client_version = client_version
+ self.verify = verify
self.logger = logging.getLogger("marklogic.connection")
self.payload_logger = logging.getLogger("marklogic.connection.payloads")
@@ -98,7 +99,7 @@ def client_uri(self, path, protocol=None, host=None, port=None, version=None):
def head(self, uri, accept="application/json"):
self.logger.debug("HEAD {0}...".format(uri))
- self.response = requests.head(uri, auth=self.auth)
+ self.response = requests.head(uri, auth=self.auth, verify=self.verify)
return self._response()
def get(self, uri, accept="application/json", headers=None):
@@ -111,7 +112,7 @@ def get(self, uri, accept="application/json", headers=None):
self.payload_logger.debug("Headers:")
self.payload_logger.debug(json.dumps(headers, indent=2))
- self.response = requests.get(uri, auth=self.auth, headers=headers)
+ self.response = requests.get(uri, auth=self.auth, headers=headers, verify=self.verify)
return self._response()
def post(self, uri, payload=None, etag=None,
@@ -133,14 +134,14 @@ def post(self, uri, payload=None, etag=None,
self.payload_logger.debug(payload)
if payload is None:
- self.response = requests.post(uri, auth=self.auth, headers=headers)
+ self.response = requests.post(uri, auth=self.auth, headers=headers, verify=self.verify)
else:
if content_type == "application/json":
self.response = requests.post(uri, json=payload,
- auth=self.auth, headers=headers)
+ auth=self.auth, headers=headers, verify=self.verify)
else:
self.response = requests.post(uri, data=payload,
- auth=self.auth, headers=headers)
+ auth=self.auth, headers=headers, verify=self.verify)
return self._response()
@@ -163,14 +164,30 @@ def put(self, uri, payload=None, etag=None,
self.payload_logger.debug(payload)
if payload is None:
- self.response = requests.put(uri, auth=self.auth, headers=headers)
+ self.response = requests.put(uri, auth=self.auth, headers=headers, verify=self.verify)
else:
if content_type == "application/json":
self.response = requests.put(uri, json=payload,
- auth=self.auth, headers=headers)
+ auth=self.auth, headers=headers, verify=self.verify)
else:
self.response = requests.put(uri, data=payload,
- auth=self.auth, headers=headers)
+ auth=self.auth, headers=headers, verify=self.verify)
+
+ return self._response()
+
+ def putFile(self, uri, data, etag=None,
+ content_type="application/json", accept="application/json"):
+
+ headers = {'content-type': content_type,
+ 'accept': accept}
+ if etag is not None:
+ headers['if-match'] = etag
+
+ self.logger.debug("PUT {0}...".format(uri))
+ self.payload_logger.debug("Headers:")
+ self.payload_logger.debug(json.dumps(headers, indent=2))
+
+ self.response = requests.put(uri, data=data, auth=self.auth, headers=headers, verify=self.verify)
return self._response()
@@ -193,10 +210,10 @@ def delete(self, uri, payload=None, etag=None,
self.payload_logger.debug(payload)
if payload is None:
- self.response = requests.delete(uri, auth=self.auth, headers=headers)
+ self.response = requests.delete(uri, auth=self.auth, headers=headers, verify=self.verify)
else:
self.response = requests.delete(uri, json=payload,
- auth=self.auth, headers=headers)
+ auth=self.auth, headers=headers, verify=self.verify)
return self._response()
@@ -239,7 +256,7 @@ def wait_for_restart(self, last_startup, timestamp_uri="/admin/v1/timestamp"):
try:
self.logger.debug("Waiting for restart of {0}".format(self.host))
response = requests.get(uri, auth=self.auth,
- headers={'accept': 'application/json'})
+ headers={'accept': 'application/json'}, verify=self.verify)
done = response.status_code == 200 and response.text != last_startup
except TypeError:
self.logger.debug("{0}: {1}".format(response.status_code,
diff --git a/test/data/simpleExtension.sjs b/test/data/simpleExtension.sjs
new file mode 100644
index 0000000..6518f6b
--- /dev/null
+++ b/test/data/simpleExtension.sjs
@@ -0,0 +1,13 @@
+function metadataFilter(context, params, content) {
+ var mutableDoc = content.toObject();
+ xdmp.log("context");
+ xdmp.log(context);
+ xdmp.log("params");
+ xdmp.log(params);
+ xdmp.log("content");
+ xdmp.log(content);
+ content = xdmp.unquote('hello', null, ["repair-none", "default-language=en"]);
+ return content;
+};
+
+exports.transform = metadataFilter;
\ No newline at end of file
diff --git a/test/ssl/resources.py b/test/ssl/resources.py
new file mode 100644
index 0000000..073d0c1
--- /dev/null
+++ b/test/ssl/resources.py
@@ -0,0 +1,5 @@
+class TestConnection(object):
+ hostname = "192.168.200.162"
+ admin = "admin"
+ password = "admin"
+ sslport = 8003
\ No newline at end of file
diff --git a/test/ssl/test_ssl_connection.py b/test/ssl/test_ssl_connection.py
new file mode 100644
index 0000000..0251bc4
--- /dev/null
+++ b/test/ssl/test_ssl_connection.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals, print_function, absolute_import
+
+#
+# Copyright 2016 MarkLogic Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0#
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# File History
+# ------------
+#
+# Philip Barber 02/14/2016 Initial development
+#
+
+import unittest
+from requests.auth import HTTPDigestAuth
+from marklogic.models import Database, Server, Forest
+from marklogic.connection import Connection
+from test.ssl.resources import TestConnection as tc
+
+class TestSslConnection(unittest.TestCase):
+ """
+ Basic creation test function.
+ """
+ def test_check_ssl_manage_server(self):
+ conn = Connection(tc.hostname,
+ HTTPDigestAuth(tc.admin, tc.password),
+ protocol="https",
+ verify = "",
+ management_port=tc.sslport)
+ server = Server.lookup(conn, "Default|Manage")
+ self.assertIsNotNone(server)
+ self.assertEqual('Manage', server.server_name())
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/test/test_put_file.py b/test/test_put_file.py
new file mode 100644
index 0000000..8a7913a
--- /dev/null
+++ b/test/test_put_file.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals, print_function, absolute_import
+
+#
+# Copyright 2016 MarkLogic Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0#
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# File History
+# ------------
+#
+# Philip Barber 02/15/2016 Initial development
+#
+
+import unittest
+from requests.auth import HTTPDigestAuth
+from marklogic.models import Database, Server, Forest
+from marklogic.connection import Connection
+from test.ssl.resources import TestConnection as tc
+
+class TestPutFile(unittest.TestCase):
+ """
+ Basic put-file test function.
+ """
+ def test_put_file(self):
+ conn = Connection(tc.hostname, HTTPDigestAuth(tc.admin, tc.password))
+
+ response = conn.get("http://192.168.200.162:8004/LATEST/config/transforms/simpleExtension")
+ self.assertIn("\"status\":\"Not Found\"", response.text)
+
+ data = open("./test/data/simpleExtension.sjs", 'rb').read()
+ response = conn.putFile(uri="http://192.168.200.162:8004/LATEST/config/transforms/simpleExtension", data=data, content_type="application/vnd.marklogic-javascript")
+ self.assertEqual(204, response.status_code, "PUTting the file should result in a 204 response code")
+
+ response = conn.get("http://192.168.200.162:8004/LATEST/config/transforms/simpleExtension")
+ self.assertIn("function metadataFilter", response.text)
+
+ response = conn.delete("http://192.168.200.162:8004/LATEST/config/transforms/simpleExtension")
+ self.assertEqual(204, response.status_code, "DELETing the file should result in a 204 response code")
+
+if __name__ == "__main__":
+ unittest.main()