diff --git a/.gitignore b/.gitignore
index b522b1da9176e59756bffe89cd4eafe0d751a23c..55fb3f0d1bc6c101704557da8f35d6e784b5ea89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,5 @@ build/
 src/caosdb/version.py
 
 # documentation
-_apidoc
\ No newline at end of file
+_apidoc
+*~
diff --git a/src/doc/gallery/curator_permissions.py b/src/doc/gallery/curator_permissions.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c2ccad99175edffa87ff07f30d9e844c83e0891
--- /dev/null
+++ b/src/doc/gallery/curator_permissions.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# encoding: utf-8
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2022 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2022 Florian Spreckelsen <f.spreckelsen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+import os
+import sys
+
+import caosdb as db
+from caosadvancedtools.models.parser import parse_model_from_json_schema
+from caosdb import administration as admin
+
+CURATOR = "curator"
+
+
+def main():
+    """Set curator role permissions: Is allowed to edit all Records; is allowed
+    to create new RTs and Properties and change them, but is not allowed to
+    change anything defined in the core data model, i.e., in the schemas.
+
+    """
+    dataspace_definitions = parse_model_from_json_schema(
+        "zmt-metadata-schema/schemas/dataspace.schema.json")
+    dataset_definitions = parse_model_from_json_schema(
+        "zmt-metadata-schema/schemas/dataset.schema.json")
+
+    # Set general permissions. The curator users should be allowed to perform
+    # any transaction.
+    perms = admin._get_permissions(CURATOR)
+    general_grant_perms = [
+        "TRANSACTION:*"
+    ]
+
+    for p in general_grant_perms:
+
+        g = admin.PermissionRule(action="Grant", permission=p, priority=True)
+        d = admin.PermissionRule(action="Deny", permission=p, priority=True)
+
+        if g in perms:
+            perms.remove(g)
+        if d in perms:
+            perms.remove(d)
+        perms.add(g)
+
+    admin._set_permissions(CURATOR, permission_rules=perms)
+
+    # Deny all permissions that could change the data model ...
+    core_model_deny_permissions = [
+        "DELETE",
+        "UPDATE:*",
+        "EDIT:ACL"
+    ]
+    # ... but allow read-access and of course using the entities as parents,
+    # properties, ...
+    core_model_grant_permissions = [
+        "RETRIEVE:*",
+        "USE:*",
+    ]
+
+    updates = db.Container()
+    for model in [dataspace_definitions, dataset_definitions]:
+
+        for ent in model.values():
+            if ent.name in [u.name for u in updates]:
+                continue
+            ent.retrieve(flags={"ACL": None})
+            for d in core_model_deny_permissions:
+                ent.deny(role=CURATOR, priority=True, permission=d)
+            ent.update_acl()
+            ent.retrieve(flags={"ACL": None})
+            for g in core_model_grant_permissions:
+                ent.grant(role=CURATOR, priority=True, permission=g)
+            updates.append(ent)
+            ent.update_acl()
+
+
+if __name__ == "__main__":
+
+    sys.exit(main())